asp.net

[ASP.NET] Subiendo archivos a un blob storage con RadCloudUpload

Posted on Actualizado enn

Hola a todos, actualmente es muy común que en las aplicaciones Web el cargue de archivos se haga a un storage en la nube, y generalmente es necesario crear todo el código para implementar dicha funcionalidad, sin embargo Telerik nos hace la vida más sencilla ya que en su gama de controles ahora disponemos de RadCloudUpload, control que en esencia nos permite realizar la subida de un archivo a un storage en la nube (Azure, Amazon S3 y Telerik Backend Services).

Pues bien, su implementación es bastante sencilla y la vamos a realizarm para cargar archivos a un blob storage de Microsoft Azure, una vez añadimos el control, como es costumbre tenemos algunas opciones para comenzar su parametrización como:

  • Tamaño del archivo
  • Proveedor del storage
  • Extensiones permitidas
  • Posibilidad de subir múltiples archivos
  • Skin

cloudupload1

Como hemos seleccionado en el proveedor Azure, se habilita un wizard para ingresar los datos del storage:

cloudupload3

No olvides agregar por Nuget el paquete Windows Azure Storage:

cloudupload2

Y listo, ya es solo probar, una vista previa del control funcionando:

cloudupload4

Si luego requieren cambiar los datos del storage, todos los datos se han replicado en el web.config:

<telerik.web.ui>
	<radCloudUpload>
	  <storageProviders>
		<add name="Azure" type="Telerik.Web.UI.AzureProvider" 
			 accountKey="681o+9PweN+2k....." 
			 accountName="demomvcsignalr" 
			 blobContainer="democloudupload" 
			 ensureContainer="true" 
			 uncommitedFilesExpirationPeriod="1" 
			 defaultEndpointsProtocol="" />
	  </storageProviders>
	</radCloudUpload>
</telerik.web.ui>

Saludos!

[ASP.NET] Integrando ASP.NET con Telerik ASP.NET AJAX

Posted on Actualizado enn

Hola a todos, muchos sabrán de mi gusto por los controles y herramientas de Telerik, así que quiero comenzar a compartir regularmente post sobre sus productos. En esta ocasión vamos a ver cómo es de sencillo integrar los controles ASP.NET AJAX en una aplicación nueva de tipo Web Forms, tarea que Telerik nos pone bastante fácil (con un wizard :)).

Una vez ya tienes instalados los controles, y te recomiendo utilices el Telerik Control Panel (luego hablamos hablaremos de él), tenemos un template que nos va a llevar paso a paso:

Primero seleccionamos el template Telerik Web Application:

telerik 1

Luego se abre un wizard en donde podemos configurar algunas partes importantes del proyecto, iniciando con el tema a utilizar y si se desea agregar una referencia de los assemblies a la solución:

telerik 2

En el siguiente paso es posible establecer algunas opciones, como por ejemplo si usar CDN entre otras:

telerik 3

Luego si queremos tener soporte para jQuery y templates:

telerik 4

Y finalmente si queremos usar Telerik Data Access, el ORM de Telerik (que la verdad va bastante bien):

telerik 5

Y listo, ya solo queda usar y aprovechar la potencia de los controles!

Saludos!

[ASP.NET MVC] Soporte para enumeraciones en ASP.NET MVC 5.1

Posted on Actualizado enn

Hola a todos, uno de las características que le hacia falta a ASP.NET MVC era el soporte nativo para trabajar con enumeraciones, sin embargo ya en la versión 5.1 (ojo que todavía es RC) ya se dispone de un helper dedicado para trabajar con enumeraciones, así que vamos a verlo (Revisa más características en este link).

Lo primero que debes hacer es descargar e instalar el update Visual Studio 2013 Update 1 RC, una vez instalado creamos un nuevo proyecto y añadimos el paquete Microsoft ASP.NET MVC, como todavía no es oficial asegúrate de seleccionar Include Prerelease:

enums

O bien por el Package Manager Console con: Install-Package Microsoft.AspNet.Mvc -Version 5.1.0-rc1 –Pre

Ahora, vamos a crear una enumeración que va a manejar los tipos de clientes:

public enum ClientType
{ 
	Free = 0,
	VIP = 1,
	Gold = 2,
	Platinum = 3
}

Y un modelo:

public class Client
{
	public int ClientId { get; set; }

	public string Name { get; set; }

	public ClientType ClientType { get; set; }
}

Ahora creamos un controlador, para el ejemplo solo voy a crear las acciones para crear (no te fijes si crea o no, porque no lo hace):

public class ClientController : Controller
{
	// GET: /Client/Create
	public ActionResult Create()
	{
		return View();
	}

	 // POST: /Client/Create
	[HttpPost]
	public ActionResult Create(Client client)
	{
		ViewBag.type = client.ClientType;
		return View();
	} 
}

Y finalmente la vista:

@model Enums.Models.Client

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Client</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ClientType, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EnumDropDownListFor(model => model.ClientType)
                @Html.ValidationMessageFor(model => model.ClientType)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Ahora al probar la aplicación, se genera correctamente una lista con las opciones de la enumeración:

client

Y si damos click en Create y revisamos lo que pasa en la acción Create, observamos que el valor seleccionado se mapea correctamente con la propiedad del modelo:

modelo

Espero el post les sea interesante, saludos!

[ASP.NET Web API] Web API VIII – Trabajando con los ActionName

Posted on Actualizado enn

Hola a todos, volviendo con la serie sobre ASP.NET Web API, en esta oportunidad quiero mostrarles como podemos personalizar el nombre de las acciones y además poder tener dos o más métodos que trabajen con el mismo verbo HTTP y una misma firma.

Para personalizar el nombre de las acciones, es necesario decorar cada acción con el atributo ActionName y especificar el nombre que deseamos utilizar:

[ActionName("nombre_de_la_acción")]

Para nuestro ejemplo vamos a crear una nueva acción con el nombre GetPersonByOtherId(Int32 id), dicha acción obedece al verbo Http Get y tiene la misma firma que la acción GetPerson, adicionalmente decoramos las acciones con el atributo ActionName y le asignamos un nombre (si en este caso la lógica de cada acción es la misma):

[ActionName("getbyid")]
public Person GetPerson(Int32 id)
{
	Person person = db.Person.Find(id);
	if (person == null)
	{
	   throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
	}

	return person;
}

[ActionName("getbyotherid")]
public Person GetPersonByOtherId(Int32 id)
{
	Person person = db.Person.Find(id);
	if (person == null)
	{
		throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
	}

	return person;
}

Adicionalmente agregamos un nuevo elemento en nuestro HTML:

<input id="btnSearch2" type="button" value="Search by Other Id" data-bind="click:getPersonByOtherId" />

Ahora modificamos el ViewModel y agregamos la función getPersonById, así como en la función getPersonById hacemos un pequeño cambio a la url que se esta llamando, en este caso agregando el nombre de la acción:

...
self.getPersonById= function () {
	var url = '/api/person/getbyid/' + self.id();
	$.getJSON(url)
		.done(function (data) {
			self.name(data.Name);
			self.lastname(data.LastName);
			self.twitter(data.Twitter);
		})
		.fail(function (erro) {
			self.clearForm();
	});
},

self.getPersonByOtherId = function () {
	var url = '/api/person/getbyotherid/' + self.id();
	$.getJSON(url)
		.done(function (data) {
			self.name(data.Name);
			self.lastname(data.LastName);
			self.twitter(data.Twitter);
		})
		.fail(function (erro) {
			self.clearForm();
		});
},
...

Luego es necesario agregar una nueva ruta en la tabla de routing, en este caso en la clase WebApiConfig:

config.Routes.MapHttpRoute(
	name: "ApiByOtherId",
	routeTemplate: "api/{controller}/{action}/{id}",
	defaults: new { id = RouteParameter.Optional }
);

Y ahora si ejecutamos y probamos podemos ver como en efecto los ActionName funcionan correctamente:

ActionName

Espero el post les haya gustado, hasta el próximo!

Descarga el ejemplo!

[ASP.NET] Como obtener el Gravatar del usuario

Posted on Actualizado enn

Hola a todos, en los próximos post que serán cortos quiero mostrar algunas pequeñas funcionalidades que nos ayudarán a realizar pequeñas mejoras a nuestras aplicaciones y/o implementar funcionalidades muy especificas a nuestros desarrollos.

En este post vamos a revisar como usando la dirección de correo electrónico obtenemos el Gravatar del usuario, primero que todo si alguno no lo sabe el Gravatar es una imagen que podemos utilizar en algunas páginas Web, más info: Gravatar.

Ya entrando en materia lo primero es tener un muy sencillo formulario con una caja de texto para ingresar el email y un botón para obtener el Gravatar:

<h1>Gravatar</h1>
<hr />
<asp:Label ID="lblEmail" runat="server" Text="Email:"></asp:Label>
<asp:TextBox ID="txtEmail" runat="server" Width="250px"></asp:TextBox>
<asp:Button ID="btnGetGravatar" runat="server" OnClick="BtnGetGravatarClick" Text="Get Gravatar" />
<br />
<asp:Image ID="imgGravatar" runat="server" />

Luego necesitamos añadir el paquete ASP.NET Web Helpers Library utilizando Nuget:

image

Y finalmente en el evento click del botón:

protected void BtnGetGravatarClick(object sender, EventArgs e)
{
	if (!string.IsNullOrEmpty(txtEmail.Text))
	{
		var gravatar = Microsoft.Web.Helpers.Gravatar.GetUrl(txtEmail.Text);
		imgGravatar.ImageUrl = gravatar;
	}
}

Si probamos e ingresamos un correo, en este caso he ingresado el mío tenemos:

image

Espero les sea de utilidad, les dejo el ejemplo, saludos!

Descarga el ejemplo!

[ASP.NET MVC] Introducción a Single Page Applications

Posted on

Hola amigos, hace poco tuce la dicha de dar una pequeña charla sobre Single Page Applications, así que ahora les comparto el material, espero les sirva y como comente en el video, 1 hora es muy poco tiempo, así que escribiré al respecto.

Descargar el webcast!

Saludos!

[ASP.NET] Hands On Labs Web Forms Y MVC

Posted on

Hola a todos, hoy simplemente les quiero compartir unos hands on labs tanto para ASP.NET Web Forms como para ASP.NET MVC los cuales tenemos disponibles ahora en el sitio oficial de ASP.NET, se que como a mi les serán de gran ayuda, los links son:

Hands On Labs Web Forms

Hands On Labs MVC

Saludos.

[ASP.NET Web API] Filtros de validación

Posted on Actualizado enn

Realmente ando muy contento trabajando con Web API, sobretodo por su facilidad de uso, sin embargo, unos de los puntos que debemos tener presente cuando creando servicios REST con Web API es la seguridad y la creación de filtros para no exponer sin consideración las acciones de nuestros servicios, para solucionar dicho problema es posible crear filtros y realizar todas esas validaciones necesarias.

Los filtros pueden ser aplicados en diferentes niveles:

  • A nivel de clase
  • A nivel de acción
  • A nivel global

Para crear un filtro, se debe crear una clase que herede de ActionFilterAttribute y luego sobrescribir el método OnActionExecuting, para ver el tema en acción crearemos un filtro para validar que el dominio del cual están realizando la petición sea conocido, por lo tanto creamos la clase FilterDomainAttribute:

public class FilterDomainAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
	{
		var domain = "dominio";
		if (!string.Equals(actionContext.Request.RequestUri.Host, domain, StringComparison.OrdinalIgnoreCase))
		{
			actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
				{
					Content = new StringContent("Petición no autorizada")
				};
		}
	}
}

Entonces, creamos la clase FilterDomainAttribute la cual hereda de ActionFilterAttribute, luego hacemos un override al método OnActionExecuting y allí lo que hacemos es obtener el dominio con actionContext.Request.RequestUri.Host y se compara en este caso con el valor de la variable domain, en caso de no ser un dominio válido retornamos el mensaje “Petición no autorizada” con el estado de no autorizado HttpStatusCode.Unauthorized.

Ahora, creamos un controller (muy sencillo) para el manejo de clientes, entonces la clase Client:

public class Client
{
	public int ClientId { get; set; }
	public string Name { get; set; }
	public string Twitter { get; set; }
}

Y el controlador:

public class ClientController : ApiController
{
	private readonly IEnumerable<Client> clients = new List<Client>() {
		new Client (){ ClientId = 1, Name = "Julio", Twitter = "@julitogtu"},
		new Client (){ ClientId = 2, Name = "Juan", Twitter = "@JuanKRuiz"},
		new Client (){ ClientId = 3, Name = "Nicolas", Twitter = "@nicolocodev"},

	};

	public IEnumerable<Client> GetAll()
	{
		return clients;
	}

	public Client GetById(int id)
	{
		return new Client() { ClientId = 1, Name = "Julio", Twitter = "@julitogtu" };
	}
}

Para utilizar el filtro a nivel de clase o a nivel de acción lo único que se debe utilizar es decorar bien sea la clase o la acción con el atributo creado (no olvidar referenciar el namespace ActionFilter.Filter):

[FilterDomain]
public class ClientController : ApiController

[FilterDomain]
public IEnumerable GetAll()

Algo interesante es que es posible escribir solo FilterDomain, y recuerden que el nombre de la clase es FilterDomainAttribute.

Y ahora, si se quiere aplicar el filtro a nivel global se debe ir al global.asax y definirlo en el Application_Start:

GlobalConfiguration.Configuration.Filters.Add(new FilterDomainAttribute());

Si quieren ver otros ejemplos relacionados les recomiendo dos post del master Gonzalo:

Les dejo el código del ejemplo: Descarga el ejemplo!

Saludos!

[ASP.NET Web API] Respondiendo en JSON

Posted on Actualizado enn

Hola, pues este será un mini-post, donde simplemente voy a mostrar como podemos configurar el tipo de respuesta que deseamos den nuestros controladores, más en especifico los métodos que ellos tienen. Si por ejemplo tenemos el siguiente controlador:

public class ClientController : ApiController
{
	private readonly IEnumerable clients = new List() {
		new Client (){ ClientId = 1, Name = "Julio", Twitter = "@julitogtu"},
		new Client (){ ClientId = 2, Name = "Juan", Twitter = "@JuanKRuiz"},
		new Client (){ ClientId = 3, Name = "Nicolas", Twitter = "@nicolocodev"},

	};

	public IEnumerable GetAll()
	{
		return clients;
	}
}

Si por ejemplo, probamos en IE lo que obtenemos es un xml:

image

Y ahora, para trabajar en formato JSON lo que hacemos es eliminar la respuesta en tipo XML, así entonces en el Global.asax:

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

y si ahora lo probamos de nuevo en IE:

image

Saludos

[ASP.NET] Minificación de scripts con Web Essentials

Posted on Actualizado enn

Hola, este será un pequeño post en donde quiero mostrar como podemos generar nuestros archivos JavaScript más compactos, esto va a permitir que el nuevo archivo sea mas liviano y su descarga se más rápida, lo primero que debemos hacer es utilizando Nuget añadir Web Essentials:

image

Una vez instalada se tiene que reiniciar Visual Studio para que la herramienta quede disponible, ahora, para el ejemplo vamos a usar el siguiente archivo JavaScript (algo muy simple):

var operaciones = {
    Suma: function (a,b)
    {
        return a + b;
    },
    Resta: function (a,b)
    {
        return a - b;
    },
    Multiplicacion: function (a, b)
    {
        return a * b;
    },
    Division: function (a, b)
    {
        return a / b;
    }
};

Ese código lo he creado en un archivo con nombre Test.js, y sobre dicho archivo damos click derecho Web Essentials –> Minify JavaScript file(s), y se generan dos nuevos archivos, el primero Test.min.js y el segundo Test.min.js.map:

image

En el archivo .min.js se tiene el código JavaScript minificado, y en .min.js.map se tiene información sobre el archivo minificado, es importante que la minificación solo debe realizarse la primera vez, ya que si cambiamos el archivo normal, automáticamente vamos a tener esos cambios reflejados en el archivo .min.

Si observamos el archivo minificado:

var operaciones={Suma:function(n,t){return n+t},Resta:function(n,t){return n-t},Multiplicacion:function(n,t){return n*t},Division:function(n,t){return n/t}};
//@ sourceMappingURL=Test.min.js.map

Espero les haya gustado este pequeño post, que es más un tip de productividad.