Using StructureMap with ASP.NET WebForms

StrutctureMap is one of the most popular IoC containers in .NET but I had never tried it out. You can learn all about StructureMap from the documentation and the tutorials already available so I won't try to explain what it is and how it works. Instead I'll show you my experience on how to use it with ASP.NET WebForms.

To test StructureMap I decided to use it in my blog which is a simple WebForms application that is now using NHibernate. The objective is use in the code only the interfaces for my Services and DAOs. Their implementation should be injected.

The first step is to create a class that will be responsible for initializing the IoC. I decided to create this class at the WebSite level in the App_Code folder because this class has dependencies on all the other assemblies. Since the WebSite has to reference all these assemblies I figured this would be the best place. Here is the code for the class:

public class IocConfigurator
{
    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IPostDao>().TheDefault.Is.
                OfConcreteType<PostDao>();
            x.ForRequestedType<ICategoryDao>().TheDefault.Is.
                OfConcreteType<CategoryDao>();
            x.ForRequestedType<ICommentDao>().TheDefault.Is.
                OfConcreteType<CommentDao>();
            x.ForRequestedType<IAuthorDao>().TheDefault.Is.
                OfConcreteType<AuthorDao>();
            x.ForRequestedType<ITagDao>().TheDefault.Is.
                OfConcreteType<TagDao>();
            x.ForRequestedType<IFrontEndService>().TheDefault.Is.
                OfConcreteType<FrontEndService>();
            x.ForRequestedType<IAdminService>().TheDefault.Is.
                OfConcreteType<AdminService>();

            x.SetAllProperties(y =>
                                   {
                                       y.OfType<IFrontEndService>();
                                       y.OfType<IAdminService>();
                                   });
        });
    }
}

 Now we have to class this IocConfiguration class in order to make all the initialization. The best place to do this is in the Global.asax in the Application_Start event.

<%@ Application Language="C#" %>
<%@ Import Namespace="StructureMap"%>

<script runat="server">

    void Application_Start(object sender, EventArgs e) 
    {
        IocConfigurator.Configure();
    }
    
...    
</script>

 Top-Down resolution

Ok, now let's deal with how to inject the services in the Pages. Let's continue using the IFrontEndService as our example. We could do something simple like:

IFrontEndService service = ObjectFactory.GetInstance<IFrontEndService>();

But this is not a recommend approach as you can see in the StructureMap Quickstart. You should minimize the GetInstance calls and let auto wiring do the job for you. Unfortunately WebForms doesn't make that easy. For that reason the team created the BuildUp feature that let's you inject the dependencies into an object that was already built.

In order to do the BuildUp into a single place I posted the code into the BasePage constructor. This class derives from the Page class and all the pages in my application derive from it instead of from the Page as would be usual.

namespace SpeakOut.Lib.Web
{
    public class BasePage : Page
    {
        public BasePage()
        {
            ObjectFactory.BuildUp(this);
        }
    }
}

Here is a page using the BasePage:

public partial class _Default : BasePage 
{
    public IFrontEndService Service { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            RepeaterPosts.DataSource = Service.GetRecentPosts(10);
            RepeaterPosts.DataBind();
        }
    }
    protected void RepeaterPosts_ItemCreated(object sender, RepeaterItemEventArgs e)
    {
        Post post = (Post) e.Item.DataItem;
        PostDetailsControl control = (PostDetailsControl) e.Item.FindControl("PostDetailsControl1");
        control.Post = post;
    }
}

The BuildUp method will look for properties of the type I have registered in the IoC Configuration and will inject the properties with the correct implementation. The registration of the type of properties that should be injected is a special part of the IoC setup. In our configuration class it is at the very end of the Configure method with this syntax:

x.SetAllProperties(y =>
                       {
                           y.OfType<IFrontEndService>();
                           y.OfType<IAdminService>();
                       });

 With this StructureMap will take care of all the dependency injection for you. Including injecting the DAOs into the Service. In order for the DAOs to be injected all you need to do is to define a constructor that receives all the values you want to have injected. When StructureMap creates the Service it will look for the constructor with most parameters (the greediest). If it sees that it has all the parameters in the configuration it will automatically create the necessary objects and pass them to the constructor.

    public class FrontEndService : IFrontEndService
    {

        private readonly IPostDao _postDao;
        private readonly ICategoryDao _categoryDao;

        public FrontEndService(IPostDao postDao, ICategoryDao categoryDao)
        {
            _postDao = postDao;
            _categoryDao = categoryDao;
        }
...

 That makes the creation of a tree of objects really simple and your code doesn't need to know anything about the interface implementations.

You can get the whole implementation from the SpeakOut Codeplex Project.

From Entity Framework to NHibernate

Recently I decided to change the data access layer in my blog from Entity Framework to NHibernate. In this post I'll tell you Why and How I did it.

The WHY

I still have some issues with the current version of the Entity Framework as I posted in the article MVC Storefront: Migrating to the Entity Framework. Many of the things I wanted to do with the EF like using POCOs or LazyLoading will be possible in version 4. Until then I decided to give NHibernate a shot. I figured it wouldn't be so hard since I already had some knowledge with Hibernate from my Java days.

The HOW

 The migration was not that hard. NHibernate has a great documentation with good examples. I also used the NHibernate in Action book which I highly recommend. It is only 400 pages and very to the point.

How the Project is Structured

I have a Website and 4 assemblies:

SpeakOut.Data: This is where the DAOs live, both their interface and implementation. Also in this assembly are the NHibernate mapping files.

SpeakOut.Model: This assembly has all the domain model entities. I had to make minor changes to these classes to get them to work best with NHibernate. The collections for instance were changed to use IList<T> instead of the IEnumerable<T> I was using with the EF.

SpeakOut.Service: This assembly has services (Interfaces and Implementations) that are used by the presentation layer.

SpeakOut.Lib: Here are all the utility classes, base classes for the pages and control and classes with extension methods.

The Model

This is the class diagram for the classes in the model. NHibernate makes populating the dependencies show in the diagram really easy, actually you don't do anything and you still get the benefit of lazy loading for free. This is something that wasn't easy in the EF.

The Mapping Files

Here are the mapping files for my entities.

Author

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SpeakOut.Model"
                   namespace="SpeakOut.Model">
  <class name="Author">
    <id name="AuthorId">
      <generator class="guid"/>
    </id>
    <property name="Name"/>
    <property name="Login"/>
    <property name="Password"/>
    <property name="Email"/>
    <property name="IsAdmin"/>
    <bag name="Posts" access="field.camelcase-underscore" inverse="true" cascade="all-delete-orphan">
      <key column="AuthorId"/>
      <one-to-many class="Post"/>
    </bag>
  </class>
</hibernate-mapping>

Post

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SpeakOut.Model"
                   namespace="SpeakOut.Model">
  <class name="Post">
    <id name="PostId">
      <generator class="guid"/>
    </id>
    <property name="Title"/>
    <property name="Body"/>
    <property name="Permalink"/>
    <property name="Published"/>
    <property name="PublishDate"/>
    <bag name="Comments" access="field.camelcase-underscore" inverse="true" cascade="all-delete-orphan">
      <key column="PostId"/>
      <one-to-many class="Comment"/>
    </bag>
    <bag name="Tags" access="field.camelcase-underscore" inverse="true" cascade="all-delete-orphan">
      <key column="PostId"/>
      <one-to-many class="Tag"/>
    </bag>
    <bag name="Categories" access="field.camelcase-underscore" table="CategoryPost">
      <key>
        <column name="PostId" not-null="true"/>
      </key>
      <many-to-many class="Category">
        <column name="CategoryId" not-null="true"/>
      </many-to-many>
    </bag>
    <many-to-one name="Author" column="AuthorId" not-null="true"/>
  </class>
</hibernate-mapping>

Comment

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SpeakOut.Model"
                   namespace="SpeakOut.Model">
  <class name="SpeakOut.Model.Comment">
    <id name="CommentId">
      <generator class="guid"/>
    </id>
    <property name="Author"/>
    <property name="Body"/>
    <property name="Email"/>
    <property name="Website"/>
    <property name="Country"/>
    <property name="Ip"/>
    <property name="IsApproved"/>
    <property name="CreatedAt"/>
    <many-to-one name="Post" column="PostId" not-null="true"/>
  </class>
</hibernate-mapping>

Tag

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SpeakOut.Model"
                   namespace="SpeakOut.Model">
  <class name="Tag">
    <id name="TagId">
      <generator class="guid"/>
    </id>
    <property name="Name"/>
    <many-to-one name="Post" column="PostId" not-null="true"/>
  </class>
</hibernate-mapping>

Category

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SpeakOut.Model"
                   namespace="SpeakOut.Model">
  <class name="Category">
    <id name="CategoryId">
      <generator class="guid"/>
    </id>
    <property name="Name"/>
    <bag name="Posts" table="CategoryPost">
      <key>
        <column name="CategoryId" not-null="true"/>
      </key>
      <many-to-many class="Post">
        <column name="PostId" not-null="true"/>
      </many-to-many>
    </bag>
  </class>
</hibernate-mapping>

 The Data Access

 In the data access layer I decided to drop the Repository I was using to go with simple DAOs. The main reason I did it was to test NHibernate as recommended by it's more experienced users. I really think I wouldn't get a lot from the Repository.

Here is the class diagram for the DAOs interfaces:



One of the approaches suggested in the NHibernate in Action book is to use a base DAO that encapsulate the common behavior in all NHibernate DAOs. Here is the code for the this class:
 

namespace SpeakOut.Data.NHibernate.Daos
{
    public class BaseDao<T> : IBaseDao<T>
    {
        private ISession _session;

        protected ISession Session
        {
            get
            {
                if (_session == null)
                {
                    _session = NHibernateHelper.GetCurrentSession();
                }
                return _session;
            }
        }

        public T FindById(Guid id)
        {
            return Session.Load<T>(id);
        }

        public T FindByIdAndLock(Guid id)
        {
            return Session.Load<T>(id, LockMode.Upgrade);
        }

        public IList<T> FindAll()
        {
            return Session.CreateCriteria(typeof (T)).List<T>();
        }

        public T MakePersistent(T entity)
        {
            Session.SaveOrUpdate(entity);
            return entity;
        }

        public void MakeTransient(T entity)
        {
            Session.Delete(entity);
        }
    }
}

 All the DAOs derive from this BaseDao and get all the basic functionality. The specialized DAOs are left to implement the functionality that is directly related to them. Look at how simple the implementation of the AuthorDao is:

namespace SpeakOut.Data.NHibernate.Daos
{
    public class AuthorDao : BaseDao<Author>, IAuthorDao
    {
        public Author FindByLogin(string login)
        {
            return Session.CreateCriteria<Author>()
                .Add(Expression.Eq("Login", login).IgnoreCase())
                .UniqueResult<Author>();
        }
    }
}

 One aspect to pay attention to is how the NHibernate Session works when you have an ASP.NET application. The easiest way to deal with this is to create an HTTP Module that creates a session that will live as long as the duration of the Request. When the Request ends the Transaction is committed and the Session is released. A similar strategy is described in this post.

 Here is the implementation of the HTTP Module.

public class NHibernateCurrentSessionWebModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += Application_BeginRequest;
        context.EndRequest += Application_EndRequest;
    }

    public void Dispose()
    {
    }

    private void Application_BeginRequest(object sender, EventArgs e)
    {
        ISession session = NHibernateHelper.OpenSession();
        session.BeginTransaction();
        CurrentSessionContext.Bind(session);
    }

    private void Application_EndRequest(object sender, EventArgs e)
    {
        ISession session = CurrentSessionContext.Unbind(NHibernateHelper.SessionFactory);

        if (session == null) return;

        try
        {
            session.Transaction.Commit();
        }
        catch (Exception)
        {
            session.Transaction.Rollback();
        }
        finally
        {
            session.Close();
        }
    }
}

Since this module creates the Session and the Transaction we need a way to access these resources. This is done by a helper class like this:

namespace SpeakOut.Data.NHibernate
{
    public static class NHibernateHelper
    {
        public static readonly ISessionFactory SessionFactory;

        static NHibernateHelper()
        {
            try
            {
                Configuration configuration = new Configuration();
                configuration.AddAssembly("SpeakOut.Data");
                SessionFactory = configuration.Configure().BuildSessionFactory();
            }
            catch (Exception ex)
            {
                throw new Exception("NHibernate initialization failed", ex);
            }
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }

        public static ISession GetCurrentSession()
        {
            return SessionFactory.GetCurrentSession();
        }
    }
}

There are two important things about this class. The first is AddAssembly method being called in the static constructor. I have to pass the name of the assembly that contains the NHibernate Mappings. In this project all the mappings are in the Speakout.Data assembly. The second important point is the GetCurrentSession which is the method that will be used in all the DAOs to get the Session already created in the HTTP Module.

More info about configuring NHibernate when using several assemblies can be found here.

The Configuration

Since I'm using a WebSite all the NHibernate configuration is done in the Web.Config. First a section is defined in the ConfigSections node:

<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"/>

And the create the configuration node:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">
      Server=(local);initial catalog=your_catalog;user id=your_user;password=your_pass
    </property>
    <property name="adonet.batch_size">10</property>
    <property name="show_sql">true</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="use_outer_join">true</property>
    <property name="command_timeout">60</property>
    <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
    <property name="current_session_context_class">web</property >
  </session-factory>
</hibernate-configuration>

 Final Words

I hope my implementation may help you. It simple and small enough that you can go through it very quickly and get a base understanding of what you need to get NHibernate going.

I'll probably give the Entity Framework another chance once my hosting starts to support EF 4. After all changing and trying, and failing and learning is exactly what this blog is all about.

You can get all the source code for this project at Codeplex.

How to Match Date without Time in NHibernate

I'm changing my blog to use an NHibernate data layer. I'll post about this experience soon.

One thing I think is worth mentioning is how to write a query to filter by date only. Yes, I want to ignore the time part of the date class. I new to NHibernate and I thought that there would be a function to do this. Well there isn't. There is nothing bad about this I just wanted to write about it to let others find the recommended solution to solve this problem.

The way to do it is by using BETWEEN and comparing the hour zero (00:00:00) of the day and the last second of the day (23:59:59).

Here is an example where I need to find all posts published in a given date:

public IList<Post> FindByDate(DateTime datePublished)
{
    DateTime initDate = datePublished.Date;
    DateTime endDate = datePublished.Date.AddDays(1).AddSeconds(-1);
    return Session.CreateCriteria<Post>()
        .Add(Expression.Between("PublishDate", initDate, endDate))
        .List<Post>();
}

 And here is the same example using HQL:


public IList<Post> FindByDate(DateTime datePublished)
{
    DateTime initDate = datePublished.Date;
    DateTime endDate = datePublished.Date.AddDays(1).AddSeconds(-1);
    string hql = "from Post where PublishDate between :initDate and :endDate";
    return Session.CreateQuery(hql)
        .SetDateTime("initDate", initDate)
        .SetDateTime("endDate", endDate)
        .List<Post>();
}

Very simple. My only doubt was if there were any other way to do this. I found a discussion on the NHibernate group where Ayende says that this is the way to do it. Case closed :-)

 

ELMAH: Error logging doesn't get any simpler

ELMAH stands for Error Logging Modules and Handlers. I don't love the name but everything else about it is great!! In it's site it is described as:

"ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment."

I'm using this blog as I write it and if I had to classify it I'd say it is a pre pre alpha release not suitable for anyone else but me. The only use I see for other people right now is to look around the code (what should be quick). Given my choice to put the application online in this early stage it seamed pretty obvious that that I needed to start logging the errors my users are getting so that I can work on them as soon as possible. As usual I was deciding between using NLog or Log4Net when I saw a new post by Scott Hanselman talking about ELMAH.

As usual Scott's post saved me a lot of time! Setting up ELMAH was really as simple as he said. In a matter of minutes I was logging all errors in my application. Now I can sleep well knowing that every weekend I'll have a list of errors to work on :-)

I highly recommend you use this in your application even if you are already using another logging framework. The cool thing about ELMAH is that if you missed something forgot to place logging on some part of your app, ELMAH won't. It will log every error you have and store it in XML, SQLServer, Oracle...

Lessons Learned in Url Rewriting

When I decided to write my own blog and leave Mephisto one of the few requirements I felt were really important was to maintain the url pattern I was already using. My articles had url's like this:

www.gbogea.com/year/month/day/permalink

When I first looked up url rewriting in google I found a great article by ScottGu that really suited my needs. I'm using IIS7 on my develpment machine and I thought I was also using it on the hosting service I contracted. ScottGu's post shows a really simple way to do rewriting when using IIS7. All you need is the UrlRewriter.Net module and a few configurations to your web.config.
Checkout SocottGu's post for the whole config, here I'll only show you the pattern I needed to be compatible with the articles url in Mephisto. Here it is:

<rewrite url="~/((19|20)\d\d)/(0?[1-9]|1[012])/(0?[1-9]|[12][0-9]|3[01])/(.+)" to="~/PostDetail.aspx?year=$1&amp;month=$3&amp;day=$4&amp;permalink=$5"/>

Once I did this everything worked fine. I had achieved my objective, or so I thought. The problem is that I found out later on that my hosting service was actually using IIS6 and to my sadness IIS6 doesn't do well with url's that do not have an extension.

When I contacted my hosting they informed me that they had support for ISAPI Rewrite, which is alson discussed in Scott's post but sadly not in engough depth for my case. The configuration is also a lot more anoying then with UrlRewrite.Net. If you have to use ISAPI Rewrite my first recomendation is to get in touch with your hosting and find out if they have version 2 or 3 installed. It makes a great difference. In my case I had version 3 installed. Here are the steps I took to configure it:

1 - Create a ".htaccess" file in the root or your web application.

2 - In the file I've written the following code:

RewriteEngine on
RewriteBase /
RewriteRule ((19|20)\d\d)/(0?[1-9]|1[012])/(0?[1-9]|[12][0-9]|3[01])/(.+)$ /PostDetail.aspx?year=$1&month=$3&day=$4&permalink=$5 [NC,L]


The rewrite rule is basically translating the pattern I'm using (www.gbogea.com/year/month/day/permalink) to the real pattern that the ASP.NET applcation understands (PostDetail.aspx?year=YYYY&month=MM&day=DD&permalink=WHATERVER).

The options and the end are also very important. NC means Case Insensitive. L means that no other subsquent rule should be processed, it stops here. You will find a lot of examples that use an R (which means Redirect) however this was not suited to my case. The redirect would be done to the new URL and then the url shown in the browser would be the ASP.NET url and not mine.

This usage was not easy to figure out. If you need any assistance on using ISAPIRewrite I can recomend this two links:

Documentation: http://www.helicontech.com/isapi_rewrite/doc/
Blog: http://helicontech.blogspot.com/search/label/isapi_rewrite

Helicon's blog was the one that helped me the most. The have a post about common issues people have which is really to the point.

Looking back at all the work I had it would probably be cheaper just to have my hosting plan upgraded to IIS7 but where would be the fun in that right? Joking aside, it's this kind of thing that make you learn, perhaps your client doesn't have the option to migrate to IIS7, then what would you do? Having said that, if you have the choice between using IIS 6 and 7 I would definitely go with 7 and avoid using ISAPI Rewrite altogether.

If you want to have a closer look at my web.config or the .htaccess file you can look at the source code for this blog at speakoutblog.codeplex.com. At this time there is no realease version yet but you can go to the source code and download any commit you want.