jueves, 16 de julio de 2015
I've moved
Eso, voy a seguirla un tiempo en un Ghost hosteado como Web App Service sobre Microsoft Azure... vamos a ver como resulta =D
viernes, 3 de abril de 2015
Could not load file or assembly Microsoft.WindowsAzure.Packaging
Luego de instalar la última actualización del Azure SDK 2.5.1 para Visual Studio 2013 ya no pude volver a publicar mi Cloud Service. El error reportado era:
Buscando en diferentes sitios pude dar con una comentario de Wayne Kuo en StackOverflow explicando que el problema era originado por un problema en el instalador de la nueva versión del Azure SDK, y que pudieron comprobar que quitando y volviendo a instalar las Microsoft Azure Authoring Tools 2.5.1 el problema se solucionaba.
Las Microsoft Azure Authoring Tools 2.5.1 pueden bajarse desde:
En mi caso bastó con ejecutar la opción Repair del instalador de las Authoring Tools, no fue necesario hacerlo en dos pasos (desinstalar y volver a instalarlas).
Una vez finalizada la reparación de las Microsoft Azure Authoring Tools 2.5.1 pude volver a publicar mi Cloud Service normalmente.
Could not load file or assembly 'Microsoft.WindowsAzure.Packaging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
| Error al intentar publicar mi Cloud Service |
Buscando en diferentes sitios pude dar con una comentario de Wayne Kuo en StackOverflow explicando que el problema era originado por un problema en el instalador de la nueva versión del Azure SDK, y que pudieron comprobar que quitando y volviendo a instalar las Microsoft Azure Authoring Tools 2.5.1 el problema se solucionaba.
| Azure Authoring Tools Installer |
Las Microsoft Azure Authoring Tools 2.5.1 pueden bajarse desde:
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x64.msi
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x86.msi
En mi caso bastó con ejecutar la opción Repair del instalador de las Authoring Tools, no fue necesario hacerlo en dos pasos (desinstalar y volver a instalarlas).
| Opción de reparación |
Una vez finalizada la reparación de las Microsoft Azure Authoring Tools 2.5.1 pude volver a publicar mi Cloud Service normalmente.
martes, 17 de marzo de 2015
Como compilar Docker Client en Windows
Desde noviembre de 2014, cuando Ahmet Alp Balkan anunció la disponibilidad de compilar Docker Client sobre Windows, han cambiado algunas cosas.
Acá dejo los comandos que utilicé para compilar el cliente Docker sobre un Windows 8.1 usando Git for Windows, y obviamente Go, el lenguaje en el cual está programado Docker.
Para poder compilar Docker es necesario tener instalado previamente Git for Windows y Go.
Por default el instalador para Windows deja Go en la carpeta C:\Go, y en el ejemplo a continuación se muestra así. Si cambias la carpeta de instalación de Go entonces modifica también la carpeta del primer comando (export GOPATH="c:\go").
Si no queres hacer todo esto podes bajarte el Docker 1.18 compilado en Windows desde esta ubicación: https://seketman.blob.core.windows.net/docker/docker_1.18.exe... mucho mas rápido.
Acá dejo los comandos que utilicé para compilar el cliente Docker sobre un Windows 8.1 usando Git for Windows, y obviamente Go, el lenguaje en el cual está programado Docker.
Requisitos
Para poder compilar Docker es necesario tener instalado previamente Git for Windows y Go.
Por default el instalador para Windows deja Go en la carpeta C:\Go, y en el ejemplo a continuación se muestra así. Si cambias la carpeta de instalación de Go entonces modifica también la carpeta del primer comando (export GOPATH="c:\go").
Procedimiento
- Abrir una consola de Git Bash desde el disco donde está instalado el Go. Para esto dale clic derecho sobre el icono del disco en cualquier explorador de archivos, y selecciona la opción Git Bash que agregó la instalación del Git for Windows.
- En la consola de Git Bash ejecuta los siguientes comandos:
# Get the Docker source export GOPATH="c:\go" cd $GOPATH go get github.com/docker/docker # Compile go-autogen export GOPATH="$GOPATH;$GOPATH\src\github.com\docker\docker\vendor" cd src/github.com/docker/docker hack/make/.go-autogen # Finally compile Docker Client export DOCKER_CLIENTONLY=1 cd docker go build -v
..y listo, en la carpeta $GOPATH\src\github.com\docker\docker\docker te quedó el archivo docker.exe que estabas buscando.
![]() |
| Consola de Git Bash |
Si no queres hacer todo esto podes bajarte el Docker 1.18 compilado en Windows desde esta ubicación: https://seketman.blob.core.windows.net/docker/docker_1.18.exe... mucho mas rápido.
sábado, 14 de marzo de 2015
Microsoft Azure Cloud Service - VIP swap feature
Esto es grandioso porque permite implementar un servicio en el entorno de Staging, probarlo, y cuando está todo ok hacer el swap que lo dejará en Production, pero hay que tener en cuenta que este 'intercambio de implementaciones', o 'promoción del servicio en ensayo al entorno de producción', tal como se nombra en varios documentos, en verdad es solamente un intercambio de punteros (la VIP y URL de cada uno de los entornos), las implementaciones en sí no se ven modificadas por este proceso en su configuración ni estado.
- Cada uno de los entornos de un Cloud Service poseen tres atributos propios:
- Su denominación: Staging o Production
- Una virtual IP pública, o VIP.
- ..y una URL: <nombredns>.cloudapp.net (Production), o <guid>.cloudapp.net (Staging)
- Tanto la VIP como la URL de Staging se mantienen durante todo el ciclo de vida de la implementación mientras no sea borrada (no cambia entre deploys).
- Cuando una implementación es borrada de un entorno recién entonces se liberan estos valores, y al hacer una nueva implementación sobre ese entorno siempre se asigna un nuevo valor de VIP. La URL de Staging <guid>.cloudapp.net solo cambia si este proceso de borrado y nueva implementación se lleva a cabo sobre el entorno de Staging.
- Antes de ejecutar el VIP swap debemos asegurarnos de que la configuración de la implementación en Staging sea la adecuada para pasarla a Production, ya que el proceso no altera ninguno de los valores en cuanto a cantidad de instancias de los roles, ni configuración de autoscaling.
- Las conexiones establecidas con cada implementación al momento de ejecutar el VIP swap se mantendrán así hasta su cierre por parte del cliente o servidor, no serán canceladas por el proceso de intercambio. Solo las nuevas conexiones son dirigidas a la nueva implementación que ocupa cada entorno.
- La opción de VIP swap aún no está disponible en el Preview Portal; para ejecutarlo tendremos que servirnos del Management Portal, o invocando la Microsoft Azure Management Service Rest API directamente, o a través del wrapper que conforman las Microsoft Azure Management Libraries, o MAML.
| Sección del Management Portal - Cloud Service Dashboard |
Bueno, sigo leyendo el Exam Ref 70-532 Developing Microsoft Azure Solutions a ver como continúa la historia de los Cloud Services.
sábado, 31 de enero de 2015
Tienda online en ASP.NET 5 sobre Docker
Intro
Entusiasmado con la posibilidad que brinda ASP.NET 5 de correr mis sitios web sobre distintas plataformas, me puse a averiguar y escribir un resumen de como levantar un sitio y correrlo sobre Docker dentro de una VM Ubuntu de Microsoft Azure... la sorpresa fue que no te lleva mas de 10 minutos, y funciona de maravillas.Requisitos
- Suscripción de Microsoft Azure.
- Una VM Ubuntu Trusty 14.04 como mínimo, con el puerto 80 habilitado.
- Estar registrado en Docker.com si queremos salvar allí la nueva imagen creada.
Contenido
- Preparar el contenido de la nueva imagen.
- Construir la imagen Docker con nuestra aplicación.
- Levantar un nuevo container con nuestra imagen.
- Salvar nuestra imagen en Docker Hub.
1. Preparar los componentes de la nueva imagen
La imagen Docker que vamos a crear para correr nuestra aplicación MVC MusicStore estará basada en la microsoft/aspnet publicado por Microsoft meses atrás que, si bien aún está en preview, sirve perfectamente para nuestro propósito.Actualizamos nuestro Ubuntu; instalamos Docker según se explica en docs.docker.com/installation/ubuntulinux; y también nos aseguramos de contar con Git:
sudo apt-get update sudo apt-get install docker.io sudo apt-get install git-core
Por último clonamos en la carpeta local storeapp el proyecto MVC MusicStore de GitHub, con el comando:
git clone http://github.com/aspnet/MusicStore storeapp
2. Construir la imagen Docker de nuestra aplicación
Nos movemos a la carpeta storeapp/src/MusicStore y ahí creamos el archivo Dockerfile que usaremos para configurar nuestra imagen. Podes crear el archivo con nano o el editor que prefieras:cd storeapp/src/MusicStore nano Dockerfile
Copia el siguiente contenido dentro del archivo Dockerfile (las lineas que comienzan con # son comentarios):
# Base image FROM microsoft/aspnet # Copy project folder into image and restore Nuget packages COPY . /app WORKDIR /app RUN ["kpm", "restore"] # Run de web site EXPOSE 5004 ENTRYPOINT ["k", "kestrel"]
..y creamos la imagen usando el comando:
sudo docker build -t storeapp .
Esto demora un poco, paciencia.
3. Levantar un nuevo container con nuestra imagen
Podemos ver las imágenes en nuestro sistema mediante el comando Docker images, luego levantamos nuestra imagen en un nuevo container con run, y por ultimo listamos los containers con el comando ps:sudo docker images sudo docker run -t -d -p 80:5004 --restart=on-failure:10 storeapp sudo docker ps -a
Y ya tenemos nuestra imagen corriendo en un container de Docker en nuestra VM, publicado en el puerto 80 de Ubuntu (no olvides configurar el endpoint en Azure).
4. Salvar nuestra imagen en Docker Hub
Ahora si queremos salvar la imagen en Docker Hub para utilizarla desde cualquier otra VM, o publicarla para la comunidad, podemos agregarle un tag y hacerle un push (previamente tenemos que registrarnos en Docker.com).Tanto el image id (934e56caf9b8), como el nombre de la cuenta registrada (seketman), deben cambiarse por los valores que corresponden:
sudo docker tag 934e56caf9b8 seketman/storeapp:demo sudo docker push seketman/storeapp:demo
| Nuestro sitio funcionando |
Pueden ver este sitio corriendo en soundstore.cloudapp.net
Mucha de la info mostrada se basa en el post Running ASP.NET 5 applications in Linux Containers with Docker de Ahmet Alp Balkan.
miércoles, 3 de diciembre de 2014
Universal PredicateBuilder... tunned for Azure AD Graph API queries
Las consultas a la Azure AD Graph API no admiten le sean provistos valores nulos o vacíos, y las opciones de filtro soportadas al día de hoy se limitan a and, or, eq, ge, le, Startswith, y Any.
La Microsoft Azure Active Directory Graph Client Library facilita notablemente el manejo de estas consultas desde las aplicaciones .NET, pero aún es algo incomodo la construcción dinámica de predicados, debido a lo cual recurrí para esta labor al PredicateBuilder generosamente compartido por Pete Montgomery allá por febrero del 2011.
Afortunadamente todo el entorno de Microsoft Azure está evolucionando rápidamente así que es de esperar estas limitaciones no perduren por mucho tiempo, pero comparto esta pequeña solución por si algún otro desarrollador se encuentra ante la misma situación.
Los ajustes introducidos a la versión de Pete fueron mínimos, y solo para asegurar la compatibilidad con los operadores lógicos and y or (Pete usó AndAlso, y OrElse, no soportados por la Graph API).
Consulta de usuarios
Basada en AzureADSamples/ConsoleApp-GraphAPI-DotNet
IPagedCollection<IUser> searchResults = null;
var predicate = GraphAPIPredicateBuilder.Create<IUser>(u => u.AccountEnabled == true);
if (!string.IsNullOrWhiteSpace(canonicalUser.Name))
predicate = predicate.And(u => u.UserPrincipalName.StartsWith(canonicalUser.Name));
if (!string.IsNullOrWhiteSpace(displayname))
predicate = predicate.And(u => u.DisplayName.StartsWith(displayname));
if (!string.IsNullOrWhiteSpace(description))
predicate = predicate.And(u => u.GivenName.StartsWith(givenname));
try
{
ActiveDirectoryClient activeDirectoryClient =
AzureADAuthenticationHelper.GetActiveDirectoryClientAsApplication();
IUserCollection userCollection = activeDirectoryClient.Users;
searchResults = userCollection.Where(predicate).ExecuteAsync().Result;
}
catch (Exception e)
{
Debug.WriteLine(string.Format("Error searching users - {0} {1}", e.Message,
e.InnerException != null ? e.InnerException.Message : ""));
}
GraphAPIPredicateBuilder
/// <summary>
/// Enables the efficient, dynamic composition of query predicates... tunned for Azure AD Graph API
///
/// Based on the work of Pete Montgomery at February 10, 2011
/// http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/
/// </summary>
public static class GraphAPIPredicateBuilder
{
/// <summary>
/// Creates a predicate that evaluates to true.
/// </summary>
public static Expression<Func<T, bool>> True<T>() { return param => true; }
/// <summary>
/// Creates a predicate that evaluates to false.
/// </summary>
public static Expression<Func<T, bool>> False<T>() { return param => false; }
/// <summary>
/// Creates a predicate expression from the specified lambda expression.
/// </summary>
public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
/// <summary>
/// Combines the first predicate with the second using the logical "and".
/// </summary>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
/// <summary>
/// Combines the first predicate with the second using the logical "andAlso".
/// </summary>
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
/// <summary>
/// Combines the first predicate with the second using the logical "or".
/// </summary>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
/// <summary>
/// Combines the first predicate with the second using the logical "orElse".
/// </summary>
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
/// <summary>
/// Negates the predicate.
/// </summary>
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
{
var negated = Expression.Not(expression.Body);
return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
}
/// <summary>
/// Combines the first expression with the second using the specified merge function.
/// </summary>
static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// zip parameters (map from parameters of second to parameters of first)
var map = first.Parameters
.Select((f, i) => new { f, s = second.Parameters[i] })
.ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with the parameters in the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// create a merged lambda expression with parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
class ParameterRebinder : ExpressionVisitor
{
readonly Dictionary<ParameterExpression, ParameterExpression> map;
ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
}
That's all folks!
jueves, 6 de noviembre de 2014
TFS - MSBuild scripts en el Custom Assembly Path?
Desde el TFS 2010 se introdujo un nuevo parámetro Custom Assembly Path (o Ruta de acceso de control de versiones a ensamblados personalizados en español... uf! que quedó largo), al Build Controller para poder especificar allí la ubicación de aquellas dll´s que queremos tener disponibles en todos nuestros Build Definitions, sin tener que estar bajándolas del TFS para cada compilación.
Lo interesante es que cualquier archivo que se guarde en ese path del TFS, lo mismo que las carpetas y sus contenidos, es bajado automáticamente a un directorio del Build Server inmediatamente luego de cada Check In. Así podemos dejar ahí scripts de MSBuild (o lo que se nos ocurra), para ejecutar rutinas en diferentes Build Process Templates usando la activity InvokeProcess.
La carpeta en la que queda el contenido del Custom Assembly Path es:
Donde username corresponde al usuario bajo el cual corre el Team Foundation Build Service. y el ultimo numero al Build Agent.
Para acceder desde un Build Process Template a esta carpeta se debe agregar un activity del tipo GetBuildEnvironment al workflow, y luego asignar su atributo Result a una variable con un scope apropiado.
Una vez creada la variable se puede acceder a todos los atributos que expone la clase BuildEnvironment, incluido el CustomAssemblyPath. en cualquier expresión VB que esté dentro del scope especificado.
Todos los links de este post quedaron apuntando a la documentación del TFS 2010 porque ese fue la versión de servidor usada en el ejemplo, pero entiendo aplica totalmente a la siguientes versiones.
Custom Assembly Path en el Build Controller
Lo interesante es que cualquier archivo que se guarde en ese path del TFS, lo mismo que las carpetas y sus contenidos, es bajado automáticamente a un directorio del Build Server inmediatamente luego de cada Check In. Así podemos dejar ahí scripts de MSBuild (o lo que se nos ocurra), para ejecutar rutinas en diferentes Build Process Templates usando la activity InvokeProcess.
La carpeta en la que queda el contenido del Custom Assembly Path es:
C:\Users\%username%\AppData\Local\Temp\BuildAgent\1\
Donde username corresponde al usuario bajo el cual corre el Team Foundation Build Service. y el ultimo numero al Build Agent.
Para acceder desde un Build Process Template a esta carpeta se debe agregar un activity del tipo GetBuildEnvironment al workflow, y luego asignar su atributo Result a una variable con un scope apropiado.
GetBuildEnvironment Activity como parte del workflow
Una vez creada la variable se puede acceder a todos los atributos que expone la clase BuildEnvironment, incluido el CustomAssemblyPath. en cualquier expresión VB que esté dentro del scope especificado.
Usando la variable buildEnvironment previamente creada
Todos los links de este post quedaron apuntando a la documentación del TFS 2010 porque ese fue la versión de servidor usada en el ejemplo, pero entiendo aplica totalmente a la siguientes versiones.
lunes, 27 de octubre de 2014
Encriptando una sección del web.config para Azure
Si bien el archivo web.config no es expuesto por el IIS, la presencia de información sensible en la sección appSettings de un proyecto Cloud Service de Microsoft Azure me llevó a buscar la posibilidad de encriptarlo local, y poder usarlo sin problemas en la nube.
Y lo que encontré fue esto:
Como mi proyecto ya estaba configurado para utilizar SSL lo que hice fue reutilizar el mismo certificado autofirmado.
Si no tenes un certificado hay que agregar uno al proyecto siguiendo los pasos descritos en Configuring SSL for an application in Azure (solo los pasos Get an SSL certStep 1: Get an SSL certificate, y la parte de upload certificate del paso Upload to AzureStep 3: Upload the deployment package and certificate).
En el caso del Cloud Service solo basta con agregar este paquete al WebRole.
Agregar la sección configProtectedData dentro de configuration del web.config, reemplazando el thumbprintValue por el del certificado usado.
En este caso solo buscaba encriptar la sección appSettings, pero se puede hacer lo mismo con cualquier otra sección, o varias.
Y si, para armar el tutorial usé el proyecto DevDay 2014 que tan gentilmente cedió la gente de Microsoft para el concurso de AR-UY... ;-)
Antes de poder usar la PKCS12ProtectedConfigurationProvider.dll en Azure vamos a necesitar registrarla en la GAC, y dado que los WebRoles de Azure no se están incluyendo las Microsoft SDKs tendremos que llevarnos una copia del gacutil.exe y config hacia la nube.
En mi caso levanté el Cloud Service sobre Windows Server 2012, así que me copie ambos archivos gacutil desde la carpeta C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools a una nueva carpeta Startup dentro de mi proyecto WebRole1.
Al desplegar el WebRole en Azure necesitamos que se ejecute gacutil como uno de los primeros pasos. Para eso agregamos un archivo RegisterGAC.cmd (salvar este archivo de con codificación ANSI), a la carpeta Startup recientemente creada, conteniendo el comando:
...y observar como la aplicación fluye gloriosa!
Fuentes:
Y lo que encontré fue esto:
Paso 1 - Necesito un certificado
Como mi proyecto ya estaba configurado para utilizar SSL lo que hice fue reutilizar el mismo certificado autofirmado.
Si no tenes un certificado hay que agregar uno al proyecto siguiendo los pasos descritos en Configuring SSL for an application in Azure (solo los pasos Get an SSL certStep 1: Get an SSL certificate, y la parte de upload certificate del paso Upload to AzureStep 3: Upload the deployment package and certificate).
Paso 2 - Agregar PKCS12ProtectedConfigurationProvider al WebRole desde Nuget
En el caso del Cloud Service solo basta con agregar este paquete al WebRole.
Paso 3 - Configurar el proveedor de ProtectedData en el web.config
Agregar la sección configProtectedData dentro de configuration del web.config, reemplazando el thumbprintValue por el del certificado usado.
<configuration>
<configProtectedData>
<providers>
<add name="ProtectedConfigurationProvider" thumbprint="thumbprintValue" type="Pkcs12ProtectedConfigurationProvider.Pkcs12ProtectedConfigurationProvider, PKCS12ProtectedConfigurationProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34da007ac91f901d"/>
</providers>
</configProtectedData>
...
</configuration>
Paso 4 - Encriptar la sección del web.config que se quiere proteger
En este caso solo buscaba encriptar la sección appSettings, pero se puede hacer lo mismo con cualquier otra sección, o varias.
aspnet_regiis -pef appSettings "C:\source\Azure\DevDay\WebRole1" -prov ProtectedConfigurationProviderComo acertadamente anticipa Alp Arslan Eren en su blog, si ejecutando el aspnet_regiis te encontrás con un error could not load the PKCS12ProtectedConfigurationProvider assembly como me pasó a mí, siguiendo estas indicaciones se soluciona.
Y si, para armar el tutorial usé el proyecto DevDay 2014 que tan gentilmente cedió la gente de Microsoft para el concurso de AR-UY... ;-)
Paso 5 - Insertar el gacutil como parte de nuestro proyecto
Antes de poder usar la PKCS12ProtectedConfigurationProvider.dll en Azure vamos a necesitar registrarla en la GAC, y dado que los WebRoles de Azure no se están incluyendo las Microsoft SDKs tendremos que llevarnos una copia del gacutil.exe y config hacia la nube.
En mi caso levanté el Cloud Service sobre Windows Server 2012, así que me copie ambos archivos gacutil desde la carpeta C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools a una nueva carpeta Startup dentro de mi proyecto WebRole1.
Paso 6 - Nueva Startup Task para ejecutar gacutil
Al desplegar el WebRole en Azure necesitamos que se ejecute gacutil como uno de los primeros pasos. Para eso agregamos un archivo RegisterGAC.cmd (salvar este archivo de con codificación ANSI), a la carpeta Startup recientemente creada, conteniendo el comando:
Startup\gacutil.exe /nologo /i PKCS12ProtectedConfigurationProvider.dll..y un nuevo Startup Task dentro del WebRole al archivo ServiceDefinition.csdef de la solución:
<WebRole name="WebRole1" vmsize="Small">
<Startup>
<Task commandLine="Startup\RegisterGAC.cmd" executionContext="elevated" taskType="simple"/>
</Startup>
...
</WebRole>
Los tres archivos agregados en la carpeta Startup deben quedar marcados como Copiar en el directorio de salida: Copiar siempre.
Paso 7 - Desplegar la solucion en Azure
...y observar como la aplicación fluye gloriosa!
Fuentes:
jueves, 16 de octubre de 2014
IIS Express, HTTPS... y una URL externa
Usar el IIS Express con un sitio web creado en VS 2013 va como piña mientras te mantengas en localhost, el problema se me presentó cuando quise accederlo desde otra maquina de la red.
- Para empezar tuve que abrir el VS 2013 como Administrador, porque sino no me permitía cambiar la URL del proyecto.
A continuación cambie la URL entrando en Propiedades del proyecto, luego en Web, y ahí en el grupo de parámetros Servidores, sustituyendo localhost por el nombre publico de la maquina donde se aloja el sitio.
- Después tuve que crear un nuevo certificado para esa dirección usando Makecert:
Makecert -r -pe -n CN="nombrePublico" -b 10/15/2014 -e 10/15/2017 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
El secreto es que el certificado quede en localmachine porque ahí lo buscará el siguiente comando.
-
Ahora falta asignar el certificado a la ip y puerto mediante netsh, ejecutando:
netsh http add sslcert ipport=0.0.0.0:44302 certhash=certThumbprint appid={anyValidGuid}
Podes averiguar el thumbprint, o huella digital, del certificado generado usando MMC, en el menú Archivos seleccionar la opción Agregar o quitar complementos, Certificados, y ahí Cuenta de equipo.
-
El último paso es que nuestro equipo cliente confíe en el certificado que generamos. En mi caso usando Chrome lo que hice fue intentar acceder al sitio web alojado en el IIS Express, cuando me apareció el mensaje de el certificado no es de confianza, baje el certificado lo guarde en un archivo en mi maquina, y luego desde la configuración del Chrome lo importe a la carpeta de Entidades de certificación raíz de confianza (en este sitio se explica mucho mas detallado).
miércoles, 24 de septiembre de 2014
ACS90014 error using Active Directory Authentication Library V2
Intentando autenticar una aplicación de consola usando ADAL v2, al invocar al método AcquireToken pasando el clientId (sin clientSecret), y PromptBehavior.Always, luego del ingreso de las credenciales me devolvía el error:
Parte del código utilizado:
Basado en la publicación de Vittorio Bertocci: Active Directory Authentication Library (ADAL) v2 for .NET/Windows Store/Windows Phone–General Availability!
ACS90014: The request body must contain the following parameter: 'client_secret or client_assertion'
Luego de buscar un rato pude encontrar que la causa era que el Application que habia creado en el Azure Active Directory era del tipo WEB APPLICATION AND/OR WEB AP cuando lo correcto, para el caso que me interesaba, era crearla del tipo NATIVE CLIENT APPLICATION.
Parte del código utilizado:
string clientId = ConfigurationManager.AppSettings["ClientId"]; string clientSecret = ConfigurationManager.AppSettings["ClientSecret"]; string resource = ConfigurationManager.AppSettings["ServiceRealm"]; string authenticationUri = ConfigurationManager.AppSettings["AuthBaseUri"] + ConfigurationManager.AppSettings["Tenant"]; AuthenticationContext authenticationContext = new AuthenticationContext(authenticationUri, false); string token; var redirectUri = new Uri(ConfigurationManager.AppSettings["RedirectUri"]); try { AuthenticationResult authenticationResult = authenticationContext.AcquireToken(resource, clientId, redirectUri, PromptBehavior.Always); token = authenticationResult.AccessToken; Console.WriteLine("\n Welcome " + authenticationResult.UserInfo.GivenName + " " + authenticationResult.UserInfo.FamilyName); } catch (AuthenticationException ex) { string message = ex.Message; if (ex.InnerException != null) message += "InnerException : " + ex.InnerException.Message; Console.WriteLine(message); Console.ReadKey(); return; }
Basado en la publicación de Vittorio Bertocci: Active Directory Authentication Library (ADAL) v2 for .NET/Windows Store/Windows Phone–General Availability!
lunes, 11 de agosto de 2014
Invalid class [0x80041010]
Después de desinstalar el SQL Server 2005 en un Windows 7 32 bits ya no pude entrar al SQL Server Configuration Manager del SQL Server 2008... aparecía el error: "Cannot connect to WMI provider. You do not have permission or the server is unreachable".
Según explica la gente de Microsoft "This problem occurs because the WMI provider is removed when you uninstall an instance of SQL Server." (http://support.microsoft.com/kb/956013), y tal parece que las diferentes versiones de SQL Server comparten el mismo archivo de configuración WMI.
La solución pasa por volver a compilar las clases necesarias en el repositorio WMI (archivo sqlmgmproviderxpsp2up.mof), con el comando mpfcomp, para la versión del SQL Server que se desea reparar.
En mi caso (Windows 7 32 bits + SQL Server 2008), el comando fue:
..y santo remedio.
Según explica la gente de Microsoft "This problem occurs because the WMI provider is removed when you uninstall an instance of SQL Server." (http://support.microsoft.com/kb/956013), y tal parece que las diferentes versiones de SQL Server comparten el mismo archivo de configuración WMI.
La solución pasa por volver a compilar las clases necesarias en el repositorio WMI (archivo sqlmgmproviderxpsp2up.mof), con el comando mpfcomp, para la versión del SQL Server que se desea reparar.
En mi caso (Windows 7 32 bits + SQL Server 2008), el comando fue:
mofcomp "C:\Program Files\Microsoft SQL Server\100\Shared\sqlmgmproviderxpsp2up.mof"
..y santo remedio.
viernes, 16 de noviembre de 2012
JDGui_noComments PowerShell style
Acá la versión PowerShell V2, mucho mas cómodo para mover en entornos Windows 7... y mas bonito para mostrar gracias a la Copy-ColoredAsHtml option del PowerShellPack ;-)
$fcount = 0 $search = '^\/\* [ \d]{1,4} \*\/ ' Get-ChildItem \source *.java -recurse | Foreach-Object { $c = ($_ | Get-Content) if ($c -match $search) { $c = $c -replace $search, '' [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n")) Write-Host $_.FullName "... updated" $fcount++ } } Write-Host $fcount "file(s) updated"
Remove JD-Gui line comments
Ok, ok.. no es la gloria.. pero es mi primer script en Ruby y merecía un lugar de privilegio... and, here is JDGui_noComments!, para quitar los odiosos comentarios que JD-Gui agrega al principio de cada linea de los archivos java decompilados... algo es algo como diría mi vieja ;-)
Mañana la versión PowerShell que terminé usando... mas sencillo para entornos Windows Seven porque ya viene como parte del SO.
# JDGui_noComments.rb def treeReplace(dir, filename, search, replace) fcount = 0 Dir["#{dir}/*"].each do |fd| if File.directory?(fd) fcount += treeReplace(fd, filename, search, replace) else if fd =~ filename text = File.read(fd) if text =~ search File.open(fd, 'w') {|f| f << text.gsub!(search, replace)} puts "#{fd}... updated" fcount += 1 end end end end return fcount end # Main program # if __FILE__ == $0 if ARGV.size < 1 puts "Usage: #{$0} <dir>" exit end dir = ARGV[0].dup dir.gsub!(/\\/, "/") # MS-DOS/Microsoft Windows style path compatible puts treeReplace(dir, /\.java$/, /^\/\* [ \d]{1,4} \*\/ ?/, "").to_s() + " file(s) updated" end
Mañana la versión PowerShell que terminé usando... mas sencillo para entornos Windows Seven porque ya viene como parte del SO.
Suscribirse a:
Entradas (Atom)





