Materiales del evento “Mecanismos de validación en ASP.NET MVC 3”

Buenas,

Ayer grabamos el webcast y a día de hoy no está disponible. Nos pareció raro que dijese que estaba grabando pero el tiempo de grabación no pasaba de 00:00:00, aunque al terminar nos dijo que si queríamos guardar la grabación. En caso de no estar disponible (Ya sabéis como es Live Metting, cuando no es el sonido es la grabación…) podríamos repetir el evento más adelante.

Para poder visualizar online o descargar el evento acceder a la url de registro y registraros.

Ajunto están los materiales del evento.

Un saludo y gracias a todos lso asistentes.

webcast-validaciones-en-mvc3-jose-maria-aguilar.rar (2,40 mb)

[SharePoint 2010] "The collection cannot be modified."

Estaba creando un powershell para añadir a un content type existente una columna de sitio con el siguiente código:

$site = Get-SPSite $url

$web = $site.RootWeb

$contenttype = $web.AvailableContentTypes["..."]

$field = $web.Fields.GetFieldByInternalName("...")

 

if ($contenttype -eq $null)

{

    Write-Host "Content Type ... does not exist"

}

elseif ($field -eq $null)

{

    Write-Host "Site Column does ... not exist"

}

else

{

    if ($contenttype.Fields.Contains($field.Id))

    {

        Write-Host "Content Type ... contains site column ..."

    }

    else

    {

        $link = New-Object Microsoft.SharePoint.SPFieldLink($field)

        $contenttype.FieldLinks.Add($link)

        $contenttype.Update($true)

        Write-Host "Content Type has been updated successfully"

    }

}

Y he recibido este error:

Exception calling "Update" with "1" argument(s): "The collection cannot be modified."

At C:…kbkb110926.ps1:41 char:24

+                 $contenttype.Update <<<< ($true)

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : DotNetMethodException

Solución:

Usar la propiedad ContentTypes en vez de AvailableContentTypes porque es read-only:

$contenttype = $web.ContentTypes["..."]

Un saludo.

[SharePoint] Crear/Borrar Scope de sitios programaticamente

En versiones anteriores de SharePoint para hacer esto hacíamos uso de la clase SearchContext que ahora en 2010 está obsoleta:

SearchContext is deprecated.

SearchContext is deprecated and shouldn’t be used as an example on a SP 2010 class.

Para crear un Scope sobre un sitio de SharePoint podemos hacer uso del siguiente código:

private void CreateScope(string title, SPWeb web, SPSite site)

{

    var remoteScopes = new RemoteScopes(SPServiceContext.GetContext(site));

 

    var allScopes = remoteScopes.AllScopes;

    var scope = allScopes.Cast<Scope>().SingleOrDefault(s => s.Name == title);

    

    if (scope != null)

        scope.Delete();

 

    var newScope = remoteScopes.AllScopes.Create(title, title, new Uri(web.Url), true, "results.aspx",

                                                 ScopeCompilationType.AlwaysCompile);

    newScope.Rules.CreateUrlRule(ScopeRuleFilterBehavior.Include, UrlScopeRuleType.Folder, web.Url);

 

    remoteScopes.StartCompilation();

}

 
Para borrar:
 
private void RemoveScope(string title, SPSite site)

{

    var remoteScopes = new RemoteScopes(SPServiceContext.GetContext(site));

 

    var allScopes = remoteScopes.AllScopes;

    var scope = allScopes.Cast<Scope>().SingleOrDefault(s => s.Name == title);

 

    if (scope != null)

        scope.Delete();

}

Estos métodos los podemos utilizar en nuestro receiver Winking smile

Un saludo

[ASP.NET MVC 3] Por qué IDependencyResolver no cumple con la filosofía de los IoC

No se si el título es muy adecuado, pero espero que leyendo esto y los artículos que menciono os quede más claro.

Tengo pendiente escribir una serie de sobre DI (Qué es, patrones, antipatrones…), pero de momento voy a escribir sobre este tema ya que el otro día por twitter lo estuve hablando con @pablonete sobre como implementar DI en ASP.NET MVC, Yo conocía desde la versión 1.0 la implentación de DI usando un IControllerFactory pero ví que en la versión 3 se había añadido la interfaz IDependecyResolver y parecía la manera correcta de hacerlo ahora, así que le pasé un enlace de como hacerlo así.

Peroooo, si leemos a los guruses hablar de temas de arquitecturas y mas concretamente sobre DI, como podemos leer en este artículo de Mark Seemann’s, los contenedores de dependencias disponen de 3 métodos para registrar, resolver y limpiar dependencias, Mark propone llamar a este patrón Register Resolve Release pattern basandose el el nombre de los métodos de CastleWindsor (En otros contenedores se utilizan otros nombres que a lo mejor pueden despistar un poco al programador, en el caso de Unity el método Release es TearDown)

En ASP.NET MVC 3 han añadido la interfaz IDependencyResolver para facilitarnos el uso de DI, pero esta interfaz carece de un método Release al contrario de IControllerFactory:

public interface IControllerFactory

{

    IController CreateController(RequestContext requestContext, string controllerName);

    void ReleaseController(IController controller);

}

public interface IDependencyResolver 

{    

    object GetService(Type serviceType);    

    IEnumerable<object> GetServices(Type serviceType);

}

Os recomiendo la lectura de este artículo de Mike Hadlow

The MVC 3.0 IDependencyResolver interface is broken. Don’t use it with Windsor.

Leyendo esto me asaltan las dudas de porque han hecho esto de esta manera la gente del equipo de MVC, si ya disponíamos desde la versión 1.0 de un mecanismo que al parecer se adapta mejor a estos patrones ¿no?

Espero opiniones al respecto y si vemos que esto da para rato, creamos una entrada en el Grupo de AUGES en LinkedIn.

Un saludo.

[Tips & Tricks] No puedo añadir las referencias de AppFabric Cache en Visual Studio 2010

Cosa rara donde las haya pero cierta. He instalado la versión de 64 bits y aquí están las dlls:

image

image

Pero desde Visual Studio no aparece la carpeta:

image

Pero existe un workaround para solucionar esto y es escribir en File name %WinDir%SysNativeAppFabric seguido de

image

Un saludo

[ASP.NET vNext] Model Binding: Actualizando datos (Ya tenemos Data Annotations!)

Menudo notición viendo el nuevo video de ASP.NET vNext!!! El otro día comentaba en este post que a ver sí se ponían las pilas e incorporaban el tema de las validaciones de ASP.NET MVC con Data Annotations a la nueva versión de ASP.NET vNext y lo han hecho señores!!!

Con las Data Annotations, indicamos que la propiedad ProductName de nuestra entidad de dominio Product es obligatoria y que su longitud debe ser mayor que 40

image 

En nuestro GridView, en el atributo UpdateMethod le decimos cual será el método de nuestra página para actualizar los datos, en este caso UpdateProduct:

image

Añadimos un ValidationSummary:

image

Y codificamos nuestro método UpdateProduct:

image

El GridView pasará el id del producto al método, obtenemos el producto de la base de datos y llamamos a la función TryUpdateModel, en la qué el Model Binding hará un bind de los datos que hemos introducido en la línea del GridView a nuestra entidad del dominio (Product). Acto seguido comprobamos si el modelo es válido, y sino lo es, en nuestra página veremos todos los errores de validación gracias al ValidationSummary que pusimos. En este caso como se ha dejado en blanco el ProductName nos dirá que es requerido:

image

¿Que os parece? A mí personalmente me parece una mejora increible, adios a los malditos validators que tanto dolores de cabeza y tiempo nos hacían perder.

Podéis ver el vídeo en este enlace

Un saludo.

[ASP.NET vNext] Model Binding: Filtrando datos

Siguiendo con la serie de ASP.NET vNext que Scott Guthrie está publicando en su blog, hoy toca el filtrado de datos. Partiendo de este grid:

<asp:GridView ID="productsGrid" SelectMethod="GetProducts" DataKeyNames="ProductID"

    AllowPaging="true" AllowSorting="true" AutoGenerateColumns="false" runat="server">

    <Columns>

        <asp:BoundField DataField="ProductID" HeaderText="ID" />

        <asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />

        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />

        <asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />

    </Columns>

</asp:GridView>

Y del método GetProducts:

public partial class Products : Page

{

    Northwind db = new Northwind();

 

    public IQueryable<Product> GetProducts()

    {

        return db.Products;

    }

}

 
Vamos a ver las nuevas mejoras que dispondremos en esta nueva versión:
 

Value Providers

Esto también lo han tomado de ASP.NET MVC, para hacer que el Model Binding sea capaz de hacer un binding entre los parámetros de nuestros métodos con lo que le especifiquemos mediante “Value Provider Attributes”, algo como esto:

image

¿Como funciona todo esto?

Cuando haya un postback al servdor, el Value Provider Attribute que hemos usado en el método le indicará al Model Binding que Value Provider tiene que usar para hacer un bind de un valor del formulario con el parámetro category de nuestro método, e incluso se encargará de la conversión. En este caso se está usando un nullable para que en caso de no estra presente dicho valor, sea nulo (De ahí la comprobación category.HasValue)

En la nueva versión de ASP.NET vNext dispondremos de todos estos Values Providers y de sus respectivos Value Provider Attributes:

  • QueryString
  • Cookies
  • Form values
  • Controls
  • Viewstate
  • Session
  • Profile

Por ejmplo por QueryString sería algo así:

public IQueryable<Product> GetProducts([QueryString("q")]string keyword)

Es decir, buscará un parámetro que se llame q en el QueryString y hará un “bind” con nuestro parámetro keyword:

query

Otro ejemplo sería utilizar un control para filtrar:

image

En este caso podemos hasta indicarle el ID del control que vamos a utilizar para el filtrado.

Podéis ver un vídeo de todo esto aquí

Un saludo y hasta el próximo.

[ASP.NET vNext] Model Binding: Obteniendo datos

Siguiendo con la serie de novedades que Scott Guthrie está publicando sobre ASP.NET vNext, esta vez toca algo que han añadido a WebForms y que viene de su hermano pequeño MVC, el Model Binding.

Si habéis trabajado con las versiones anteriores de ASP.NET el tema del binding es algo que no acaba de convencer en lo que se refiere a tener
nuestra propia capa de datos (Repository pattern por ejemplo) y escribir lógica de negocio (Servicios) que hace uso de esta capa y a su vez
tener los controles de datos en ASP.NET que hagan uso de esta lógica a través de un patrón MVP.

Sí es cierto que con el control ObjectDataSource la cosa mejoró un poco, pero sigue siendo insuficiente porque no soporta binding para tipos complejos.

El Model Binding

El Model Binding es una evolución del binding que ya disponíamos en versiones anteriores de ASP.NET y nos a va a permitir trabajar con los controles de datos de manera más simple y más limpia.

Mirar el siguiente ejemplo que muestra Scott en su página:

<asp:GridView ID="categoriesGrid" runat="server" ModelType="WebApplication1.Model.Category"

    SelectMethod="GetCategories" AutoGenerateColumns="false">

    <Columns>

        <asp:BoundField DataField="CategoryID" HeaderText="ID" />

        <asp:BoundField DataField="CategoryName" HeaderText="Name" />

        <asp:BoundField DataField="Description" HeaderText="Description" />

        <asp:TemplateField HeaderText="# of Products">

            <ItemTemplate><%
   1: # Item.Products.Count 

%></ItemTemplate>

        </asp:TemplateField>

    </Columns>

</asp:GridView>

Hay 3 cosas importatntes que resaltar:

La primera es el uso del atributo ModelType del que habalmos en este post para ofrecer strongly-typed data-binding en la vista.

La segunda es el atributo SelectMethod, en el que podemos especificarle un método de nuestro code behind desde donde obtendrá la información (Model Binding) que en este caso es del métiodo:

public IQueryable<Category> GetCategories() {

    var northwind = new Northwind();

    return northwind.Categories.Include(c => c.Products);

}

Si nos fijamos, el método GetCategories se hace uso del método extensor Include que indica a EF que además de traerse la información de la categoría se traiga también los productos relacionados. Luego en el templatefield tenemos la propiedad Item.Products.Count y ese es el tipo de binding complejo del que antes hablabamos y que requería codificación extra por nuestra parte para escenarios de este tipo.

Otra cosa que hay que resaltar del método GetCategories es que devuelve un IQueryable<T> que habilita la ejecución diferida (Mira este post que escribí hace un tiempo) y que es muy util para controles que soportan paginación y ordenación, porque le va a permitir aplicar la ordenación y la páginación antes de ejecutarse. Te preguntarás ¿Y en que nos ayuda esto? Pues que ahora la páginación y la ordenación es algo muy sencillo de implementar, basta con poner los atributos AllowSorting y AllowPaging a true el PageSize a el tamaño que tu quieras:

<asp:GridView ID="categoriesGrid" runat="server" AutoGenerateColumns="false"

    AllowSorting="true" AllowPaging="true" PageSize="5"

    ModelType="WebApplication1.Model.Category" 

    SelectMethod="GetCategories">

    <Columns>

        <asp:BoundField DataField="CategoryID" HeaderText="ID" SortExpression="CategoryID" />

        <asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" />

        <asp:BoundField DataField="Description" HeaderText="Description" />

        <asp:TemplateField HeaderText="# of Products">

            <ItemTemplate><%
   1: # Item.Products.Count 

%></ItemTemplate>

        </asp:TemplateField>

    </Columns>

</asp:GridView>

Y tachán:

image_thumb_5EEAFDD8

La verdad es que todas las novedades que están incluyendo para la nueva versión de ASP.NET prometen mucho, yo espero que se pongan las pilas en el tema de las validaciones y tomen nota también de su hermano pequeño, porque los validators de ASP.NET son un verdadero infierno.

Hasta la próxima!!!

[ASP.NET vNext] Strongly Typed Data Controls, No más Eval y Bind!

Siguiendo con la serie de post que Scott Guthrie está escribiendo en su blog, seguro que los que habéis trabajado con ASP.NET conocéis fijo las templates de los controles de ASP.NET ¿verdad? y sino pues las templates de controles de datos basicamente nos permiten modificar o customizar el HTML que emiten al cliente usando expresiones de databinding como Eval y Bind, algo como esto:

Eval

Para solo mostrar la información hacemos uso de Eval One-Way-Binding

<asp:GridView ID="grv_Mensajes" runat="server" AutoGenerateColumns="False" AllowPaging="True">

   <Columns>

      <asp:TemplateField>

         <ItemTemplate>   

            <asp:Label ID="lblTitulo" runat="server" Text='<%# Eval("Titulo") %>'></asp:Label>  

         </ItemTemplate>

      </asp:TemplateField>      

      <asp:TemplateField>

         <ItemTemplate>   

            <asp:Label ID="lblDescripcion" runat="server" Text='<%# Eval("Descripcion") %>'></asp:Label>  

         </ItemTemplate>

     </asp:TemplateField>

   </Columns>

</asp:GridView>

Bind

Para mostrar y modificar la información usamos Bind Two-Way-Binding

<asp:FormView ID="FormCustomer" runat="server" >

    <EditItemTemplate>

        <div>

            Título:

            <asp:TextBox ID="txtTitulo" runat="server" Text='<%# Bind("Titulo") %>' />

        </div>

        <div>

            Descripción:

            <asp:TextBox ID="txtDescripcion" runat="server" Text='<%# Bind("Descripcion") %>' />

        </div>

        <asp:Button runat="server" CommandName="Update" />

    </EditItemTemplate>

</asp:FormView>

¿Cual es el problema de esto?

Hay 2 problemas con esto desde mi punto de vista:

  1. No es fácil recordar como se llaman todas las propiedades de nuestras clases o entidades.
  2. En la vista HTML no disponemos de Intellisense para los Data Controls y es posible que al escribir el nombre del campo mal, en tiempo de ejecucuión nos salte una excepción.

Para evitar esto y facilitarnos un poco más la vida, en la próxima versión de ASP.NET tendremos los Strongly Typed Data Controls

eval

Como se aprecia en la imagen haciendo uso del atributo ModelType le indicamos al control cual será la clase de nuestro modelo con la que vamos a trabajar y ya tenemos disponible en el intellisense todos los campos. El Item es equivalente al método Eval

El equivalente al método Bind es BindItem

<asp:FormView ID="FormCustomer" runat="server" >

    <EditItemTemplate>

        <div>

            Título:

            <asp:TextBox ID="txtTitulo" runat="server" Text='<%# BindItem.Titulo %>' />

        </div>

        <div>

            Descripción:

            <asp:TextBox ID="txtDescripcion" runat="server" Text='<%# BindItem.Descripcion %>' />

        </div>

        <asp:Button runat="server" CommandName="Update" />

    </EditItemTemplate>

</asp:FormView>

Si nos equivocamos en el nombre del campo, en tiempo de diseño el Intellisense de Visual Studio nos avisará:

error

Mola! ¿no?

Un saludo.

[ASP.NET vNext] Smart Tasks y generación de eventos de controles desde la vista HTML

Leyendo el blog de Scott Guthrie vamos a ir descubriendo las novedades que incluirán en ASP.NET, MVC y VS. En esta ocasión tenemos 2 mejoras para ASP.NET en la próxima versión de Visual Studio, que seguro gustará a los desarrolladores que prefieren trabajar con la vista HTML en vez del diseñador (Por ejemplo yo)

Smart Tasks en la vista HTML

Hace tiempo que tenemos disponible los Smart Tasks en la vista de diseño:

creating-asp-net-menu-control_clip_image003

Y en la nueva versión de Visual Studio lo tendremos en la vista HTML:

smarttask

Generación de eventos desde la vista HTML

Es una cosa que siempre he echado de menos cuando uso la vista HTML, eso de tener que hacer doble click en el control o tener que irme a la ventana de propiedades, eventos y seleccionar… no me gusta y ahora ya lo podemos escribir desde la vista HTML:

event

Además, si ya tenemos el evento en el code behind podremos seleccionarlo.

A medida que se vayan publicando nuevas mejoras, iré escribiendo más posts.

Un saludo