Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Sunday, July 24, 2011

Putting it all together: ASP.NET MVC, SQLite, NHibernate, Fluent NHibernate & Log4Net

Today, I will explain how to set up a ASP.NET MVC project, which is using NHibernate for accessing a SQLite Database and Fluent NHibernate for configuring NHibernate. In this post I will give you a general overview about the structure of the project and in my future posts I will explain more in detail single its parts.

The sample project which can be downloaded from the following link http://dl.dropbox.com/u/36200417/MvcNhibernate.zip was setup as explained below.

The project is divided in two subprojects:
a)    MVC Web application
b)    DAL (Data Access Layer)

In a real project I would have more layers and subprojects, but for this example I want to keep it simple and therefore I removed the business layer.

First I was referencing all needed dlls:
- fluentnhibernate-NH3.0-binary-1.2.0.694
- log4net
- NHibernate-3.0.0.GA-bin
- SQLite-1.0.66.0-binaries

Afterwards I was generating a Database with the following command:sqlite3 test.db.

Copying the test.db file to the App_Data folder and adding the following connection string allows Asp.Net to access the SqLite Database.

<connectionStrings>
  <add name="SqLiteCon" connectionString="data source=|DataDirectory|test.db;" />
</connectionStrings>

Let’s now investigate on the structure of the project:

Project DAL:
/DAO: Data Access Objects provide abstract interfaces to a persistence medium like a database
/DAO/Interface: Interfaces for DAOs
/DAO/Implementation: Concrete implementation that provides access to the database with NHibernate. Note: BasicNhDAO<T, EntityKey> is a base class that provides basic functions (=CRUD). For every entity a DAO object exists, that is responsible for persisting the entity.
/Entities: Plain objects for encapsulating data.
/Entities/Interface: Interfaces for the plain objects
/Entities/Implementation:
/Mapping: FluentNHibernate Mappings, which are containing information how to map entities to tables of a database.
/SessionStorage: small framework for managing the NHibernate Session.

Project MvcNhibernate:
/App_Data: contains the SqLite database file
/Controllers: MVC Controllers. SqLiteController contains the logic for this example.
/Views/SqLite: MVC Views that are interesting for this example.

Thursday, July 21, 2011

ASP.NET MVC 3.0: CheckBoxListFor

Salve sviluppatori! È passato diverso tempo dal mio ultimo blog in italiano, perciò eccovi un metodo assolutamente utile per chi di voi sviluppa applicazioni web con ASP.NET MVC. Il metodo, che oggi vi propongo, serve per mostrare una lista di caselle di controllo (="Checkboxes"). Ricapitolando nel "Controller" vengono preparati i dati che verranno incorporati in un oggetto (="Model"), che poi verranno passati ed elaborati da una "View". Il metodo, che oggi vi presento, verrà utilizzato nella "View" ed estende la classe "HtmlHelper".

public static MvcHtmlString CheckBoxListFor<TModel, TKey, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IDictionary<TKey, TValue>>> expForAvailableItems, Expression<Func<TModel, IList<TKey>>> expForSelectedKey)
{
    return CheckBoxListFor(htmlHelper, expForAvailableItems, expForSelectedKey, x => Convert.ToString(x), x => Convert.ToString(x), null, null);
}

public static MvcHtmlString CheckBoxListFor<TModel, TKey, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IDictionary<TKey, TValue>>> expForAvailableItems, Expression<Func<TModel, IList<TKey>>> expForSelectedKey, Expression<Func<TValue, string>> expForValueToString, Expression<Func<TKey, string>> expForKeyToString, IDictionary<String, Object> htmlAttributesForListDiv = null, IDictionary<String, Object> htmlAttributesForItemDiv = null)
{
    //the name for the checkbox 
    string name = ExpressionHelper.GetExpressionText(expForSelectedKey);
    string HtmlName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
    if (String.IsNullOrEmpty(HtmlName))
    {
        throw new NullReferenceException("HtmlName is null");
    }

    //available items
    IDictionary<TKey, TValue> availableItems = expForAvailableItems.Compile().Invoke(htmlHelper.ViewData.Model);

    //selected items
    IList<TKey> selectedItems = expForSelectedKey.Compile().Invoke(htmlHelper.ViewData.Model);

    //convert value to string function
    Func<TValue, string> funcValueToString = expForValueToString.Compile();

    //convert key to string function
    Func<TKey, string> funcKeyToString = expForKeyToString.Compile();

    //Convert to checkboxlist
    TagBuilder listDiv = new TagBuilder("div");
    listDiv.MergeAttributes(htmlAttributesForListDiv, true);

    StringBuilder listItemsBuilder = new StringBuilder();
    // Define items
    // Loop through items
    Int32 index = 0;
    foreach (var item in availableItems)
    {
        // Define div
        TagBuilder inputdiv = new TagBuilder("div");
        inputdiv.MergeAttributes(htmlAttributesForItemDiv, true);

        // Define input 
        TagBuilder input = new TagBuilder("input");
        if (selectedItems.Contains(item.Key))
            input.MergeAttribute("checked", "checked");
        input.MergeAttribute("id", String.Concat(name, index));
        input.MergeAttribute("name", name);
        input.MergeAttribute("type", "checkbox");
        input.MergeAttribute("value", funcKeyToString(item.Key));

        // Define label
        TagBuilder label = new TagBuilder("label");
        label.MergeAttribute("for", String.Concat(name, index));
        label.SetInnerText(funcValueToString(item.Value));

        // Add item
        inputdiv.InnerHtml = String.Format("{0}{1}", input.ToString(TagRenderMode.SelfClosing), label.ToString(TagRenderMode.Normal));
        listItemsBuilder.Append(inputdiv.ToString(TagRenderMode.Normal));
        index++;
    }

    // Return list
    listDiv.InnerHtml = listItemsBuilder.ToString();
    return MvcHtmlString.Create(listDiv.ToString());
}

Nel "Controller" come già accennato prima vengono preparati i dati. Nel "Model" devono esistere un dizionario del tipo IDictionary<TKey, TValue> e una IList<TKey>. Il dizionario contiene tutti gli possibili elementi che verranno mostrati come caselle di controllo (="checkboxes"); la lista contiene le chiavi delle caselle di controllo selezionate.

[HttpGet]
[Authorize]
public ActionResult Edit()
{
    DataModel model = new DataModel();
    model.AvailableItems = DAO.GetAvailableItems().ToDictionary(x => x.ID, x => x.Desc);
    model.SelectedItems = DAO.GetSelectedItems().ToList(x => x.ID);
    return View(model);
}

Nella "View" per mostrare le caselle di controllo (="Checkboxes") basta chiamare la funzione ("CheckBoxListFor") e passare ad essa il dizionario e la lista che si trovano nel "Model". Non dimenticatevi di importare il "Namespace"!

<%@ Import Namespace="CuMvcApi.Helpers.HTML" %>

<%: Html.CheckBoxListFor(x=>x.AvailableItems, y=>y.SelectedItems) %>

Spero, che vi sia piaciuto questo articolo e che vi sia utile per il vostro lavoro!

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!

Monday, September 20, 2010

Performanceprobleme??? Hier die Lösung

Jeder seriöse Webentwickler sollte den Artikel “Best Practices for Speeding Up Your Website” (http://developer.yahoo.com/performance/rules.html) von Yahoo Developer Network kennen.
Hier nochmals eine kleine Zusammenfassung der wichtigsten Regeln:

  • Minimieren Sie HTTP-Requests
    • Alle Script Dateien sollten zu einer großen Script Datei zusammengeführt werden, das gleich gilt für CSS Dateien.
  • Verwenden Sie einen Content Delivery Network
  • Verwenden Sie eine Expires oder Cache Header
  • Verwenden Sie Gzip Components
  • Referenzieren Sie Stylesheets im Header
  • Referenzieren Sie Scripts auf der Unterseite
  • Vermeiden Sie CSS Ausdrücke
  • Script und CSS sollten in externen Dateien vorliegen
  • Reduzieren Sie DNS-Lookups
  • Verkleinern Sie Script und CSS Dateien
    • Entfernen Sie unnötige Zeichen (Leerzeichen, Zeilenumbruch und Tabulator)
    • Entfernen Sie Kommentare und unnötigen Code

Nachdem wir ein bisschen die Theorie aufgefrischt haben nun die Praxis:
Die NET-Bibliothek COMBRES (http://combres.codeplex.com/) ermöglicht das Verkleinern, die Kompression und die Kombination von Script und CSS Dateien. Zudem erlaubt diese das Zwischenspeichern (= Caching) von Script und CSS Ressourcen für ASP.NET und ASP.NET MVC Web-Anwendungen.

Thursday, August 5, 2010

Localize ASP.NET MVC 2 DataAnnotations validation messages with a custom resource provider

The problem

If in ASP.NET applications you are using a Customized Resource Provider and System.ComponentModel.DataAnnotations for validating your model, then you will have problems to localize messages. To be more precise, I am using a Database Resource Provider, which I wrote some years ago, for pulling localization information from a Database and to localize, in this way, ASP.NET and ASP.NET MVC Web Applications. Data Annotations are using two properties for localizing messages, ErrorMessageResourceType and ErrorMessageResourceName, which accept a Type (i.e. a compiled resource file) and a String respectively. Having a Customized Resource Provider (= Database Resource Provider) does not allow me to specify a Type for the ErrorMessageResourceType, since resources are not compiled.

Approaches to solve the problem:

  1. Writing a Custom Build Provider, which compiles resources from the Database.
  2. Creating a Dynamic Object, which transforms the property name to a key for the Resource Manager.
  3. Extending Attributes of Data Annotations.
  4. Using a T4 Template for generating a class containing the resources.

First approach

The Idea was to have a Custom Build Provider (namely DataBaseResourceBuildProvider) for compiling resources that are in a Database. So I started with a simple implementation. During this task I want to underline, that the tool CodeDom Assistant (http://www.codeproject.com/KB/cs/codedom_assistant.aspx) was helping me a lot, since I could convert some pieces of source code into a CodeDom object. Finally I registered the Build Provider in my web.config file and I found out that it is not working. It took me some time to find out that adding a Customized Build Provider class to the web.config file works in an ASP.NET Web Site but does not work in an ASP.NET Web Application project. In a Web Application project, the code that is generated by the Build Provider class cannot be included in the application. This information I found in Microsoft MSDN (http://msdn.microsoft.com/en-us/library/system.web.compilation.buildprovider.aspx). I was very surprised and angry about this, therefore abandoned this approach and moved on to the second one.

Second approach

My second approach was to create a Dynamic Object and to encapsulate the call to the Resource Manager in a general implementation. Basically, the idea was that you can call any property that you want on this object, even if this property was not explicitly defined. In the background the property name would be used as a key for retrieving the resources. First, I extended the class System.Dynamic.DynamicObject and I overrode the function TryGetMember. This is a sketch of the implementation:

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    result = HttpContext.GetLocalResourceObject("", "Resource_KEY822.Title") as string
    return (result != null);
}

It turned out that the Data Annotations needs static property for retrieving resources, and therefore I discarded this approach.

Third approach

I tried to avoid this approach, because I would have had to extend several classes, which requires time. It consists to extend all Attributes of Data Annotations and to write some logic for displaying localized messages. To show that it works, I extended on Attribute, namely the DisplayNameAttribute. This is a sketch of the implementation:

public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    public LocalizedDisplayNameAttribute(string displayNameKey)
        : base(displayNameKey)
    {
    }
    
    public override string DisplayName
    {
        get
        {
            string s = HttpContext.GetLocalResourceObject("", base.DisplayName) as string;
            if (string.IsNullOrWhiteSpace(s))
                return base.DisplayName;
            else
                return s;
        }
    }
}

Fourth approach and Solution

I use T4 Template for generating a wrapper class, which encapsulates all resources of the Database as properties. To be more precise, I generate a property with the name of the key of the resource in the Database. In this way, I generate a class where every property corresponds to a call to the Resource Manager that, given the key, returns the localized resource message. Moreover, I generate a constant of type String, whose name is composed of a prefix Prop and the key. The value of the constant is the name of the property. Having constants and properties allows me to use Data Annotations for validating my model: for the property ErrorMessageResourceType I will pass the type of my generated class; for the property ErrorMessageResourceName I will set it to the constant that encapsulates the name of the property. I would like to emphasize that properties have to be declared as static for working with Data Annotations. Using constants for specifying the ErrorMessageResourceName has the following two fundamental advantages:

  1. Using of IntelliSense
  2. Error detection at compile time

The following example shows a sketch of the T4 Template:

public class Resources
{
<#
string connectionString = CurrentConnectionStrings["xxx"].ConnectionString;
string providerName = CurrentConnectionStrings["xxx"].ProviderName;
string applicationName = CurrentApplicationName["xxx"].Value;
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
DataBaseResourceProvider provider = new DataBaseResourceProvider(applicationName, connection);
foreach (DictionaryEntry entry in provider.ResourceReader)
    {
        string propName = createUnderscore(Convert.ToString(entry.Key));
        WriteLine(string.Format("    public const string Prop_{0}=\"{1}\";", propName, propName));
        WriteLine(string.Format("    public static string {0}", propName));
        WriteLine("    {");
        WriteLine("        get { return HttpContext.GetLocalResourceObject(\"a\", \""+Convert.ToString(entry.Key)+"\") as string; }");
        WriteLine("    }");
        WriteLine("");
    }
#>    
}

Thursday, July 29, 2010

ASP.NET MVC Suggerimento: Compilare le "View"!

Una cosa fondamentale subito dopo avere creato un progetto ASP.NET MVC è di modificare il file *.csproj aprendolo con un semplice editore di testo e aggiungere all’ elemento <PropertyGroup> la seguente riga: <MvcBuildViews>true</MvcBuildViews>

Il vantaggio fondamentale nel compilare le “views” è di individuare gli errori di sintassi.  In questo modo evitiamo di individuare questi tipi di errore a “runtime”. Naturalmente questa impostazione comporta, che la compilazione del progetto richieda un po’ più di tempo. Se questo per voi non è accettabile potete impostare la compilazione delle “views” solamente per la versione “release” . Io personalmente ho impostato questo settaggio sia per versione “release” che anche per la versione “debug” .