¿Problemas con los pipelines de compilación de proyectos React/Node? Si la respuesta es sí y esos problemas se vienen produciendo desde el 1 de diciembre… esta puede ser la solución.
Sin categoría
.Net 6 | No encuentro el fichero Startup.cs
Para los desarrolladores de .Net, es habitual usar el archivo Startup.cs, que viene por defecto en ciertas plantillas de proyecto, entre ellas las de proyectos de Web y de Api, para realizar determinadas tareas que deben ejecutarse al inicio, como determinar los orígenes de las variables de entorno/configuración, añadir servicios al contenedor de dependencias, etc. e incluso aprendimos a añadirlo en proyectos de consola donde no viene por defecto. Pero, al crear un proyecto de Web y de Api con .Net 6, podemos apreciar que ya no existe este fichero Startup.cs. ¿Y ahora dónde ponemos nuestra configuración?
React.js | Variables de entorno
Al desarrollar un proyecto siempre es necesario disponer de diferentes entornos para poder desarrollar y testear antes de pasar a producción. Así, es habitual tener entornos de Desarrollo, Pre-Producción y Producción aunque también podemos encontrarnos con escenarios con más (o menos) entornos. Por ello, es necesario disponer de variables de entorno que puedan ser configurables de forma automática a la hora de compilar/ejecutar nuestras aplicaciones react, tales como URLs de Apis, Client Ids, etc.
Error con jQuery UI datepicker dentro de formulario en Safari
Escenario
Hace algunos días me encontré con un problema en Safari al establecer fechas con un datepicker de Metro UI que es el mismo que el que corresponde a jQuery UI datepicker. El problema se producía al seleccionar una fecha que, al realizarse la validación con jQuery.validation decía que era incorrecta al contrario que en el resto de navegadores (Internet Explorer, Microsoft Edge, Google Chrome*, Firefox y Opera). Además, parece que el error se reproducía en Google Chrome para Mac lo que hacía más complicado determinar cuál es el problema. Como se puede apreciar en la imagen, tiene problemas al establecer fechas predefinidas como en el campo «inicio» en el que he puesto la fecha actual (tanto desde el modelo como con JavaScript) y, en el campo «Vencimiento» la fecha seleccionada con el datepicker genera un error de validación «incomprensible»
Solución
La solución es sencilla aunque no me parece del todo correcta y pasa por saltarse la validación de los campos que estén relacionados con el datepicker con una simple instrucción que siempre devolverá «true» cuando se trate de una fecha.
jQuery.validator.methods[«date»] = function (value, element) { return true; }
Tiene algo de sentido si pensamos que la fecha está establecida por el propio datepicker y que no se debe permitir que se inserte una fecha manualmente, cosa que de forma automática ya cumple el datepicker, pero podría darse el caso de que sí que necesitemos realizar algún tipo de validación que nos estaríamos perdiendo por forzar que siempre devuelva «true».
Explicación
Por lo que he investigado, Safari incluye algún tipo de tratamiento para las fechas que nos rompe nuestra validación y que, por lo tanto, nos generará un error de formato. Yendo un poco más allá, parece que en Mac esto mismo se reproduce para Google Chrome, cosa que me parece «inexplicable» cuando sobre Windows funciona correctamente.
¿Conoces alguna solución?
¿Conocéis algún workaround más elegante u óptimo? Abramos el debate pero adelanto que tengo preestablecido el lenguaje en el fichero web.config «es-ES» y en el propio datepicker «es».
ASP.NET MVC | Cómo enviar modelo con JavaScript desde un formulario a una acción
Escenario
Supongamos que tenemos un formulario en una vista de una aplicación web realizada con ASP.MVC y necesitamos enviar los datos, que corresponden a un modelo de la aplicación, a nuestra acción del controlador. ¿Cómo realizamos esta tarea? Seguro que se nos ocurren ideas «liosas» para realizar esta operación pero generalmente optamos por lo más obvio que, además, no es óptimo ni flexible o no aprovechamos las facilidades que nos ofrece el ModelBinding.
Para explicar las posibilidades, quiero exponer las dos opciones que me he encontrado con más regularidad (por orden de veces que lo he visto) antes de exponer la que a mi parecer es la opción más óptima y os explicaré por qué.
Solución NO óptima 1
Lo que más he visto hacer, es lo más costoso y menos flexible que se podría hacer y no es otra solución que cambiar los parámetros de la acción del controlador por los campos del modelo y, en código JavaScript, recoger cada uno de esos campos por separados y mandarlos en los datos de la acción «Ajax». Esto no es en ningún momento óptimo ni bueno aunque funcione porque no es nada flexible ante cambios con lo que si añadimos una nueva propiedad, tendremos que cambiar todo nuestro código para poder enviarla, recibirla y validarla.
Acción del controlador
-
[HttpPost]
-
public JsonResult Create(string brand, string model, …) {
-
try {
-
if (string.IsNullOrEmpty(brand) || string.IsNullOrEmpty(model) || …) return false;
-
var car = new Car {
-
Brand = brand, Model = model, // …
-
};
-
car.Status = «Solicitados»;
-
return Json(true);
-
} catch {
-
return Json(false);
-
}
-
}
Código JavaScript
-
$(‘#btn-sendForm’).click(function() {
-
var car = {
-
prop1: document.getElementById(‘brand’).value(),
-
prop2: document.getElementById(‘model’).value(), // …
-
}
-
$.ajax({
-
url: ‘@Url.Action(«ACTION», «CONTROLLER»)’,
-
type: ‘POST’,
-
data: item,
-
success: function(result) {
-
var modelStatus = $(‘.model-status’);
-
if (result) modelStatus.text(«Estado: Enviado con éxito»);
-
else modelStatus.text(«Estado: Enviado con error. Compruebe que ha rellenado todos los campos»);
-
},
-
error: function(jqXHR, textStatus, error) {
-
$(‘.model-status’).text(«Estado: Error inesperado»);
-
}
-
});
-
});
Solución NO óptima 2
A priori podría parecer que la solución pasaría por dejar el formulario con el parámetro del tipo del modelo y crearnos un objeto en JavaScript con las propiedades necesarias e ir recogiendo los valores uno por uno de los campos del formulario para posteriormente enviarlos en la acción «Ajax» como el código que explico a continuación. Esta opción está muy cerca de la óptima porque recibimos el modelo en la acción y la validación se la delegamos al ModelState, pero aún sigue sin ser flexible ya que, si añadimos un nuevo campo al formulario, tendríamos que añadir esa nueva propiedad al objeto JavaScript para poder enviarlo y, como sabemos, esto siempre puede llevar a olvidos y/o errores.
Acción del controlador
-
[HttpPost]
-
public JsonResult Create(Car car) {
-
try {
-
if (!ModelState.IsValid) return Json(false);
-
car.Status = «Solicitados»;
-
return Json(true);
-
} catch {
-
return Json(false);
-
}
-
}
Código JavaScript
-
$(‘#btn-sendForm’).click(function() {
-
var car = {
-
prop1: document.getElementById(‘brand’).value(),
-
prop2: document.getElementById(‘model’).value(), // …
-
}
-
$.ajax({
-
url: ‘@Url.Action(«ACTION», «CONTROLLER»)’,
-
type: ‘POST’,
-
data: item,
-
success: function(result) {
-
var modelStatus = $(‘.model-status’);
-
if (result) modelStatus.text(«Estado: Enviado con éxito»);
-
else modelStatus.text(«Estado: Enviado con error. Compruebe que ha rellenado todos los campos»);
-
},
-
error: function(jqXHR, textStatus, error) {
-
$(‘.model-status’).text(«Estado: Error inesperado»);
-
}
-
});
-
});
Solución ÓPTIMA
Por último, vamos a ver la solución que a mi parecer es la óptima para estos casos. Lo que haremos, es tener la acción del controlador como en el caso anterior pero variaremos un poco el JavaScript para enviar todo el formulario de golpe. De esta forma, conseguimos que si tenemos que añadir un nuevo campo al formulario, no nos tengamos que preocupar cómo se envía ni cómo se recoge gracias al ModelBinding
Acción del controlador
-
[HttpPost]
-
public JsonResult Create(Car car) {
-
try {
-
if (!ModelState.IsValid) return Json(false);
-
car.Status = «Solicitados»;
-
return Json(true);
-
} catch {
-
return Json(false);
-
}
-
}
Código JavaScript
-
$(‘#btn-sendForm’).click(function() {
-
var formContainer = $(‘#car-form’);
-
$.ajax({
-
url: ‘@Url.Action(«Create», «Car»)’,
-
type: ‘POST’,
-
cache: false,
-
data: formContainer.serialize(),
-
success: function(result) {
-
var modelStatus = $(‘.model-status’);
-
if (result) modelStatus.text(«Estado: Enviado con éxito»);
-
else modelStatus.text(«Estado: Enviado con error. Compruebe que ha rellenado todos los campos»);
-
},
-
error: function(jqXHR, textStatus, error) {
-
$(‘.model-status’).text(«Estado: Error inesperado»);
-
}
-
});
-
});
Como podéis observar, lo que haremos será serializar el formulario completo dentro de la propiedad «data» de la acción «Ajax» con lo que estaremos enviando todos los campos del formulario y, una vez en la acción del controlador, gracias al ModelBinding, el parámetro del modelo, en este caso «Car car» se rellenará de forma automática con todos los valores que procedan, los validamos con el ModelState y hemos acabado. Esto es totalmente flexible a cambios y, por lo tanto, no nos dará dolores de cabeza cuando tengamos que hacer modificaciones en el formulario.
Resumen
Siempre debemos intentar buscar la solución más óptima y flexible para nuestros desarrollos porque en el futuro, cuando tengamos que mantener el código u otro se encargue de esa tarea, nos alegraremos de haber perdido un poco de tiempo en ello.
Podéis descargaros una solución simple de ejemplo desde mi GitHub
Azure Webjobs | Envío de correo con SendGrid
Es bastante común que necesitemos enviar correos electrónicos desde nuestras aplicaciones web para notificar ciertas acciones realizadas por eso, hoy quiero compartir un ejemplo de cómo desarrollar un Azure Webjob que realice el envío de correos por medio de SendGrid que, dado que para los suscriptores de Microsoft Azure dispone de una opción gratuita que permite enviar hasta 25.000 correos al mes, es, desde mi punto de vista, la mejor opción.
Para ilustrar el ejemplo, detallaré paso a paso cómo configurar todo lo necesario para usar SendGrid desde un proyecto de consola que después se podrá publicar como Webjob asociado a una aplicación web (Web App) alojada en Microsoft Azure.
Crear el servicio de SendGrid desde la tienda de Microsoft Azure
En primer lugar debemos acceder a nuestra cuenta de Microsoft Azure y dirigirnos a la tienda de servicios donde buscaremos SendGrid. Una vez lo hayamos localizado, sólo tenemos que agregarlo y rellenar los datos correspondientes a su configuración.
Es muy importante que nos quedemos con el usuario y que recordemos la contraseña porque será lo que nos permita enviar el correo
Añadiendo la referencia a SendGrid en nuestro proyecto
Ahora que ya tenemos creado el servicio de SendGrid, debemos referenciar la API desde nuestro proyecto de consola que previamente habremos creado. Esto lo haremos desde el Administrador de paquetes de Nuget
Crear un correo
Ahora que ya tenemos el servicio y la referencia a la API, será muy sencillo crear y enviar correos tal y como se explica en la documentación de SendGrid
Lo primero que debemos hacer es generar el correo con los parámetros correspondientes tal y como muestro en el siguiente código
private static MailMessage CreateEmail()
{
// Create the email object first, then add the properties.
var message = new MailMessage();
// Add the message properties.
message.From = new MailAddress("santiagoporras@santiagoporras.com");
// Add multiple addresses to the To field.
var recipients = @"Santiago Porras Rodríguez <demo1@gmail.com>,
Santiago Porras Rodríguez <demo2@gmail.com>,
Usuario Demo 1 <demo1@outlook.com>,
Usuario Demo 2 <demo2@outlook.com>";
message.To.Add(recipients);
message.Subject = "Testing the SendGrid Library";
//Add the HTML and Text bodies
var html = "<h1>¡santiagoporras.com próximamente!</h1><p>En breve estará disponible mi sitio web. No dudes en visitarlo</p>";
var text = "¡santiagoporras.com próximamente!n En breve estará disponible mi sitio web. No dudes en visitarlo";
message.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
message.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Html));
return message;
}
Enviar un correo
El envío lo haremos por medio de SMTP mediante un simple código que establece las credenciales con las que estamos dados de alta en el servicio y que os dije que debíais recordar en el paso de creación del servicio.
private static void SendEmail (string sgUsername, string sgPassword, MailMessage message)
{
// Set credentials
var credentials = new NetworkCredential(sgUsername, sgPassword);
// Create SMTP cliente
SmtpClient smtpClient = new SmtpClient("smtp.sendgrid.net", Convert.ToInt32(587));
smtpClient.Credentials = credentials;
// Send email
smtpClient.Send(message);
}
Publicar como Webjob
Ahora debemos proceder a publicar este proyecto como Webjob de nuestra aplicación web tal y como os mostré en este artículo.
Ver estadísticas
Finalmente, podemos entrar en el sitio de estadísticas de SendGrid y ver cuál es el uso que estamos haciendo de este servicio.
Resumen
Como podéis comprobar, es muy sencillo crear el servicio, que nos permite el envío de hasta 25.000 correos de forma gratuita y, mediante su API, poder generarlos y enviarlos a los usuarios de nuestras aplicaciones web y espero que os sirva de ayuda. Podéis descargaros el código desde GitHub
ASP.NET 5 (vNext) | Conectando nuestro sitio ASP.NET 5 beta5+ con Azure Active Directory
Con las últimas actualizaciones Visual Studio y ASP.NET 5, ya es posible crear un sitio conectado a un directorio activo desde la creación de la plantilla del proyecto, cosa que veníamos echando de menos los que ya estábamos haciendo algunas cosas con esta nueva versión de ASP.NET aunque, como podremos observar, es una tarea bastante sencilla una vez la hayamos visto.
Para ilustrarlo, en este artículo haré una introducción sobre cómo crear nuestra aplicación conectada con Azure Active Directory y el código que pone nuestra plantilla para conectarse, hacer login y logout y ver que funciona correctamente publicada como Azure Web App. Podéis descargaros el ejemplo de GitHub.
Creando el proyecto
Lo primero es crear un proyecto ASP.NET 5 usando la plantilla de Visual Studio como se ve en la imagen y para ir ahorrando tiempo, marcamos la casilla de «Alojar en Azure» en una Web App con lo que directamente podremos publicar nuestro sitio web y hacer pruebas online.
Para conectar con el directorio activo, seleccionamos la opción «Cambiar autenticación» y realizamos los siguientes pasos:
- Marcar la opción «Cuentas de trabajo o estudiante»
- Seleccionar el tipo de Directorio Activo con el que vamos a conectar, que en nuestro ejemplo será «Cloud – Single Organization»
- Indicar el dominio de nuestro directorio activo, en este caso XXXXX.onmicrosoft.com
- Si queremos hacer operaciones de lectura de datos del directorio activo, debemos marcar la opción «Leer datos del directorio»
- Aceptar
Desgranando el código
Al crear el proyecto directamente conectado con Azure Active Directory, automáticamente se ha generado código que hace que todo funcione pero debemos saber qué es y cómo funciona, así que vamos a ver qué se ha hecho.
Startup.cs
Abrimos el fichero Startup.cs que se encuentra en la raíz del proyecto y vemos código generado automáticamente en dos de los métodos de este fichero.
ConfigureServices(…)
Aquí podemos apreciar que se ha añadido código que nos permite la autenticación usando las cookies y después se configurar el acceso al directorio activo leyendo parámetros de configuración que en la creación del proyecto se generaron automáticamente en la Web App. Si no quisiéramos estos parámetros, tendríamos que configurarlos en el fichero config.json que se encuentra también en la raíz del proyecto.
-
services.Configure < CookieAuthenticationOptions > (options => {
-
options.AutomaticAuthentication = true;
-
});
-
services.Configure < OpenIdConnectAuthenticationOptions > (options => {
-
options.AutomaticAuthentication = true;
-
options.ClientId = Configuration[«Authentication:AzureAd:ClientId»];
-
options.Authority = Configuration[«Authentication:AzureAd:AADInstance»] + Configuration[«Authentication:AzureAd:TenantId»];
-
options.PostLogoutRedirectUri = Configuration[«Authentication:AzureAd:PostLogoutRedirectUri»];
-
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
-
});
Configure
Vemos que en este método se ha añadido la inicialización de OpenId con la siguiente instrucción que establece el middleware de OpenId como el sistema encargado de la autenticación contra Azure Active Directory.
-
// Add OpenIdConnect middleware so you can login using Azure AD.
-
app.UseOpenIdConnectAuthentication();
Como se puede observar, es todo muy sencillo ya que sólo hay que establecer los parámetros de conexión con nuestro Azure Active Directory e inicializar el middleware.
AccountController.cs
Dentro de este controlador debe ir el código que interactúe con el usuario para realizar las tareas de autenticación que, en este caso, dado que se trata de un directorio activo, sólo incluirán el Login y el Logout. Por ello, de una forma muy sencilla, se establece que el login se realiza mediante el middleware de OpenId con una simple instrucción donde además se le puede especificar la Url de retorno que aconsejo modificar para que vuelva siempre a la página desde la que el usuario solicita la autenticación.
Como se puede observar, no hay nada muy complejo dado que de todo ello se encarga el middleware y sólo tenemos que indicar los parámetros y el comportamiento que deseamos.
Publicando en Azure
Cuando se haya creado el proyecto, ya estará preparado para publicar en Azure ya que, durante el proceso se ha creado la correspondiente Web App, con lo que sólo tendremos que hacer click con el botón derecho sobre el nombre del proyecto, y seleccionar «Publicar».
Habrá que configurar correctamente los parámetros de la publicación, seleccionando la Web App correspondiente y, finalmente estableciendo las propiedades adecuadas para el directorio activo tal y como muestro en la imagen a continuación. Notad que aquí ya no es necesario establecer el directorio activo porque se ha generado de forma automática ese parámetro en la Web App.
Probando la aplicación
Finalmente, podemos probar la aplicación y comprobar cómo se nos solicita aprobar el acceso a nuestra cuenta de la aplicación asociada al directorio activo.
Resumen
Hemos visto lo sencillo que es conectarse a Azure Active Directory con la plantilla del proyecto de ASP.NET 5 beta5 pero, además, viendo el código también resultará muy sencillo lograrlo aunque no hayamos partido de esa plantilla ya que sólo tenemos que establecer los parámetros y determinar el comportamiento del middleware de OpenId.
Espero que os haya sido de utilidad y que aprovechéis al máximo las capacidades de ASP.NET 5 que será el nuevo estándar propuesto por Microsoft cuando vea la luz definitiva dentro de muy poco.
Enjoy coding!!
TLP Innova | Un año más en el mayor evento tecnológico de Canarias
Ayer se abrieron las puertas de la zona TLP Innova dentro de Tenerife Lan Party pero hoy comienza mi participación con TenerifeDev apoyando a los ponentes que hemos invitado a ilustrarnos y formarnos sobre algunas de las nuevas tecnologías de Microsoft.
Hoy jueves tendremos un taller sobre Xamarin.Forms impartido por el gran Josué Yeray Microsoft MVP Windows Platform Development y otro taller que impartirá Javier Suárez también Microsoft MVP Windows Platform Development.
10:00 – 13:00 | Taller: Xamarin.Forms, un código para unirlos a todos!
16:00 – 19:00 | Taller: Desarrolla para todos los dispositivos Microsoft con Windows 10
Mañana viernes, tendrá lugar el grueso de nuestra participación en esta edición de 2015 con 10 sesiones técnicas en las que participaré hablando de desarrollo web con ASP.NET y Visual Studio, así como el futuro que se nos viene encima de la mano de Microsoft. Entretanto, otros ponentes, de los que la mayor parte ha venido desde la península a este evento, hablarán sobre Movilidad, Marketing Mobile, Mobile Engagement, Azure, Machine Learning y Programación de Gadgets. No os podéis perder esta ocasión única de conocer a estos ponentes de talla internacional y lo que os pueden contar.
Ni qué decir que será una oportunidad inigualable para hacer «networking» con los ponentes y con el representante de Microsoft DX, Alejandro Campos Magencio, así que… preparad vuestras preguntas y no faltéis!!!
NOTA: No olvidéis registraros gratuitamente desde la web de TLP Innova http://tlp-tenerife.com/tlpinnova/agenda/mes/?tribe-bar-date=2015-07-13
GAPAND 2015 | Disfrutar de Andorra a ritmo de tecnología
El pasado 4 de julio estuve en Andorra para disfrutar de GAPAND 2015 donde tuve la oportunidad de participar como ponente junto a Adrián Díaz y compartir cartel con todo un elenco de ponentes de nivel «god» (todos ellos).
Ya el viaje a Andorra prometía con un viaje en coche junto a Adrián, Josué Yeray e Hilda donde no faltaron las anécdotas de las que se cuentan a los nietos. Finalmente pudimos llegar a nuestro destino preparados para lo que nos deparaba una apasionante jornada en la Universidad de Andorra con 3 tracks en paralelo y diversos talleres gracias a la GRAN ORGANIZACIÓN de Andorra_dot_net con LLUIS FRANCO a la cabeza (Nos quitamos el sombrero ante Lluis, exitazo!)
Adrián y yo teníamos una dura prueba a la que enfrentarnos ya que hablábamos tras Josue Yeray (Showman king) y antes de Bruno Capuano (Showman god), así que no podíamos dejar pasar la ocasión de ponernos el mono de Chinos mayores del reino y mostrar un completo repertorio de tecnologías Microsoft para escenificar nuestra demo de Machine Learning y Project Oxford. Por ello, montamos un sitio web con ASP.NET MVC5 alojado en una Web App de Azure, con tres WebJobs que consultaban y procesaban la información que alojamos en, cómo no, SharePoint Online de Office365. Aquí podéis ver las slides que usamos.
Finalmente, tras el evento disfrutamos de unas horas de networking muy gratificantes que, como siempre, nos unen y acercan aunque la distancia entre nuestras residencias sea grande.
CEUS by Iberian SharePoint Conference 2015, rompiendo registros
Esta edición de CEUS by Iberian SharePoint Conference 2015 estaba marcada por la convergencia entre los dos mayores eventos de SharePoint en españa, CEUS que incluía la parte más orientada al negocio e Iberian SharePoint Conference que trataba la parte más técnica. El resultado ha sido un gran evento de dos días en el que rompimos todas las previsiones de asistencia y pudimos conocer todos los aspectos de SharePoint y de las tecnologías con las que se relaciona, Azure, Lync, Visual Studio, SQL Server, ALM,…
El primer día tuvieron lugar las keynotes a cargo de profesionales de Microsoft y los talleres técnicos, 6 en total, de los cuáles tuve el placer de impartir uno para poner mi granito de arena mostrando a un grupo de más personas de las previstas cómo aplicar Branding en SharePoint mediante un caso de uso con SharePoint Online en Office365. El resto de compañeros también tuvo gran éxito llenando sus salas y consiguiendo una alta valoración por parte de sus asistentes.
El segundo día, fue el más fuerte al tener 7 tracks en paralelo en los que participé en una mesa redonda de discusión sobre movilidad en SharePoint 2013 junto a Rubén Toribio primero y con mi sesión de Modern Branding en SharePoint 2013 después y de las que saqué la impresión de que la gente verdaderamente estaba aprovechando el evento.
Finalmente y como siempre acostumbramos allá donde vamos, cerramos el evento con premios, sorpresas con la participación de los últimos valientes que aguantaron hasta el final.
Aquí podéis encontrar las slides de mi sesión sobre Modern Branding en SharePoint 2013
Espero que os haya gustado a los que pudisteis asistir y a los que no, el próximo año una nueva oportunidad J
Enjoy coding!