Sunday, March 6, 2011

A useful ASP.NET MVC HTML extension method for rendering a DropDownList

I really like ASP.NET MVC, but understanding the usage of the DropDownListFor HTML helper method is not trivial. Therefore I decided to simplify it by introducing the following HTML extension methods for rendering a DropDownList. The idea is that the data for a dropdownlist is encapsulated in an IDictionary object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Linq.Expressions;
using System.Diagnostics.CodeAnalysis;
using System.Web.Routing;
using System.Web.Mvc.Html;

namespace My.Helpers.HTML
{
    public static class CuSelectExtensions
    {
        /// <summary>
        /// returns an HTML select element for an IDictionary 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="funcForDict">a function that returns an IDictionary</param>
        /// <param name="expForSelectedKey">a expression which returns the selected Key of the IDictionary</param>
        /// <returns></returns>
        public static MvcHtmlString DropDownListFor<TModel, TKey, TValue>(this HtmlHelper<TModel> htmlHelper, Func<TModel, IDictionary<TKey, TValue>> funcForDict, Expression<Func<TModel, TKey>> expForSelectedKey)
        {
            return htmlHelper.DropDownListFor(expForSelectedKey, funcForDict.Invoke(htmlHelper.ViewData.Model).ToSelectList(expForSelectedKey.Compile().Invoke(htmlHelper.ViewData.Model)));
        }

        /// <summary>
        /// Converts a dictionary to a SelectList
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static SelectList ToSelectList<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
        {
            //call with default value
            return dictionary.ToSelectList(default(TKey));
        }

        /// <summary>
        /// Converts a dictionary to SelectList
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="selectedItem"></param>
        /// <returns></returns>
        public static SelectList ToSelectList<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey selectedItem)
        {
            return new SelectList(dictionary, "Key", "Value", selectedItem);
        }
    }
}


Emphasizing the importance to divide view model from data model is fundamental for creating a good MVC project. Keeping in mind this aspect you will notice the importance and the goodness of the extension methods I introduced above.
Let’s suppose we have the following data model and we want to render a form for collecting this kind of data.


public class Address
{
    public virtual int? ID { get; set; }
    public virtual State State { get; set; }
    public virtual string Province { get; set; }
    public virtual string City { get; set; }
    public virtual string Street { get; set; }
    public virtual string PostCode { get; set; }
}

public class State
{
    public virtual int? ID { get; set; }
    public virtual string Desc { get; set; }
}

Then our view model will look like this:


public class AddressView
{
    public IDictionary<int, string> AvailableStates { get; set; }
    public int SelectedState { get; set; }
    public string Province { get; set; }
    public string City { get; set; }
    public string Street { get; set; }
    public string PostCode { get; set; }
}

In the following controller, which access the Business-Logic (BL) for retrieving the Address object and which again is built on top of the DataAccess-Logic (DAL), we convert an Address object into an AddressView object and we pass it to a View for rendering it. For simplifying this example I am going to hide the implementation of the BL and DAL.


public ActionResult Edit(int id)
{
    Address ad = AddressBL.GetByID(id);
    IList<State> states = StateBL.GetAll();
    //Convert datamodel to viewmodel
    AddressView av = new AddressView();
    av.AvailableStates = states.ToDictionary(x => x.ID, x => x.Desc);
    dv.selectedState = ad.State.ID;
    av.Province = ad.Province
    // . . .
    return View(av);
}

Finally, using our proposed implementation for DropDownlistFor in a view is very easy. It is enough to specify an IDictionary object and a Key for the selected element. Here is an example:


<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" Inherits="ViewPage<AddressView>" %>

<%@ Import Namespace="My.Helpers.HTML" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <%: Html.DropDownListFor(x => x.States, x => x.AvailableStates)%>
</asp:Content>

Sunday, February 6, 2011

Second part: MVC.net & jqGrid

Let’s start by explaining how to include jqGrid (http://www.trirand.com/blog/) in your views. First you need to download and unzip jqGrid and jQueryUI (http://jqueryui.com/). I placed them in the root folder (jquery-ui-1.8.7.custom, jquery.jqGrid-3.8.2) of my project. Afterwards you need to reference them in the header of your web page.

<%--css for UI--%>
<link rel="stylesheet" type="text/css" media="screen" href="<%:Url.Content("~/jquery-ui-1.8.7.custom/css/ui-lightness/jquery-ui-1.8.7.custom.css") %>" />
<%--css for grid--%>
<link rel="stylesheet" type="text/css" media="screen" href="<%:Url.Content("~/jquery.jqGrid-3.8.2/css/ui.jqgrid.css") %>" />
<%-- jquery scripts --%>
<script src="<%:Url.Content("~/jquery.jqGrid-3.8.2/js/jquery-1.4.2.min.js") %>" type="text/javascript"></script>
<%-- ui scripts --%>
<script src="<%:Url.Content("~/jquery-ui-1.8.7.custom/js/jquery-ui-1.8.7.custom.min.js") %>" type="text/javascript"></script>
<%-- grid scripts --%>
<script src="<%:Url.Content("~/jquery.jqGrid-3.8.2/js/i18n/grid.locale-en.js") %>" type="text/javascript"></script>
<script src="<%:Url.Content("~/jquery.jqGrid-3.8.2/js/jquery.jqGrid.min.js") %>" type="text/javascript"></script>

Including following code should render the jqGrid on your page.

<table id="grid">
</table>
<div id="pager">
</div>
<script type="text/javascript">
    jQuery(document).ready(function () {
        jQuery("#grid").jqGrid({
            url: "/JqGrid/GridData",
            datatype: 'json',
            mtype: 'POST',
            colNames: ['Start Time', 'End Time', 'Date', 'Description', 'Notes'],
            colModel: [
            { name: 'FromTime', sortable: true, editable: true, edittype: 'text', width: 80 },
            { name: 'ToTime', sortable: true, editable: true, edittype: 'text', width: 80 },
            { name: 'Date', search: true, editable: true, edittype: 'text', width: 80 },
            { name: 'Description', search: true, editable: true, edittype: 'text', width: 200 },
            { name: 'Notes', sortable: true, editable: true, edittype: 'text', width: 150}],
            pager: jQuery('#pager'),
            rowNum: 10,
            rowList: [5, 10, 20, 50, 100, 200, 500, 1000],
            sortname: 'Date',
            sortorder: "desc",
            height: "100%",
            viewrecords: true,
            scrollOffset: 0,
            caption: 'Sample'
        });

        jQuery("#grid").jqGrid('navGrid', '#pager',
            { edit: true, add: true, del: true, search: true },
            { url: "/JqGrid/Edit", width: 'auto', closeAfterEdit: true, beforeShowForm: function (formid) { $("#Date").datepicker({ dateFormat: 'dd.mm.yy', showButtonPanel: true }); } },
            { url: "/JqGrid/Create", width: 'auto', closeAfterAdd: true, beforeShowForm: function (formid) { $("#Date").datepicker({ dateFormat: 'dd.mm.yy', showButtonPanel: true }); } },
              { url: "/JqGrid/Delete" },
            { closeAfterSearch: true, closeOnEscape: true, multipleSearch: true });
    });
</script>

Let’s explain now some parts:

url: "/JqGrid/GridData" -> tells where the grid should retrieve the data
colNames: ['Start Time', 'End Time',..] '-> column names
colModel: [{ name: 'FromTime' ...}] –> describes the data

To be more precise data is formatted as json. For example:
"cell":["00:00","02:00","06.02.2011","Element0",""]
where the element 1 (ex. 00:00) of cell items corresponds to the item 1 of the colNames and colModel items. 

Finally, we are going to investigate how data is retried from a controller. This part is quite simple you just need to have the data in a list object. At that moment you will have an extension method which encapsulate sorting, filtering and paging functionality. It is just enough to call JqGridDataModelConvert and to specify which properties of the objects contained in the list corresponds to the colModel. Moreover the property has to be wrapped by an object of GridCell, which encapsulate compare and string serialization and deserialization logic. Most of the time you will use BasicGridCell<T>, but it is also possible to extend the wrapper with custom code.

Example:

public virtual ActionResult GridData(GridSettings jqGridSettings)
{
    JqGridDataModel data = Data.JqGridDataModelConvert(columns =>
    {
        columns.Add("FromTime", ev => new BasicGridCell<string>(ev.FromTime));
        columns.Add("ToTime", ev => new BasicGridCell<string>(ev.ToTime));
        columns.Add("Date", ev => new DateTimeGridCell(ev.Date) { Format = "dd.MM.yyyy" });
        columns.Add("Description", ev => new BasicGridCell<string>(ev.Description));
        columns.Add("Notes", ev => new BasicGridCell<string>(ev.Notes));
    }, ev => new BasicGridCell<int>(ev.ID), jqGridSettings);
    return Json(data);
}

Programming is fun!!

Saturday, February 5, 2011

First part: MVC.net & jqGrid

This is the first part of a series of posts in which I am going to explain my solution for a fully functional data table with sorting, searching, filtering and paging functionalities. For reaching my goal I am using ASP.NET MVC 2.0 with jQuery (http://jquery.com/)and the jqGrid (http://www.trirand.com/blog/)plugin. I was browsing the internet looking for a solution, but I was not able to find a complete working solution. To be more precise I found some solution, but they were always buggy with common errors for example using simple string sorting for all data types. Basically, this examples were using string comparison, which for example is not evaluating  correctly on dates or on integers. A concrete example: Given numbers from 1 to 15 the sorted result would be 1,10,11,12,13,14,15,2,3,4,5,6,7,8,9.

Today I would like only to publish the sample project, to explain how to set up and to show how to use it. In the near future I will also explain more in detail some tricky parts of my solution. Today I would like only to publish the sample project, to explain how to set up and to show how to use it. In the near future I will also explain more in detail some tricky parts of my solution.

The project can be downloaded by the following url:
http://cid-a8f4afb63c503b89.office.live.com/self.aspx/.Public/MvcJqGrid.zip
It is enough to unzip and to start the solution.

Have fun to investigate about my approach!

Tuesday, January 4, 2011

Framework für iPhone, iPod Touch und iPad Webapp

Sollte ein Entwickler eine Webseite oder eine Webapplikation für einen iPhone, iPod Touch und iPad entwickeln, so empfehle ich euch folgendes free open source Framework iWebKit (http://iwebkit.net/).
photoiWebKit besteht aus mehreren Dateien, welche Ihnen ermöglicht auf einfacher weiße eine kompatibel Website oder Webapplikation für iPhone, iPod Touch und iPad zu erstellen. Das Kit ist für jedem  zugänglich und sehr einfach zu verwenden. Außerdem es ist gut dokumentiert und es gibt auch genügend Beispiele. iWebKit ist ein großartiges Werkzeug, weil es sehr einfach zu bedienen, extrem schnell, kompatibel und erweiterbar ist.

Die folgende Seite wurde mit diesem Framework erstellt: http://www.provincia.bz.it/meteo/mobile/

Monday, January 3, 2011

LINQ & Expressions costruzione a runtime

Questo post vi servirà come un piccolo aiuto per capire meglio i miei post futuri che parleranno di jQuery (http://jquery.com/) è jqGrid (http://www.trirand.com/blog/). Qualche volta è necessario costruire una LINQ  query a runtime, che non è una cosa triviale. Per imparare e per avere un piccolo aiuto, io ho utilizzato un istrumento chiamato Expression Tree Visualizer (http://msdn.microsoft.com/en-us/library/bb397975(VS.90).aspx), che permette di vedere la costruzione delle espressioni. Expression Tree Visualizer lo trovate negli esempi di VS2008.

image

Praticamente ho prima scritto la LINQ query che mi interessava. Questa la ho analizzata con Expression Tree Visualizer è ho infine riscritto la stessa LINQ query utilizzando solamente le espressioni (costruzione di un expression tree). Perché tutta questa fatica? Per scrive LINQ a runtime.

Esempio:
Questa LINQ query

cells => cells["Description"].eq(cells["Description"].Create("Daniel"));
è stata trasformata in
ParameterExpression param = Expression.Parameter(typeof(Dictionary<string, GridCell>), "cells");
//cells["Description"]
ConstantExpression pKey = Expression.Constant("Description");
MethodCallExpression dicCall = Expression.Call(param, "get_item", null, pKey);
//cells["Description"]
ConstantExpression pKey1 = Expression.Constant("Description");
MethodCallExpression dicCall1 = Expression.Call(param, "get_item", null, pKey1);
//.Create("Daniel")
ConstantExpression pStrValue = Expression.Constant("Daniel");
MethodCallExpression createCall = Expression.Call(dicCall, "Create", null, pStrValue);
//operation 
MethodCallExpression eqCall = Expression.Call(dicCall1, "eq", null, createCall);

Infine vorrei fare farvi nottare, che per qualcuno di voi potrà essere abbastanza l’utilizzo di queste librerie Dynamic LINQ (http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx).

Wednesday, November 3, 2010

Log4Net: esempio di configurazione

Un piccolo suggerimento per chi di voi utilizza Log4Net (http://logging.apache.org/log4net/index.html) ma utile: Invece di utilizzare log4net.Appender.FileAppender sarebbe consigliato l’utilizzo di log4net.Appender.RollingFileAppender, che vi da decisivamente più funzionalità per esempio potete impostare la grandezza massima del file di log o anche potete specificare che il file venga rinominato con un “date pattern”.

Ecco un esempio di configurazione:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    <log4net debug="false">
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender, log4net">
            <file value="C:\xxx\xxx_Log4Net" />
            <appendToFile value="true" />
            <rollingStyle value="Composite" />
            <datePattern value=".yyyyMM'.log'" />
            <maxSizeRollBackups value="-1" />
            <maximumFileSize value="50MB" />
            <layout type="log4net.Layout.PatternLayout, log4net">
                <conversionPattern value="%d [%t] %-5p %c - %m%n" />
            </layout>
        </appender>
        <root>
            <priority value="ALL" />
            <appender-ref ref="RollingLogFileAppender" />
        </root>
    </log4net>
</configuration>

Qualche note:

Impostando la proprietà RollingStyle uguale a Composite istruisco a Log4Net che il file corrente si chiami xxx_Log4Net e i file successivi vengano denominati con il seguente pattern .yyyyMM'.log' (yy sta per anno e MM sta per mese). Per essere più esatti passato un mese il file corrente xxx_Log4Net verrà rinominato a xxx_Log4Net.yyyy.MM.log. Inoltre se il file supera la grandezza di 50Mb verrà creato un nuovo file con il nome xxx_Log4Net.1.

Tuesday, October 26, 2010

How to post your source code on blogspot

I am using SyntaxHighlighter (http://alexgorbatchev.com/SyntaxHighlighter/) for formatting and highlighting source code on blogspot and I will explain in this post step by step how to set it up. Btw: For writing my blogs I am using Windows Live Writer with the plug-in Precode (http://precode.codeplex.com/) which gives support for SyntaxHighlighter and snippet indentation.

1) From the navigation menu of blogspot select DesignEdit HTML. Add following lines:




2) For posting a piece of c# source code it is enough to wrap it between:

source code

HAPPY POSTING!!