Codepoint

by Trentia Consulting

Projection y Query en Orchard CMS

El módulo Projector nos permite crear instancias de Query y Projection, consultas de datos y páginas que muestran el resultado de estas.

En este artículo crearemos una consulta que devuelva todos nuestros productos y una página que muestre el listado de estos. Suponemos que inicialmente en nuestro proyecto ya existen diferentes Content Types que tienen asociado un ProductPart.
public class ProductPart : ContentPart<ProductPartRecord>
{
  public string SerialNumber
  {
    get { return Retrieve(r => r.SerialNumber); }
    set { Store(r => r.SerialNumber, value); }
  }

  public decimal Price
  {
    get { return Retrieve(r => r.Price); }
    set { Store(r => r.Price, value); }
  }
}

public class ProductPartRecord : ContentPartRecord
{
  public virtual string SerialNumber { get; set; }
  public virtual decimal Price { get; set; }
}
Necesitamos una Query que devuelva todos los elementos cuyo tipo de contenido contenga un ProductPart adjunto. En el framework no tenemos un filtro que permita esta funcionalidad, así que creamos una nueva clase que herede de IFilterProvider:
public class ProductPartFilter : IFilterProvider
{
  public void Describe(DescribeFilterContext describe)
  {
    describe.For("Content","Content","Content")
        .Element("ProductPartFilter", "ProductPartFilter", "ProductPartFilter", ApplyFilter, DisplayFilter);
  }

  private void ApplyFilter(FilterContext context)
  {
    context.Query = context.Query.Join(x => x.ContentPartRecord(typeof(ProductPartRecord)));
  }
}
Ahora ya podemos añadir la nueva Query desde la interfaz web de administración asignándole el título "Productos". La editamos y hacemos clic en "Add a new Filter" para seleccionar el filtro que hemos creado anteriormente.

Es posible que por alguna razón específica de nuestro proyecto necesitemos realizar lo mismo programando directamente, en este caso podemos utilizar el siguiente código:
string name = "Productos";
string type = "ProductPartFilter";

QueryPart query = _queryService.CreateQuery(name);

var form = new Form { ContentTypes = type };
var serializer = new XmlSerializer(form.GetType());
StringWriter sw = new StringWriter();
XmlWriter writer = XmlWriter.Create(sw);
serializer.Serialize(writer, form);
var state = sw.ToString();

query.FilterGroups[0].Filters.Add(new FilterRecord
{
  Category = "Content",
  Description = "ProductPartFilter",
  Position = 0,
  State = state,
  Type = type
});

_contentManager.Publish(query.ContentItem);

[Serializable]
public class Form
{
  public string Description { get; set; }
  public string ContentTypes { get; set; }
}
Por último, para crear la página que muestra el listado de productos, hacemos clic en New Projection. Asignamos el título "Listado Productos", la url "productos" y seleccionamos en el desplegable la Query "Productos".

Una vez más, si necesitamos crear la instancia de Projection programando, tenemos el código equivalente:
var projection = _contentManager.New("ProjectionPage");
projection.As<TitlePart>().Title = "Listado Productos";
projection.As<AutoroutePart>().DisplayAlias = "productos";
projection.As<ProjectionPart>().Record.QueryPartRecord = query.Record;

string ownerName = _siteService.GetSiteSettings().SuperUser;
var owner = _membershipService.GetUser(ownerName);
projection.As<ICommonPart>().Owner = owner;

_contentManager.Create(projection, VersionOptions.Published);
Projection - Orchard Documentation

Solución a la hora de filtrar Foreign Keys con identificadores Guid en la grid de la suite de controles Telerik MVC Extensions

Seguramente los que hayáis trabajado con la suite de controles de Telerik para MVC os hayáis dado cuenta que determinados operaciones con los controles Grid no funcionan como deberían. Entre ellas, la más destacada y a la que no hemos encontrado solución hasta ahora, se trata del error que se producía a la hora de filtrar una grid con Foreign Keys donde la Primary Key eran identificadores únicos (Guid o Uniqueidentifier).

Parece ser que Telerik no ha querido darle la solución a esta problemática ya que este error se arrastra desde versiones muy iniciales de esta suite de controles y estoy seguro que no hemos sido los únicos que nos hemos encontrado con este problema.

Pues bien, después de darle vueltas al asunto,en Trentia Consulting no hemos tenido más remedio que darle solución y para ello hemos descargado el último código fuente y lo hemos modificado para dar solución al problema.

Aunque al final de esta entrada acompañamos el código fuente modificado para que los podáis compilar y actualizar a vuestra solución, hemos querido resaltar algunos pasos que creemos que son los más importantes.

Vamos a ello, principalmente cuando filtrábamos por una FK, la llamada AJAX que se encargaba de dibujar el GRID nos daba el siguiente error en la pila del Stack Trace

Invalid cast from "System.String" to "System.Guid" 
System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) +10578274 
	
System.String.System.IConvertible.ToType(Type type, IFormatProvider provider) +8 
	
System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) +10625268 

Con este error, deducimos que la la conversión de String a Guid no estaba implementada. Así que después de investigar, lo primero que tuvimos que tocar fue la clase FilterLexer ubicada dentro del namespace Telerik.Web.Mvc.Infrastructure.Implementation.

Revisando el método Tokenize vimos que el parse de parámetros Guid no estaba implementado, así que tuvimos que añadir lo siguiente:

 public IList Tokenize()
        {
            List tokens = new List();

            while (currentCharacterIndex < input.Length)
            {
                string result;

                if (TryParseGuid(out result))
                {
                    tokens.Add(UniqueIdentifier(result));
                }
                else if (TryParseIdentifier(out result))
                {
                    tokens.Add(Identifier(result));
                }
	...
}


Aquí hemos implementado el método TryParseGuid, que se encargará de detectar y formatear el string del identificador del filtro a Guid.

El código es el siguiente

private bool TryParseGuid(out string guid)
{
            SkipSeparators();

            int longitud=36;

            StringBuilder result = new StringBuilder();
            for (int i = 0; i < longitud; i++)
            {
                if((i + currentCharacterIndex)<input.Length)
                    result.Append(input[i + currentCharacterIndex]);
            }

          
            Guid outGuid = Guid.Empty;

            if (Guid.TryParse(result.ToString(), out outGuid))
            {
                guid = result.ToString();
                currentCharacterIndex+=longitud;
                return true;
            }
            else
            {
                guid = null;
                return false;
            }
}

Una vez implementada la detección del Guid, ya sólo nos queda ir al resto de clases que integran las funcionalidades de filtrado de la Grid de Telerik como la clase FilterParser.cs, GuidNode.cs y FilterTokenType.cs del mismo namespace.

Aquí os dejo el enlace de descarga del artículo que hemos redactado en CodeProject con el fin de compartir este problema con el mayor número de personas.

Descarga de la solución

Espero que os sea de ayuda.

Proyecto Orchard: CMS en ASP.NET MVC

Orchard es un gestor de contenidos web o CMS que parece contar con la bendición de Microsoft. Recientemente hemos estado desarrollando con este CMS, como alternativa a Umbraco, otro conocido CMS de .NET.


Orchard nos ha gustado especialmente por sus características funcionales y técnicas.

Orchard cubre bastante bien aspectos que otros CMS quizás no tengan demasiado presente, como el soporte multiidioma y multicultural, que acostumbra a ser un problema. También dispone de una buena extensibilidad a muy diversos niveles, que nos permite trabajar con vistas de MVC para definir hasta el más mínimo aspecto de la web. Tenemos control absoluto del HTML resultante y eso es muy positivo. También contempla bien aspectos de SEO, tan necesarios hoy en día. Y finalmente, ofrece un buen rendimiento, aspecto que también puede resultar complejo en CMS basados en Microsoft .NET.

Nuestro último proyecto en Orchard es el desarrollo de una web con CMS, haciendo uso deFoundation Zurb como framework de diseño responsable. Estamos realmente satisfechos con el resultado y con Orchard. Os recomiendo que lo tengáis presente en vuestro portfolio de soluciones CMS.

Autenticación Windows en MVC 4 redirige a página de login

En mi caso ha sido a Login.aspx, pero podría haber sido /Account/Login. Por alguna razón las llamadas a controladores que requieren autorización me llevaban a la página de inicio de sesión, cuando en realidad en web.config tengo configurada la autenticación Windows.

Después de investigar algo he visto un artículo en Stackoverflow que me ha ayudado a resolver el problema. Se trata de deshabilitar SimpleMembership de la aplicación. Esto se consigue añadiendo esta entrada en la clave <appSettings> de web.config.


Por cierto, un artículo sobre cómo configurar SimpleMembership: http://www.mono-software.com/blog/post/Mono/226/Adding-ASP-NET-SimpleMembership-to-an-existing-MVC-4-application/

Enviar información entre métodos de acción (MVC)

Hay veces en las que necesitamos enviar información de un método de acción (ActionMethod) a otro, por ejemplo si queremos realizar una acción determinada y luego volver al método anterior.

Podemos almacenar la información necesaria en el objeto TempDataDictionary del controlador, antes de llamar al método RedirectToAction que nos redirigirá a la próxima acción. El valor de la propiedad TempData se almacena en el estado de la sesión, y cualquier método llamado después de guardarlo podrá leerlo y procesarlo. El valor del objeto TempData se conservará hasta la expiración de la sesión o hasta que sea leído.

Ejemplo:

- Guardar información en el objeto TempData:

public ActionResult AddUsuario(Usuario model)
{
    if (ModelState.IsValid)
    {
	//guardar usuario en la base de datos        

        TempData["message"] = "Usuario creado correctamente.";
        return RedirectToAction("DetailsUsuario ", new { USU_Id = model.USU_Id } );
    }

    return View(model);
 }
public ActionResult DetailsUsuario(Guid USU_Id)
{
    //Consultar usuario de la base de datos
    if(TempData["message"] != null)
    {
        ViewBag.message = TempData["message"];
    }
 return View(usuario);
}

Nueva versión de Umbraco en MVC 3

La versión 5 del conocido gestor de contenidos web Umbraco está disponible desde enero de 2012. La nueva versión, inicialmente denominada “Jupiter”, ha sido reconstruida para adaptarse a la arquitectura ASP.NET MVC 3, lo cual es una buena noticia para todos los desarrolladores que trabajan con Umbraco. Tambien es una buena noticia que a pesar de la actualización de arquitectura se consevan todas las funcionalidades de la versión anterior.

La nueva arquitectura ofrece un mayor rendimiento y mayores posibilidades de integración con sistemas externos a Umbraco.