[ASPNET] Obtener tipo MIME de un archivo, opciones y el nuevo System.Web.MimeMapping en ASP.NET 4.5

Si alguna vez te toco trabajar en ambiente web con requerimientos de publicación de archivos, subir archivos desde el cliente o descargarlos, guardar el contenido…  cuando enviamos un email con datos adjuntos (aunque esto ultimo se realiza automáticamente) seguramente has trabajado con tipos MIME (Multipurpose Internet Mail Extensions) Y seguramente tienes en tu app o componente un mecanismo para mapear extension a tipo MIME.

Para los que comienzan o necesitan utilizar… Una pregunta relacionada con MIME es ¿Como recuperamos el tipo de un archivo a partir de la extensión o viceversa?

Las opciones:

  1. Obtener tipo MIME de la Registry (incluso la inversa, la extensión asociada)
  2. Obtener tipo MIME “manualmente” ayudándonos con una estructura de un Dicccionario (o switch kilométrico)
  3. Obtener tipo MIME mediante el método  GetMimeMapping de la clase System.Web.MimeMapping [Nuevo desde ASP.NET 4.5]
    • 3.1 App Pool en Modo Clásico: Obtiene los valores de un diccionario (idem opción 2)
    • 3.2 App Pool en Modo Integrado: Obtiene los valores de la lista de tipos Mime configurada en el IIS (y/o app web)

 

Vemos los pro y contra que tiene cada uno así podemos conocer cuando utilizarlos y cuando “no”.

 

OPCION 1: Obtener tipo MIME de la Registry de Windows

Si bien esta opción no es recomendada.. Seguramente habrás encontrado algún código que realiza esto. La idea aquí es obtener el tipo MIME o la extensión a partir de la búsqueda dentro del árbol en la Registry

HKEY_CLASSES_ROOTMIMEDatabaseContent Type

SNAGHTML14987f48

 

A tener en cuenta: El inconveniente de esta opción es que debe estar cargado en el la registry de nuestro sistema operativo donde ese alojara la aplicación web todos los tipos que necesitemos (y allí solo se registran los que las app registran/instalan o viene predeterminado).

  • Se debe tener permisos para agregar, así que no es muy factible de escalar en nuestras app web

Como podemos ver, no es muy oportuno utilizarlo, pero dejo la opción para indicar los inconvenientes.

 

 

OPCION 2: Obtener el tipo MIME “manualmente” ayudándonos con una estructura de un  Diccionario (o switch kilométrico)

La mejor recomendación es utilizar un diccionario para acceder por la key (pero podrías también tener una lista genérica con un tipo de entidad creada para tal fin)

Ejemplo con un Dicccionario:

private static readonly Dictionary<string, string> TiposMime =
new Dictionary<string, string>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase)
{
{".323", "text/h323"},
{".3g2", "video/3gpp2"},
{".3gp2", "video/3gpp2"},
{".3gp", "video/3gpp"},
{".3gpp", "video/3gpp"},
{".aac", "audio/aac"},
{".aaf", "application/octet-stream"},
....

A tener en cuenta que necesitaríamos buscar en ella a partir de los dos valores. El mas común siempre es buscar a partir de la extensión pero también nos puede servir en algún momento la inversa buscar a partir de un tipo MIME la extensión correspondiente.

 

 

OPCION 3: Obtener mediante el método  GetMimeMapping de la clase System.Web.MimeMapping [Nuevo desde ASP.NET 4.5]

Desde la versión de ASP.NET 4.5 tenemos la clase System.Web.MimeMapping que posee un solo método de clase GetMimeMapping que lo bueno es que obtiene los valores MIME de dos lugares diferentes dependiendo del modo que esta configurado el Pool de Aplicaciones en el IIS donde se aloja nuestra aplicación web

  • Si se encuentra en modo Clásico: Obtiene el valor de un diccionario que se encuentra entro del assembly (idem a opcion2). Si somos curiosos y vemos el código fuente vemos 343 mapeos (System.Web.dll v4.0.30319.17929)

  • Si se encuentra en modo Integrado: Obtiene los valores de la lista de tipos Mime configurada en el IIS. Lo cual es mucho mejor y extensible sin tocar el código de nuestro mapeador

Podemos ver como esta codificado y así investigamos como se obtiene los datos

SNAGHTML153d8f43

http://msdn.microsoft.com/en-us/library/system.web.mimemapping.getmimemapping.aspx

Lo bueno

  • Al actualizar el sistema operativo más tipos MIME se añaden a IIS

    (incluso podríamos agregar los que necesitamos)
  • Podemos agregar tipos MIME personalizados por app con solo utilizar la seccion system.WebServerstaticContent

    (que desde IIS7 toma)

    • [Otro post] Agregar tipos MIME personalizados a IIS/IIS Express o nuestra app web en la seccion staticContent  del web.config

A tener en cuenta

  • El diccionario embebido que se utiliza en modo Classic contiene 343 mapeos (System.Web.dll v4.0.30319.17929)
  • El diccionario en modo Integrado (IIS Express): 374 mapeos (archivo ..IISExpressconfig, seccion system.WebServerstaticContent
    … pero además podemos agregar lo que necesitamos para una app específica

 

Ejemplo

Por ejemplo si necesitamos mapear la extension .yoda al tipo mime starwars/characters

Utilizando el IIS Express (o IIS 7 o superior), podríamos mapear el contenido estatico directamente en el web.config, para que sola esta aplicacion tome este tipo MIME

(mas abajo esta el ejemplo para descargar)

<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".yoda" mimeType="starwars/characters" />
</staticContent>
</system.webServer>
</configuration>

Entonces en modo Integrado (nos devolveria) starwars/characters y en modo clasico el tipo MIME por default application/octet-stream

SNAGHTML3d92f1e

 

Ejemplo para descargar

Enlace para descargar: http://sdrv.ms/WXeNel

 

Referencias

[ASPNET/VS2012] Como descargar e instalar offline Web Developer Tools 2012.2

Bueno si tienes varias maquinas en una intranet para que estar descargando en cada una el instalador a través de web plataform, es bueno descargarlo el instalador y compartirlo

Como sabrán se descarga a través del Web Platform installer

http://www.microsoft.com/web/handlers/webpi.ashx?command=getinstallerredirect&appid=ASPDOTNETandWebTools2012_2

 

Puedes descargar ASP.NET and Web Frameworks 2012.2 (32Mb) desde Microsoft Download.
El enlace directo es:
http://download.microsoft.com/download/6/5/6/6562AFBE-9503-4E64-970C-1427133FCD73/AspNetWebTools2012Setup.exe

(NOTA: No se porque no esta buscando por el texto, el que aparece en el buscador es e la versión RC que tiene 50Mb y es de Dic/2012, debe ser para que lo hagamos por Web Platform installer)

Bueno pero si descargamos directamente la versión final que pesa 32Mb la podremos instalar tranquilamente…

SNAGHTML532c359

Si tienes “Microsoft Visual Studio 2012 for Web” (que es la version express para web) tendrías que descargar esto

 

Referencia

 

[ASPNET] ModalPopupExtender control vía javascript, eventos (showing/shown/hidding/hidden). Limpiar controles

Como podemos limpiar los controles dentro de un ModalPopupExtender (léase dentro de un panel asociado a un ModalPopupExtender)? O simplemente realizar acciones en el cliente cuando se visualiza un ventana modal?

Bueno podemos limpiarlo al momento de realizar la acción de postback. Pero si lo queremos limpiar en el cliente? Que tenemos disponible?
Aquí tendremos que utilizar los  propiedades OnOkScript y OnCancelScript, pero también podremos suscribirnos a estos eventos con nuestras propias funciones, para ello utilizaremos: add_showing / add_shown  / add_hiding / add_hidden

Además dejo un ejemplo para descargar.

Vemos entonces:

  1. Como descargar e instalar AjaxControlTookit en VS2012 (VS2010) con NuGet
    Como descargar/instalar los componentes, agregarlos a la barra de herramientas
  2. Manipular el ModalPopup vía Javascript
  3. ModalPopup y sus eventos (suscripción a eventos)

 

1) Como descargar e instalar AjaxControlTookit en VS2012 (VS2010) con NuGet

Como hace un par de años no utilizo AjaxControlTookit, estoy mucho con proyectos ASP.NET MVC… pero siempre es bueno refrescar componentes. Y si estas utilizando ASP.NET Webforms es util esta librería que nos da un abanico de controles y extensiones de controles webforms para utilizarlo con “ajax features” sin escribir mucho codigo, simplemente configurando.

Lo bueno de ver esto es que me hizo ver la forma de descargar estos componentes por NuGet en un proyecto con VS2012…

Asi que para descargarlo simplemente ir al Administrador de Paquetes de NuGet

SNAGHTMLb523d68

Y buscarlo…

SNAGHTMLb54638e

Y como ya lo conocemos a la configuración… pero nuget lo hace por vos. Nos queda asi (y algo mas para agregar los controles)

Te agrega los assemblies necesarios en el BIN
SNAGHTMLb57a1f4
Y te configura el prefijo para los controles en el web.config SNAGHTMLb56fe37
Agregar los controles en la barra de herramientas

(esto no es automático)

Pero te creas el nuevo tab en la barra y arrastras simplemente el assembly

SNAGHTMLb8ac203

 

Para utilizar el ModalPopupExtender ya nos comentaba algo Luis Miguel Blanco

Pero además tenemos el sitio de ejemplo de AjaxControlToolkit para visualizar el modo de utilización del ModalPopupExtender

 

 

2) Manipular el ModalPopup vía Javascript

Como Visualizar/Mostrar vía javascript una ModalPopupExtender?

AQui debemos obtener el Id del lado del cliente, mediante la propiedad ClientID (que tambien podemos modificar su comportamiento con la propiedad ClientIDMode), luego nos valemos del metodo $find (acceso directo al método findComponent de la clase Sys.Application)

function abrirModal() {
var modalId = '<%=ModalPopupExtender1.ClientID%>';
var modal = $find(modalId);
modal.show();
}

Para ocultar el metodo: hide();

NOTA: Si vamos al ejemplo de ModalPopup Demonstration podemos ver en el código HTML como se realiza dicha acción.

 

 

3) ModalPopup y sus eventos (suscripción a eventos)

Eventos: add_showing / add_shown  / add_hiding / add_hidden (y sus respectivos remove)

Podemos ver el archivo ModalPopupBehavior.pre.js del código fuente en CodePlex (ajaxcontroltoolkit.codeplex.com) de AjaxControlToolkit que tiene estos eventos, que son metodos para agregar nuestros funciones cuando estan sucediendo estos eventos…

  • add_showing / remove_showing: Cuando se esta por visualizar el modal
  • add_shown / remove_shown: Cuando ya se visualizo el modal
  • add_hiding / remove_hiding: Cuando se esta comenzando a ocultar (se dispara primero)
  • add_hidden / remove_hidden: Cuando ya se oculto el modal (luego recien se dispara el OnCancelScript)

 

Ejemplos del codigo fuente:

SNAGHTMLb8c63cd

 

SNAGHTMLb96fe19

 

Suscribiéndose con funciones propias a los eventos

Aquí necesitamos realizar esto en el load, y no suscribimos a la función add_load de la aplicación del lado del cliente con (puedes descargar el ejemplo de código que dejo mas abajo)

Sys.Application.add_load(modalInicializar);

NOTA IMPORTANTE: Esto debe estar dentro del tag form de nuestro webforms

Bueno en el ejemplo podemos ver como disparar estos eventos



<script type="text/javascript">

Sys.Application.add_load(modalInicializar);



function abrirModal() {
var modalId = '<%=ModalPopupExtender1.ClientID%>';
var modal = $find(modalId);
modal.show();
}


function modalInicializar() {
var modalId = '<%=ModalPopupExtender1.ClientID%>';

//Antes de visualizarlo
$find(modalId).add_showing(modalShowing);

//Una vez que se renderizo
$find(modalId).add_shown(modalShown);

//Ocultando...
$find(modalId).add_hiding(function () {
alert('Hiding...');
});

//Una vez que se oculto
$find(modalId).add_hidden(function () {
alert('Hidden...');
});
}
</script>

Como vemos hay varias formas de suscribirse, pasando como parámetro la función a llamar o escribiendo la función anónima directamente… tu eliges dependiendo de tu política de desarrollo

Ejemplo: Limpiar controles al momento de visualizar/mostrar el modal

Aqui en el evento previamente que nos “suscribimos con nuestra función”:
$find(modalId).add_showing(modalShowing);

 
Entonces seria algo así en el ejemplo para descargar:
function modalShowing() {
alert('modalShowing...');
modalLimpiarControles();
}


function modalLimpiarControles() {
//OPCION1: Limpiando cada control con javascript "puro"
//------------------------------------------------------
//var txtNombre = '<%=txtNombre.ClientID%>';
//var txtApellido = '<%=txtApellido.ClientID%>';

//document.getElementById(txtNombre).value = '';
//document.getElementById(txtApellido).value = '';

//
//

//OPCION2: Limpiando con jquery todos los textbox
//-------------------------------------------------------
var panelModal = '<%=Panel1.ClientID%>';
jQuery('#' + panelModal + ' input[type=text]').val('');

}

 

Como verán la parte de  limpieza de controles es porque en las preguntas de los foros de MSDN este era el objetivo final (la cual me disparo que publique este post que lo tenia en borrador), pero puede ser cualquier acción necesaria sobre estos controles (focus, obtener datos, presentar imágenes de cargando.. etc)

 

 

Ejemplo para descargar

Puedes descargar el ejemplo “simple” desde aquí: ASP.NET-ModalPopupExtender-Demo.zip

 

 

Enlaces

 

[ASP.NET] Asignar el DefaultButton de un webcontrol Login

Como asignar un DefaultButton para un formulario de Login que se encuentra en un layout con MasterPages y el común denominador de un formulario de login que siempre lo podemos encontrar del lado derecho o arriba a la izquierda.  
Esta fue la pregunta desde los foros de MSDN de ASP.NET que si bien no es fácil asignar esta propiedad cuando el botón objetivo se encuentra dentro de un template de un webcontrol, se puede hacer y aqui dejo para ”ayuda-memoria” y referencia.

Si bien lo podemos hacerlo mediante javascript (algo similar ya lo comente por aquí) la idea en el presente articulo es aplicar la propiedad DefaultButton que lo tiene los controles Form (HtmlForm) y Panel.

Particularmente por el layout presentado era que MasterPage que en una pagina con un formulario, cuando se quería dar login y desde el texbox de password al “presionar el enter” no era el evento por default el botón de login sino otra parte de la pagina. Como sabrán esto depende de como esta “armada” ya que en HTML el tab de los controles es en orden que están en el HTML (no del orden visible). Por eso que tenemos en ASP.NET la posibilidad de asignarlo este comportamiento tan natural a un Form (HtmlForm) o Panel. Incluso si estas familiarizado con los ValidationGroups de los controles esto viene a ayudarnos una vez mas a tener “porciones o grupos de formularios independientes” en nuestros webforms.
NOTA: Solo se admite para esta propiedad controles Button e ImageButton.

 

Como asignamos la propiedad DefaultButton de un Panel con el botón de un webcontrol Login?

Aquí tienes dos opciones para asignar esta propiedad por código y mediante el uso de identificador que renderiza en el cliente (sin código)
Si bien podemos convertir a template el webcontrol para manipular los controles internos de su template, el botón de login sigue dentro y no podemos obtener directamente su UniqueID (pero si lo podemos hacer por codigo)

SNAGHTML48a04527

Y vemos realmente el ID del botón:

SNAGHTML48a2b180
Pero estas dos opciones que comentare no es necesario convertir a template el webcontrol.

OPCION 1: Por código asignamos el DefaultButton al panel (obteniendo el botón de login mediante FindControl)

Aquí la idea es por código obtener el UniqueID (identificador único jerárquico) del botón, si necesidad de convertirlo a template.

Si tenemos por ejemplo el siguiente webcontrol login dentro de un panel:

<asp:Panel ID="pnlLogin" runat="server">      
Aqui otro boton de login<br/>
<asp:Login ID="Login1" runat="server"
onauthenticate="Login1_Authenticate"
onloggingin="Login1_LoggingIn">
</asp:Login>
</asp:Panel>

Y desde el codebehind asignamos la propiedad DefaultButton del Panel.

Para eso obtenemos el botón dentro del webcontrol Login (con FindControl) y lo asignamos el UniqueID del mismo como propiedad del DefaultButton del panel

protected void Page_Load(object sender, EventArgs e)
{
pnlLogin.DefaultButton = ((Button)Login1.FindControl("LoginButton")).UniqueID;
}

Vemos que es necesario el UniqueID y no el ClientID, textual de MSDN:


(…)Esta propiedad se diferencia de la propiedad de ID , en que la propiedad de UniqueID incluye el identificador del contenedor de nomenclatura del control de servidor. Este identificador se genera automáticamente cuando se procesa una solicitud de página.(…)

SNAGHTML48b2bfb4

 

OPCION 2: Vía el nombre del webcontrol padre (en modo diseño, "Login1$LoginButton")

Aquí nos ayudamos de nombre del que obtiene el botón que se encuentra dentro del webcontrol login

SNAGHTML48812bec

Como vemos en la propiedad name se concatenan con $ los nombres de los controles padres hasta el control. Esto es la jerarquía del control (útil para controles con el mismo nombre) 
No es necesaria toda la ruta solamente el control contenedor padre (ya que el panel se encuentra en la misma ubicación y como padre del webcontrol login) para asignar a la propiedad…

Es decir nos quedaría así:

DefaultButton="Login1$LoginButton"

<asp:Panel ID="pnlLogin" runat="server" 
DefaultButton="Login1$LoginButton">
Aqui otro boton de login<br/>
<asp:Login ID="Login1" runat="server" ClientIDMode="Static"
onauthenticate="Login1_Authenticate"
onloggingin="Login1_LoggingIn">
</asp:Login>
</asp:Panel>

Y así ya estaría funcionando el DefaultButton.

NOTA (por si se confunde el id con el name): Para esta opción 2 utilizamos el NamingContainer que se renderiza en el name que justamente no influye el modo que lo utilicemos a la propiedad ClientIDMode porque aquí esta dentro de un control Login y siempre lo estará, pero lo único que cambia es el id del lado del cliente (por eso es la propiedad ClientIDMode)

O sea el id de “cliente” cambia pero no el name cuando la propiedad es Static por ejemplo

SNAGHTML48a7f718

 

 

Otros enlaces que te pueden ayudar

 

Delicious tags : ,

[ASP.NET/IIS] Compartir las variables de session entre diferentes App con modo StateServer (modificando el AppDomainAppId)

Esta es una articulo que se corresponde con uno anterior donde hable sobre las opciones de compartir session:

Particularmente en este articulo veremos la opción 1.1

OPCION 1: Cambiar el modo de estado de session (SessionState) a StateServer

OPCION 1.1: O cambiamos el ID de App (AppDomainAppId)

OPCION 1.2: O cambiamos el método que se obtiene el ID de Session (sessionIDManagerType)

Si bien hay varias opciones para compartir, la idea de hacerlo con el Servicio de estado de ASP.NET (StateServer) pero no tiene en modo nativo la forma de unificar el nombre de la aplicación y mas precisamente la propiedad AppDomainAppId que se utiliza dentro del servicio de estado para mantener el diccionario de variables de session por aplicación. Además mas abajo un ejemplo para descargar

 

Vamos paso por paso

Pasos que debemos cumplir para lograr el objetivo

  1. Todas las aplicaciones deben estar bajo el mismo dominio (para restricciones de cookie) IMPORTANTE!
    En este caso mis pruebas fueron bajo localhost, pero funciona si cambas el dominio. Solo respetar que cada app esta bajo el mismo dominio
  2. Establecer el SessionState en modo StateServer
  3. Configurar el servicio de estado de session (Importante)
  4. Establecer la misma machinekey
    Incluso para compartir entre diferentes servidores cuando estas en un cluster
    Ejemplo: Puedes encontrar varios generadores online
  5. Establecer la misma nombre de la cookie
    PAra poder compartir los datos deben ser ubicados (en la misma cookie de session). Acuerdense que es simplemente un identificador
  6. IMPORTANTE El mismo nombre de la app (mmmm!??) propiedad AppDomainAppId
    Por lo que hice este post donde explicamos como modificarla

 

Paso 1: Todas las aplicaciones deben estar bajo el mismo dominio

Aclaraciones, bajo el mismo dominio, y están configuradas como directorios virtuales. (mas abajo el ejemplo para descargar)

image

Para crear una de estas app

SNAGHTMLc52d597

image

Mas adelante veremos como se obtiene el nombre de la app AppDomainAppId (Paso 6)

Paso 2: Establecer el SessionState en modo StateServer

Aqui utilizamos la seccion del web.config sessionState para establecer donde se ubicara nuestra variables de session

<sessionState cookieName="YODADemoApp" 
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />

Aqui el primer comentario es que no tiene una forma de setear el nombre de la aplicación, siendo que en su correspondiente funcionalidad en Windows Azure si tiene! Sorpresa vamooosss que se puede modificar applicationName

http://msdn.microsoft.com/en-us/library/windowsazure/gg185682.aspx

 

PASO 3: Configurar el servicio de estado de sesión

Para que funcione al configuración del Paso 3 donde establecimos el modo StateServer y la ubicacion del servidor en la maquina local debemos habilitar ese servicio

SNAGHTMLc29ee92

 

Paso 4: Establecer la misma machinekey

Incluso para compartir entre diferentes servidores cuando estas en un cluster o en la misma maquina debes configurar la misma machinekey que se utiliza para:

“(…)Configura los algoritmos y las claves que se utilizan en el cifrado, descifrado y validación de los datos de autenticación de formularios y de los datos de estado de vista, así como para la identificación del estado de sesión fuera de proceso.(…)”

Ejemplo: Puedes encontrar varios generadores online

 

Paso 5: Establecer la misma nombre de la cookie

PAra que se guarde el valor de la session (un indentificdor) y que podamos obtenerlo a traves de multiples applicaciones en necesario que el nombre sea identico, por esta razon es conveniente modificarlo en la propiedad cookieName de sessionState

<sessionState cookieName="YODADemoApp" 
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />

 

Paso 6: IMPORTANTE El mismo nombre de la app (mmmm!??)

Bueno hicimos todo lo anterior, pero cuando utilizamos StateServer para guardar los datos de session el proveedor utiliza el ApplicationName. El servicio es simplemente un ejecutable que tiene en cuenta el nombre de la aplicación

SNAGHTMLc3d7722

 

Como unificar el mismo nombre de ApplicationName para guardar el estado de session

Por aquí podemos leer que los proveedores de utilizan el nombre de la app para mantener el estado de session:

(…) Para mantener el ámbito de la sesión, los proveedores de estados de sesión guardan por separado la información de sesión de cada aplicación. De esta forma, varias aplicaciones ASP.NET pueden usar el mismo origen de datos sin entrar en conflicto en caso de que se encuentren identificadores de sesión duplicados.

Dado que los proveedores de almacén de estados de sesión guardan por separado la información de sesión de cada aplicación, deberá asegurarse de que el esquema de datos, las consultas y las actualizaciones incluyen el nombre de la aplicación. Por ejemplo, se podría utilizar el comando siguiente para recuperar los datos de sesión de una base de datos.(…)

 

Cual es el nombre de mis app en este ejemplo

Las app que configure bajo el WebSite0 (dos websites ASP.NET Webforms y un app con ASP.NET MVC)

SNAGHTMLbdfcdb8

El árbol en el IIS quedo así en el ejemplo:

Para las app Los AppDomainAppId son respectivamente
image
WebSite0:

/LM/W3SVC/2/ROOT

WebSite1:

/LM/W3SVC/2/ROOT/WebSite1

WebSite2:

/LM/W3SVC/2/ROOT/WebSite2

MvcApplication1:

/LM/W3SVC/2/ROOT/MvcApplication1

De donde sale este nombre?

Podes listar las app con la herramienta de lista de comandos appcmd pero los AppDomainAppId no se encuentran visible

Comando: appcmd list app

SNAGHTMLbe61024

Pero ni aquí encontré el AppDomainAppId

SNAGHTMLbefffcf

Pero si listamos la configuración por sitio podemos ver el ID del sitio (un numero), con appcmd:

SNAGHTMLc014854

En la configuración avanzada mediante el Administrador de IIS

SNAGHTMLc033947

Entonces… como se arma el nombre?

El primer sitio que esta detenido “Default Web Site” es el primero que se creo en mi IIS local es el sitio numero 1, el segundo que cree para esta demo es WebSite0 que como es el 2 y el el raiz tiene el nombre:

/LM/W3SVC/2/ROOT

Por eso los nombres: /LM/W3SVC/2/ROOT/{nombre de la app}

 

 

Cambiar el AppDomainAppId

Primero antes de cambiarlo como lo leemos desde nuestro código:

Por eso veras en que el ejemplo que lo colocamos al nombre en un webcontrol literal llamado litAppDomainAppId:

private void RefrescarControles()

    {

        litAppDomainAppId.Text = HttpRuntime.AppDomainAppId;

 

        Literal1.Text = SessionHelper.Variable1;

        Literal2.Text = SessionHelper.Variable2;

    }

Como cambiar

Si vemos la propiedad es estática y de solo lectura, así que no nos sirve ya que no podremos modificarla

Aquí nos ayudamos Reflection para obtener la variable privada dentro de HttRuntime que contiene el valor que es expuesto a traves de la propiedad AppDomainAppId. Ya han publicados ejemplos aquí y aquí, pero bueno es Reflection al fin y al cabo

El ejemplo seria en una método estático que nos ayude a modificar el nombre:

public static class SessionStateServerSharedHelper
{
public static void ChangeAppDomainAppId(string name)
{
FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
if (runtimeInfo == null) return;
HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
if (theRuntime == null) return;
FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);
if (appNameInfo == null) return;
var appName = (String)appNameInfo.GetValue(theRuntime);
if (appName != "applicationName") appNameInfo.SetValue(theRuntime, name);
}
}
 
En el global.asax nos ayudamos con el evento Application_Start (que se ejecuta una sola vez al primera vez que se solicita un recurso a la aplicacion web ASP.NET)
void Application_Start(object sender, EventArgs e) 
{
// Code that runs on application startup
SessionStateServerSharedHelper.ChangeAppDomainAppId("YODADemoApp");
}

Con esto logramos que nuestras aplicaciones donde aplicamos esto tengan el mismo nombre y asi poder compartir las variables de session cuando utilizamos ASP.NET State Server
 

NOTA 1: El único problema que podemos encontrar es cuando los chicos de IT están monitoreando nuestros sitios y necesitan conocer en que app causo el problema, pero bueno hablando con ellos podremos detectarla con al nombre y la url que dio el error

NOTA 2: Cambiar metadata del IIS para unificar directorios: Si bien hay una forma de cambiar la metada es mas bien para compartir entre sitios web (aqui la idea que es que se mantenga la metadata y a nivel de aplicacion

 

El ejemplo para descargar

Sencillo para observar los pasos comentados. Se puede mejorar encapsulando este comportamiento y no estar compartiendo archivos de clase (eso lo dejo para mejorar por el que necesita utilizarlo). Lo puedes descargar directamente aquí

   
Tres aplicaciones bajo un solo dominio

2 Websites ASP.NET Webforms

1 Webapp ASP.NET MVC

Debes configurarlo en el IIS como aplicaciones

image
Donde el negocio es simplemente modificar variables de session y ver los valores de todas las variables

Website1: Modifica la variable 1, Visualiza ambas variables

WebSite2: Modifica la variable 2

, Visualiza ambas variables

MvcApplication1: Visualiza ambas variables

SNAGHTMLc6dd182
Todas tienen una clase que nos ayuda a modificar el nombre de AppDomainAppId mediante Reflection Clase SessionStateServerSharedHelper

Metodo de clase (estatico): ChangeAppDomainAppId


Además nos ayudamos para tener intellisense en las variables de session con una clase.

Por ejemplo para obtner el valor de la Variable1 de session utilizo

public static string Variable1
{
get
{
if (HttpContext.Current.Session["Variable1"] != null)
{
return HttpContext.Current.Session["Variable1"].ToString();
}

return string.Empty;
}
set {
HttpContext.Current.Session["Variable1"] = value;
}
}

Una mejora es que el nombre de la AppDomainAppId compartida sea configurada por el AppSettings pero como se mencione mas arriba deberías reiniciar la app para que lo tome. Esto se puede solventar con la opcion 1.2 sessionIDManagerType que será para el próximo post

 

 

Espero que les sirva de ayuda o guía.

 

Delicious tags : , , , , ,

,

[ASP.NET/IIS] Como compartir las variables de Session entre diferentes Applicaciones Web

Hay momentos y aplicaciones que a veces debemos necesitamos compartir sus variables de session entre otras app web (sea con Webforms o ASP.NET MVC)

Esta fue una pregunta en los foros de MSDN pero también de un equipo de desarrollo donde hace par de meses donde estaba facilitando una capacitación en ASP.NET, así que dejo plasmado aquí (la ayuda memoria) y de como seria la manera de realizarlo con la configuración del administrador de estado de sesión.

La idea es este post es presentar un listado de opciones que tenemos para compartir y obligarme (cuando tenga un tiempo) de ir publicando mas en detalle y tener ejemplos de cada una para que sea más útil.

A la pregunta:

"…¿Cual es la mejor manera de compartir variables de sesión entre aplicaciones virtuales?…"

Compartir? Estas seguro?

La idea de compartir sesión si bien se puede realizar hay que evaluar bien este tipo de “conexión entre app” es decir evaluar arquitectura de app que tenemos…

  • Por que la naturaleza separada de estas app? están separadas en dominios de app diferentes y se quieren compartir datos?
  • Podriamos implementar un login común, pero bueno… eso es otro tema. Si es necesario un SSO (single-sign-on)
  • La arquitectura que se le da a las app web que estamos desplegando. Porque podríamos tener otras formas de compartir variables y que el usuario se siente libremente “paseando entre app web” (y porque no entre diferentes app en tu maquinas locales)
  • Por algo se realizan app separadas, si es necesario compartir algo seria otro tipo de arquitectura o mediante componentes comunes

Pero no es tema de este post pero es bueno que te detengas a pensarlo aunque sea tomando una cerveza.
Pero el tema que me atañe comentar son las formas de formas que tenemos de compartir la session del usuario… asi que

Las opciones que tenemos…

Si lo que quieres es compartir la variables de session podemos

  • OPCION 1: Cambiar el modo de estado de session (SessionState) a StateServer
    Para realizar esto debemos utiliza: el mismo nombre de cookie, la misma configuración del machineKey en el web.config de la app y además el mismo nombre de aplicación (que?)
    En esta ultima parte esta el problema, no es fácil cambiar el nombre de App (para el modo de StateServer, pero se puede) por default el AppName que da el IIS (que es algo asi LM/W3SVC/2/ROOT/WebSite1) o cambiamos la forma

<ayudaMemoria>{aquí va el enlace al post con mas detalle}</ayudaMemoria>

  • OPCION 2: Cambiar el modo de estado de session (SessionState) a SQLServer
    Utilizando el motor SQL Server ya sabemos para guardar el estado de session, esta opción es idem al anterior pero mas fácil ya que son procedimientos almacenados los que debemos modificar.
  • OPCION 3: Cambiar el modo de estado de session (SessionState) a Custom, 
    Y utilizar algún componente de proveedor de estado de session que hayas armado que contemple poder compartir las variables
  • OPCION 4: Utilizar una DB para compartir "elementos comunes"
    Idem al punto 3, pero tendríamos que codifica la lógica sin ayudarnos con un proveedor de estado de session
  • OPCION 5: Pasar variables de session mediante un mecanismo GET/POST
    Idem a la técnica para a pasar variables de session desde ASP Clásico, PHP, etc)… muy artesanal esta opción y difícil de mantener
  • OPCION 6: Utilizar Windows Server AppFabric Cache con un proveedor Custom de estado de session
    Bueno si bien esta opción es como la 3, aquí la vedette es Windows Server AppFabric y el servicio de Cache Distribuido (ex nombre clave Velocity)  que podamos instalarlo en varios servidores y administrar los objetos de cache agrupándolos por un simple nombre e incluso regiones (en vez de tener una sola “bolsa”), administración centralizada… la verdad una belleza.

NOTA 1: Creo que son estas 6 si hay alguna otra escriban mas abajo en comentarios así aumentamos conocimiento y estrategias Guiño

NOTA 2: Lo que no tengo es conocimiento sobre Azure en mi know-how, hasta que pueda tener mi codekata en algún proyecto

 

En este momento el post se hizo extenso así que lo particioné en estos temas para que sean mas cohesivos. Espero llegara escribir todos las opciones en artículos por separado o por lo menos tener enlaces para ayudar en cada caso

Necesito feedback al respecto, así que por favor sus comentarios son bienvenidos

  • Cuando utilizarla? Cuando no utilizarla?
  • Has necesitado esto alguna vez?

Espero que les sirva de ayuda o guía.

 

Delicious tags : , , , , ,

,

[VS2010+SP1+NuGet] Actualización manual de NuGet (copiando y pegando archivos) cuando tenemos problemas en la instalación/actualización en VS2010 SP1.

Este problema es conocido desde la versión SP1 del VS2010, por lo menos a mi me toco vivenciar este problema en varias maquinas y esta documentado en los “known-issues” por si alguien necesita mas info.

En su momento fue porque instale una versión de NuGet antes de instalar SP1, algo así fue no recuerdo bien…me volvió a pasar en una maquina virtual de hace un tiempo así que dejo como instalar “manualmente” (copiando y pegando archivos).

Justo hoy quise actualizar una maquina virtual que la tenia para algunos proyectos, pero también sucedió con estas versiones (las anote por las dudas):

  • 1.2.20325.9034 (un poco antigua) a la versión 1.6.21215.9133
  • 1.5.20902.9026 a la versión 1.6.21215.9133
  • Y hace unos minutos de la versión 1.6.30117.9648 a la versión 1.7.30402.9028
    (aquí con solo descargar el instalador y ejecutarlo funcionó).

[Actualización el Lun/04/Jun/2012] Veo en Hotfix para VS2010 SP1: KB2581019 en el sitio la pagina de descarga de NuGet. Va como Solución 3

Si por las dudas tratas de instalar NuGet en un  Visual Studio 2010 SP1

Y en el log tienes el siguiente mensaje de error:

VSIXInstaller.SignatureMismatchException: The signature on the update version of ‘NuGet Package Manager’ does not match the signature on the installed version. Therefore, Extension Manager cannot install the update.

Y la pantalla:
image

 

Solución 1: Desinstalar y volver a instalar

  1. Desinstalar NuGet
    1. Desde el VS2010. En Herramientas > Administrador de Extensiones
      image
      (NOTA: Si no te aparece este botón para desinstalar habilitado debes iniciar VS como Administrador)
    2. O por el Panel de Control
      image
  2. Volver a instalarlo… (con la opción que mas te guste)

 

Solución 2: Instalar una actualización de NuGet “manualmente”

Como instalar el administrador de paquetes manualmente…

  1. Descarga la ultima versión de NuGet desde Visual Studio Gallery
    (ejemplo la ultima versión al 24/04/2012 es la 1.7.30402.9028)
  2. Descomprime el archivo (las extensiones de .vsix son archivos comprimidos)
    image
    Cambias la extensión por .zip y descomprimes…
    Algo ya nos había mencionado El Bruno:
       – [#VS2010] HowTo: Instalar un paquete VSIX sin utilizar el instalador 
  3. En la carpeta de instalación del administrador de paquetes de NuGet en Archivos de Programas  
    1. En 32bits:
      %ProgramFiles%Microsoft Visual Studio 10.0Common7IDEExtensionsMicrosoft CorporationNuGet Package Manager
    2. Si estas en 64bits la carpeta es Archivos de Programas (x86)
      %ProgramFiles(x86)%Microsoft Visual Studio 10.0Common7IDEExtensionsMicrosoft CorporationNuGet Package Manager
  4. Se debe crear la carpeta para la versión a instalar y copiar todos los archivos que se descomprimieron.
    En este ejemplo que descargue la versión 1.7.30402.9028 aqui la carpeta

    NuGet-Carpeta-Instalacion-02

  5. Y listo! ya esta disponible esta versión
    Como sabemos cual esta utilizando VS2010?
    Si vamos a Herramientas > Administrador de Extensiones podremos ver la versión de Administrador de Paquetes de NuGet
    image

 

Solución 3: Un hoxfix salvador

[Actualización el Lun/04/Jun/2012] Veo en Hotfix para VS2010 SP1: KB2581019 en el sitio la pagina de descarga de NuGet. Va como Solución 3

Te instalas este Hotfix para VS2010 SP1

 

 

Enlaces

Delicious tags : , ,

[ASP.NET+jQuery] Gridview con checkbox limitando a un solo valor de selección

Si necesitamos tener un control checkbox en cada fila y que solo podamos seleccionar un sola fila a la vez (idem a un option)
Esto puede servir tanto para ASP.NET Webform como para MVC, con la salvedad de que depende de como renderizan las grillas de datos.
Gracias a una pregunta de los foros de MSDN de ASP.NET “Limitar selección Checkbox en GridView” tenia algo similiar en el borrador así que aquí va.

Si tenemos un Gridview con una columna template algo así:

<asp:GridView ID="GridView1" runat="server" 
        AutoGenerateColumns="False">
        <Columns>
            <asp:TemplateField HeaderText="Seleccion">
                 <ItemTemplate>
                     <asp:CheckBox ID="chkSeleccion" runat="server" CssClass="controlSeleccion" />
                 </ItemTemplate>
            </asp:TemplateField>  
            <asp:BoundField DataField="Nombre" HeaderText="Nombre" />
            <asp:BoundField DataField="FechaNacimiento" HeaderText="Fecha Nacimiento" />
        </Columns>
    </asp:GridView>

 

Cuando renderiza en ASP.NET 4.0 lo hace de esta manera

La tabla HTML La celda con el control
image image

Solución con jQuery: Evento .click()

Podriamos tener un selector en jQuery que tome todos los checkbox que están dentro de nuestra clase “controlSeleccion” y cada vez que se realiza un evento click (con mouse o sin el directamente con el teclado igualmente dispara el evento)

<script type="text/javascript">
   1:         $(function () {
   2:             $('.controlSeleccion input:checkbox').click(function () {
   3:                 $('.controlSeleccion input:checkbox').removeAttr('checked');
   4:                 $(this).attr('checked', true);
   5:             });
   6:         });    

</script>

NOTA: El selector :checkbox es identico a [type=checkbox]

Solución con jQuery: Atachando el evento con .on() (nuevo en jQuery 1.7)

En la version 1.7 de jQuery tenemos la sintaxis “.on()” para bindear a eventos (como lo eran live o bind, etc).

Nos quedaria algo asi para hacer lo anterior:

<script type="text/javascript">
   1:     $(function () {
   2:         $('.controlSeleccion input:checkbox').on('click', function () {
   3:             $('.controlSeleccion input:checkbox').removeAttr('checked');
   4:             $(this).attr('checked', true);
   5:         });
   6:     });    

</script>

 

Para otros post:

Mas adelante escribiré como hacer que este checkbox se comporte como el “comando de selección del gridview”, para que nos quede todo “un poco mas elegante”, ya que en este caso particular el desarrollador deberá “iterar” para buscar que control esta seleccionado. Una mejora seria que este control este enlazado a algun campo booleano del la colección de objetos

 

 

Espero que les sirva de ayuda o guía.

[Control+F 2011] Curso Terminado: .NET Senior 80hs. WPF/WCF/Silverlight (Polo IT Corrientes)

Se acerca fin de año y por estos lugares, terminó un curso intensivo (y casi sin respiro) de estas tres tecnologías (WPF/WCF/Silverlight) en el marco de las Becas Control+F (@becascontrolf)

“Con el objetivo de fomentar más y mejor empleo en las áreas de software y tecnología a nivel nacional, el Ministerio de Trabajo, Empleo y Seguridad Social de la Nación, en conjunto con CESSI, y con el apoyo de empresas referentes del sector, ofrecen cursos de capacitación gratuita en todo el país.”

Esta vez se armaron en Corrientes, y los gestionó el Polo IT Corrientes a los cursos de Programación .NET Junior, .NET Senior, Administración en SQL Server y Genexus

Aquí los que rindieron el primer día, y los del segundo (a la derecha):

ControlF-NETSENIOR-2011

Algunos ya trabajaban con este tecnología o en .NET, pero la mayoría alumnos de entidades educativas de la región (UTN FRRe, UNNE, Institutos de IT)  y por eso razón casi la mitad del curso quedo en el grupo de los rezagados que quedaron por el camino (por falta de tiempo)

Mas fotos

 

Similares que tuve la oportunidad de estar al frente:

Mas info

[EF] Utilizar el ConnectionString de mi modelo Entity Framework

Trabajando con Federico necesitamos realizar consultas a la DB “dinámicamente” para rellenar reportes con Report Server embebido en nuestras aplicaciones web.
Para eso utilizamos Procedimientos Almacenados, y como queremos que sea lo mas “genérico posible”, obtenemos el nombre del reporte (ya sea por un campo de la DB o armándolo con alguna política de nombres teniendo en cuenta el del reporte).

Como sabemos la Cadena de Conexión de Entity Framework esta compuesta por la cadena, path de archivos del modelo y de asignación. Por ejemplo…

<connectionStrings>
    <add name="AdventureWorksEntities" 
         connectionString="metadata=.AdventureWorks.csdl|.AdventureWorks.ssdl|.AdventureWorks.msl;
         provider=System.Data.SqlClient;provider connection string='Data Source=localhost;
         Initial Catalog=AdventureWorks;Integrated Security=True;Connection Timeout=60;
         multipleactiveresultsets=true'" providerName="System.Data.EntityClient" />
</connectionStrings>

Para armar nuestro Comando ADO.NET “puro y simple” (y genérico para llenar nuestros reportes) necesitamos la Conexión y para ello una cadena… y no queríamos:

  • Tener una cadena por separado (la tentación y fuerte!)
  • Parsear la cadena de conexión de EF (para obtener la parte que necesitamos)

 

Entonces solo basta una lectura rápida de las propiedades de la conexión en este caso nos valemos de la propiedad StoreConnection del EntityConnection

Textual de MSDN:

(…)Proporciona acceso a la conexión de origen de datos subyacente usada por el objeto EntityConnection.(…)

 

Podríamos entonces tener una propiedad estática que nos ayude:

public static string ConnectionString
{
    get
    {
        using ( AdventureWorksEntities contexto = new AdventureWorksEntities())
        {
            string cadenaCon = 
                    ((System.Data.EntityClient.EntityConnection)contexto.Connection).StoreConnection.ConnectionString;
            return cadenaCon;
            }
    

    }
}
 

 

Enlaces