Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
Mostrando entradas con la etiqueta asp.net. Mostrar todas las entradas
Mostrando entradas con la etiqueta asp.net. Mostrar todas las entradas
miércoles, 3 de diciembre de 2014
Aunque aún en beta e inmersa en un intenso proceso de desarrollo, la próxima versión de ASP.NET MVC está tomando forma en los hornos de Microsoft, y, sin ser definitivas, ya se pueden ver cuáles serán las novedades principales que la acompañarán.

En futuros posts iremos entrando en mayor detalle, pero de momento vamos a echar un vistazo desde una cierta distancia para tener la idea general sobre dónde estamos y la evolución que vamos a encontrar en las nuevas versiones de tecnologías y plataformas, de forma que podamos ver en qué nos afectará como desarrolladores y, en definitiva, para qué tenemos que irnos preparando.
Disclaimer: estamos aún en una fase en la que algunas cosas pueden cambiar y aún no existe información exhaustiva de muchos detalles, por lo que pueden existir ausencias o imprecisiones. Pero bueno, digo yo que el grueso será más o menos correcto ;-)

martes, 22 de julio de 2014
DebugHay veces que desde Javascript nos interesa ejecutar un código u otro en función de si la ejecución se está produciendo en un servidor de desarrollo o en uno de producción. Por ejemplo, en el primer caso suele ser interesante disponer de logs o herramientas de ayuda a la depuración, mientras que en el segundo lo normal es que queramos introducir código más eficiente y sin este tipo de condimentos.

En este post vamos a ver algunas técnicas muy básicas que nos permitirán ejecutar un código u otro en el lado cliente de aplicaciones ASP.NET MVC (o ASP.NET en general) en función del modo de compilación.
martes, 10 de junio de 2014
Microsoft ASP.NETHay muchos escenarios, y relativamente habituales, en los que es interesante lanzar una tarea desatendida, en segundo plano, desde una aplicación ASP.NET: manipulación de archivos, envío de mensajes, acceso a recursos externos costosos, procesos de colas, generación de archivos, etc.

En general, es un enfoque que puede interesarnos siempre que se trate de realizar un trabajo pesado, que no requiera intervención alguna por parte del usuario ni siquiera para darle feedback del progreso o terminación, y que pueda ejecutarse de forma independiente a las peticiones HTTP que acceden a la aplicación.
miércoles, 3 de abril de 2013
ASP.NETLa nueva versión de System.Web.Optimization traerá (aún está en beta) algunas novedades interesantes al sistema de bundling que se incluye de serie en los proyectos ASP.NET MVC y se distribuye a través de Nuget en el paquete Microsoft.AspNet.Web.Optimization.

En particular, vamos a centrarnos en una característica muy práctica si queremos utilizar una Content Delivery Network (CDN) externa (como la de Microsoft, Google o incluso una propia) para delegar a ella la carga de bibliotecas de script comunes, pero queremos a la vez proporcionar una alternativa local por si acaso ésta fallase debido a cualquier motivo.
martes, 5 de marzo de 2013
Anónimo
Venga, lo confieso: yo también he generado desde mis aplicaciones contenidos HTML y los he enviado al cliente en un archivo con extensión XLS, incluso modificando el content-type, para que pareciera un documento de hoja de cálculo. Durante años. Y también le he dicho a mis clientes que el molesto mensaje que aparece al abrirlo desde Excel, el que indica que el contenido del archivo no coincide con la extensión del mismo, es algo normal.

Pero esto se acabó desde que descubrí ClosedXML, un magnífico componente para .NET basado en el estándar OpenXML que permite la generación de archivos Excel “de verdad”, con formato, estilos, fórmulas, rangos, filtros, y casi todo lo que se nos pueda ocurrir.
martes, 22 de enero de 2013
ASP.NET MVCHace poco veíamos que el nuevo sistema de routing usado por proyectos MVC 4 permitía una cierta configuración del formato de URL generadas por la aplicación al usar helpers como Url.Action() o Html.ActionLink(), y cómo usando una simple línea de código podíamos hacer que las rutas se generaran usando sólo minúsculas.
martes, 18 de septiembre de 2012
Seguro que alguna vez habéis notado que al generar URLs hacia acciones de una aplicación MVC usando helpers como Url.Action() o Html.ActionLink(), éstas son generadas usando mayúsculas y minúsculas según hubiéramos indicado en los parámetros de las llamadas:

Helper URL generada
@Url.Action("index", "home")/home/index
@Url.Action("List","Products", new{ Category="PC" }) /Products/List?Category=PC
@Url.Action("VIEWALL", "PRODUCTS") /PRODUCTS/VIEWALL

Como podemos ver, la URL resultante queda a criterio del desarrollador o, lo que es peor, al puro azar. A veces incluso no es algo que podamos elegir fácilmente, puesto que son generadas por otros componentes como T4MVC. Y no sé si desde el punto de vista del SEO tendrá su impacto, pero desde luego el ofrecer estas direcciones sin un aspecto unificado no da buena impresión.

En versiones anteriores a ASP.NET 4.5, esto podíamos solucionarlo creando helpers, o rutas personalizadas que, heredando de Route, realizaran esta conversión a minúsculas. Sin embargo, ahora disponemos de un mecanismo más cómodo para forzar que las URLs generadas sean normalizadas a minúsculas, así:
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.LowercaseUrls = true;
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        [...]
    }
}

Un detalle, sin duda interesante, para tener en cuenta en nuestros desarrollos.

Publicado en: Variable not found.
martes, 17 de julio de 2012
ASP.NET MVCHace poco hablábamos de la creación de Display Modes personalizados en ASP.NET MVC 4, y veíamos cómo hacerlo usando la clase DefaultDisplayMode proporcionada por el framework, con la que podíamos cubrir la mayoría de necesidades comunes.

Así, veíamos cómo el siguiente código era suficiente para registrar un nuevo Display Mode llamado “iPhone”, que sería activado cuando en el identificador del agente de usuario (encabezado user-agent de la petición) incluyera el texto “iPhone”:
DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
{
    ContextCondition = (context => context.Request.UserAgent.IndexOf
        ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
});
 
imageHecho esto, ya podíamos definir vistas alternativas a las habituales específicas para este dispositivo, cuyos nombres de archivo acabarían siempre en “.iphone.cshtml”. Observad que estamos usando la clase DefaultDisplayMode, a la que estamos facilitando la condición que debe cumplirse para que se active este Display mode.

Sin embargo, si pensamos crear muchas vistas específicas para dispositivos, podríamos encontrarnos con un maremagnum de archivos como el que veis en la captura de pantalla adjunta.

Obviamente, no es una situación fácilmente manejable, así que ¿por qué no cambiar la forma de nombrar los archivos dependiendo del Display Mode actual? Pues dicho y hecho, vamos a conseguir que cada dispositivo disponga de una carpeta específica para guardar sus vistas.

Heredando de DefaultDisplayMode

Si analizamos el código fuente de la clase DefaultDisplayMode, veremos que hay varios miembros virtuales que podemos sobrescribir para tomar el control, y uno de ellos es el método TransformPath(), encargado de transformar la ruta hacia el archivo físico donde está definida la vista teniendo en cuenta el nombre del Display Mode actual.

El código por defecto del método es el siguiente:
    protected virtual string TransformPath(string virtualPath, string suffix)
    {
      if (string.IsNullOrEmpty(suffix))
        return virtualPath;
      string extension = Path.GetExtension(virtualPath);
      return Path.ChangeExtension(virtualPath, suffix + extension);
    }
O sea, que se reemplaza la extensión del archivo, normalmente “.cshtml” por el resultado de concatenar el sufijo suministrado (el nombre del Display Mode) a dicha extensión. Por esta razón, el comportamiento por defecto del framework es utilizar construcciones como “nombrevista.iphone.cshtml”.

Si, como es el caso, queremos cambiar la ruta donde van a intentar localizarse las vistas, lo único que tenemos que hacer es crear una clase descendiente de DefaultDisplayMode, sobrescribir la forma de “montar” la ruta hacia la vista, y utilizar esta nueva clase para registrar los modos de visualización que nos interesen. Una posible implementación podría ser la siguiente:
    public class OrganizedDisplayMode: DefaultDisplayMode
    {
        public OrganizedDisplayMode(string displayModeId): base(displayModeId)
        {
        }
 
        protected override string TransformPath(string virtualPath, string suffix)
        {
            if (string.IsNullOrEmpty(suffix))
                return virtualPath;
 
            // Transforms /index.cshtml --> /suffix/index.cshtml
            int lastSeparator = virtualPath.LastIndexOf('/');
            virtualPath = virtualPath.Substring(0, lastSeparator) + 
                            "/" + suffix + 
                            virtualPath.Substring(lastSeparator);
            return virtualPath;
        }
    }
Vistas estructuradas por carpetasY en la inicialización de la aplicación ya podríamos registrar este Display Mode y asociarlo a la condición que esperamos que cumpla la petición:
  DisplayModeProvider.Instance.Modes.Insert(0,
     new OrganizedDisplayMode("iPhone") 
     {
        ContextCondition = 
           context => context.Request.UserAgent.Contains("iPhone")
     });
De esta forma, ya podemos organizar las vistas como podéis observar en la captura de pantalla de la derecha: cada dispositivo (o Display Mode registrado) dispondría de una carpeta en cuyo interior se encontrarían las vistas específicas para el mismo.

Y observad que su funcionamiento no se limita a las vistas asociadas a controladores concretos, la solución también sería válida en vistas compartidas (Shared) y con aquellas incluidas en áreas :-)

Publicado en Variable not found.
lunes, 25 de junio de 2012
AUGES: ASP.NET User Group EspañaEl próximo miércoles 27 de junio de 2012, de 19:00 a 21:00 (horario peninsular español), tenemos un interesante evento en AUGES que, sin duda, nos sacará de dudas a los muchos desarrolladores ASP.NET que lo más que sabemos de SharePoint es que existe ;-)

El cartel oficial del evento es el siguiente:

SHAREPOINT PARA APLICACIONES EN ASP.NET DESDE CERO

image¿Eres programador ASP.NET y no sabes nada acerca de SharePoint? No te preocupes, en AUGES hemos preparado este evento para que aprendas desde cero sobre está plataforma de Microsoft que está pegando muy fuerte y que ya usan millones de clientes en todo el mundo. Veremos las bases de la plataforma, los servicios, buenas practicas, el IDE de desarrollo… No puedes perdértelo!!!
Ponente
Edin Kapic que es Key Consultant en Pasiona consulting, con más de 6 años de experiencia en Sharepoint, ponente en la European Sharepoint Conference de Berlín y miembro de Grupo de Usuarios de SharePoint de Cataluña – SUG.CAT.

Os recuerdo que se trata de un Webcast, o sea, que podéis asistir a este evento desde vuestro sillón favorito, acompañados de una buena cerveza y un saco de palomitas. Y por supuesto, es totalmente gratuito.

Lo único que debéis hacer para poder asistir es registraros:
Esperamos veros por allí ;-)

Publicado en Variable not found.
martes, 12 de junio de 2012
ASP.NET MVCSabemos que las editor y display templates son magníficas herramientas de productividad que nos facilitan la creación de potentes interfaces de usuario. Resumidamente, son las vistas creadas específicamente para generar el interfaz de edición o de visualización de un objeto concreto que son almacenadas en las carpetas EditorTemplates y DisplayTemplates, dentro de /Views/Shared.

Lo más habitual es utilizarlas para crear editores o visualizadores para tipos de datos concretos, en cuyo caso las vistas disponibles en las carpetas citadas anteriormente se llaman igual que el tipo de dato a editar o visualizar.

Por ejemplo, si tenemos una vista llamada int.cshtml en la carpeta /Views/Shared/EditorTemplates , será la utilizada como editor de propiedades de tipo entero. Algo parecido utilizamos por aquí, hace ya bastante tiempo, para integrar jQuery datepicker en nuestras aplicaciones.

También es habitual encontrar en estas carpetas plantillas vinculadas a propiedades u objetos de forma directa mediante el atributo [UIHint] (como en este post), mediante el cual se indica explícitamente qué plantilla debe utilizarse:
    [DisplayName("Long description")]
    [StringLength(140), Required]
    [UIHint("LimitedTextArea")]  // Use the template "LimitedTextArea.cshtml"
    public string Description { get; set; } 

Y otra alternativa, aunque quizás algo menos utilizada, es la posibilidad de indicar la plantilla a utilizar en la misma llamada al helper EditorFor() o DisplayFor() que provoca su renderizado:
    @Html.EditorFor(m=>m.Description, "LimitedTextArea")
Sin embargo, hay una posibilidad adicional, que curiosamente no es demasiado conocida, consistente en utilizar el atributo DataTypeAttribute para indicar la plantilla de edición o visualización a emplear para la propiedad a la que se aplica.

El funcionamiento es trivial: decoramos las propiedades con [DataType] suministrándole como parámetro el tipo de información que va a contener, y el sistema intentará localizar una plantilla con ese nombre.  Veamos un ejemplo:
    [DataType(DataType.EmailAddress)] 
    public string Email { get; set; }
 
    [DataType(DataType.Time)]
    public DateTime StartDate { get; set; }
 
    [DataType(DataType.Html)]
    public string LongDescription { get; set; }
En el momento de renderizar un editor (o un display) template para la primera propiedad, el sistema utilizará, si existe, el archivo EmailAddress.cshtml; en caso de no existir, intentará localizar un string.cshtml, y si tampoco lo encuentra generará un editor por defecto. En el segundo caso se realizará la misma operación con Time.cshtml, y el último de ellos usará la plantilla Html.cshtml como primera opción.

Podemos utilizar como nombre de plantilla todos los valores que encontramos en la enumeración DataType:
  • DateTime
  • Date
  • Time
  • Duration
  • PhoneNumber
  • Currency
  • Text
  • Html
  • MultilineText
  • EmailAddress
  • Password
  • Url
  • ImageUrl
Publicado en Variable not found.
martes, 5 de junio de 2012
ASP.NET MVC¡Bueno, pues parece que esto se mueve! Hace unos días ha sido publicada la Release Candidate de ASP.NET MVC 4 coincidiendo con la liberación de Windows 8 Release Preview y Visual Studio 2012 Release Candidate (que, de hecho, incluye de serie MVC 4 RC).

Y como viene siendo costumbre, vamos a dar un repaso a todo lo que encontramos en esta nueva entrega, que presumiblemente será la última (bueno, o penúltima, nunca se sabe) antes de la versión definitiva. Eso sí, para no hacer el post demasiado largo nos centraremos exclusivamente en los cambios más destacables y visibles que se han introducido respecto a la versión beta.
miércoles, 30 de mayo de 2012
ASP.NET MVCComo venimos comentando desde la aparición de la preview de MVC 4, el Display Mode o modo de visualización es un nuevo mecanismo que permite la creación de aplicaciones capaces de retornar vistas específicas según las características y capacidades del cliente conectado u otros parámetros del entorno de la petición.

Esto tiene mucha utilidad directa, por ejemplo, a la hora de construir aplicaciones web que adapten su interfaz en función de si el cliente es un dispositivo móvil o desktop, pero como casi siembre ocurre en el framework, se trata de un mecanismo muy extensible y fácil de adaptar a otras necesidades.
martes, 8 de mayo de 2012
ASP.NETImaginad que tenemos un sistema web de cierto volumen y decidimos estructurarlo en aplicaciones independientes, cada una publicada en un subdominio propio:
  • www.acme.org, que sería el sitio principal.
  • crm.acme.org, con el sistema CRM de la empresa.
  • erp.acme.org, con un sistema de gestión empresarial.
  • administration.acme.org con las herramientas de administración del sistema.
  • etc.
Desde un punto de vista operativo, es probable que nos interese suministrar un mecanismo de autenticación de usuarios compartido entre todas estas aplicaciones, de forma que el usuario, una vez identificado, pueda pasar de una a otra sin necesidad de introducir de nuevo sus credenciales.

No es una tarea complicada en ASP.NET, aunque hay que hacer algunos ajustillos para que todo funcione correctamente. Veámoslos.
martes, 24 de abril de 2012
ASP.NET MVCHace poco comentamos algunos detalles sobre las novedades que incluirá Razor 2, la versión que será incluida en ASP.NET MVC 4, y siguen apareciendo más novedades destinadas a mejorar la calidad del código y nuestra productividad al crear las vistas MVC o Web Pages.

En este post vamos a ver otros comportamientos de Razor en distintos escenarios.
miércoles, 11 de abril de 2012
Hace unos meses ya estuvimos comentando el interesante paquete System.Web.Optimizations que se distribuía con la developer preview de MVC 4, aunque también decíamos que este paquete era igualmente descargable a través de Nuget, y esto hacía posible su uso con MVC 3 o incluso con WebForms.
miércoles, 28 de marzo de 2012
ASP.NET MVCUna novedad que descubro en los tutoriales preliminares de la segunda versión de WebPages, y que por tanto tendremos disponible en las futuras versiones de WebMatrix y ASP.NET MVC 4, es la posibilidad de registrar los scripts y estilos que necesitan nuestros componentes visuales (sean layouts, vistas completas, parciales o helpers), centralizando su carga y evitando duplicidades.
martes, 20 de marzo de 2012
Como vengo comentando desde hace un tiempo, SignalR es un framework realmente impresionante y aporta unas posibilidades enormes en prácticamente cualquier tipo de aplicación. Ya hemos visto qué es y las bases en las que se sustenta, y también hemos visto algunos ejemplos de uso utilizando conexiones persistentes (aquí y aquí), que es el enfoque de menor nivel disponible a la hora de desarrollar servicios basados en esta plataforma.

En este post ascenderemos a un nivel de abstracción mucho mayor que el proporcionado por las conexiones persistentes y veremos cómo utilizar los Hubs, otro mecanismo proporcionado por SignalR que nos permitirá lograr una integración increíble entre el código cliente y de servidor, y hará aún más sencilla la implementación de este tipo de servicios.
martes, 13 de marzo de 2012
Qué divertidoLo divertido de escribir sobre productos que están todavía en fase de desarrollo es que cambian... y a veces, ¡de qué forma! Pues esto ha ocurrido con SignalR: recientemente se publicó la revisión 0.4 y bastantes cosas de las tratadas en el post anterior de la serie ha quedado en agua de borrajas. En fin, estaba avisado, así que mucho no puedo quejarme ;-)

Por tanto, esta tercera entrega de la serie vamos a dedicarla (otra vez ;-)) a las conexiones persistentes, veremos qué cosas han cambiado con la llegada de la revisión 0.4, y desarrollaremos un nuevo ejemplo que ilustre las novedades que podemos encontrar a la hora de trabajar a bajo nivel con SignalR.
martes, 14 de febrero de 2012
ASP.NET MVCComo sabemos, los helpers como Url.Action() y Html.ActionLink() son capaces de generar URLs hacia acciones partiendo de la información disponible en la tabla de rutas y de los parámetros que les suministramos.

Por ejemplo, el siguiente código genera un enlace hacia la acción Edit del controlador Friends, suministrándole el valor 3 al parámetro de ruta id:
@Html.ActionLink("Edit friend", "Edit", "Friends", new {id = 3}, null)
Sin embargo, estos helpers no nos ayudan demasiado cuando desconocemos a priori el valor de los parámetros. De hecho, si en lugar del 3 que hemos suministrado quisiéramos enviar un valor obtenido a través de scripting tendríamos un problema, puesto que el bloque de código anterior se ejecuta en servidor y el enlace sería generado antes incluso de ejecutarse el script para obtener el valor a enviar.

Esta es una pregunta que suelo ver muy a menudo en comunidades y foros (como el de ASP.NET MVC en MSDN) y me han realizado más de una vez en el curso de ASP.NET MVC 3 que tutorizo en CampusMVP, así que vamos a ver un par de enfoques para enfrentarnos a este escenario, bastante frecuente al trabajar en sistemas web y, sobre todo, en aquellos muy basados en scripting y Ajax.