Mar 28, 2012

ASP.NET MVC extension points in action

Recently I made a tech talk about my alt.net web stack of love. It has lots of things there. Validation, NHibernate, Routing etc. So here are slides:

Source code for it is on bitbucket. Its purpose is just see it all in action. If you want, you should move code your new/old projects. Don’t try to make some type of project template out of it.

To try things out

Once again link to sources.

I was asked to give some kind of practice task to try all stack together. So here it is:

Implement blog details page to show posts inside it. So when I open localhost/blogs/3 I should see something like:

untitled_page

When I navigate to post details page I should be able to see post content and leave comments. Just like on this blog Smile.

Mar 5, 2012

Using ASP.NET MVC 4 WebAPI with NHibernate and Autofac

Wanted to try how they play together. So it will yet another tutorial with sample application built from scratch. First of all I don’t want to manage ISession and ISessionFactory lifetime manually, so I’ll use Autofac to do the job. So after creating new Web API project execute following commands in nuget console:

Uninstall-Package EntityFramework
Install-Package NHibernate
Install-Package Autofac.Mvc3

First remove EntityFramework, then install NHibernate and Autofac.Mvc3 package. The last package has some really useful extensions like implementation of dependency resolver for MVC and instance per web request life style. Now setup autofac:

var builder = new ContainerBuilder();
// Register ISessionFactory as Singleton 
builder.Register(x => NHibernateConfigurator.BuildSessionFactory())
    .SingleInstance();
// Register ISession as instance per web request
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession())
    .InstancePerHttpRequest();

// Register all controllers
builder.RegisterAssemblyTypes(typeof(ProductsController).Assembly)
    .InNamespaceOf<ProductsController>()
    .AsSelf();

// override default dependency resolver to use Autofac
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));

// this override is needed because WebAPI is not using DependencyResolver to build controllers 
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
    DependencyResolver.Current.GetService, 
    DependencyResolver.Current.GetServices);

This code is executed one time on Application start. I won’t put code for domain (its simple one entity) and NHibernateConfigurator class you can find them on github.

Now we are ready to add our first controller that is going to expose web api:

public class ProductsController : ApiController
{
    private readonly ISession nhSession;

    public ProductsController(ISession nhSession)
    {
        if (nhSession == null) throw new ArgumentNullException("nhSession");
        this.nhSession = nhSession;
    }

    public IQueryable<Product> Get()
    {
        return nhSession.Query<Product>();
    }
}

Notice that I don’t need to do anything to get the ISession instance. Autofac will find that in order to get it it needs ISessionFactory and will configure factory first to give ISession for controller. Now we can visit url http://localhost:54270/api/products and see our list of products in XML format. Notice that because returned type is IQueryable request to http://localhost:54270/api/products?$top=1&$skip=0 will return only first product from the list.

PUT, POST and DELETE methods are pretty straight forward and won’t be different from the same in entity framework. So I won’t cover it. The last thing I want to try is transaction management. In mvc projects I used to do it with action filter. Here is slight catch involved. There are two ActionFilterAttribute classes. One in System.Web.Http.Filters and other is in System.Web.Mvc. In order to get working in webapi we need to implement the one in System.Web.Http.Filters namespace. So the implementation is the following:

using System.Data;
using System.Web.Mvc;
using NHibernate;
using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;

namespace webapi.Infrastructure
{
    public class TransactionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            base.OnActionExecuting(actionContext);
            DependencyResolver.Current.GetService<ISession>().BeginTransaction(IsolationLevel.ReadCommitted);
        }

        public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
            ITransaction currentTransaction = DependencyResolver.Current.GetService<ISession>().Transaction;

            try
            {
                if (currentTransaction.IsActive)
                    if (actionExecutedContext.Exception != null)
                        currentTransaction.Rollback();
                    else
                        currentTransaction.Commit();
            }
            finally
            {
                currentTransaction.Dispose();
            }
        }
    }
}

I’ve put all the code there just be sure that you can figure out all required namespaces. The last thing I want to notice here is that if you implement System.Web.Mvc version of action filter, you won’t see any error messages or exceptions. Your filter just won’t work.

All code you can find here.

Mar 1, 2012

Convert tfs repository to mercurial

The easiest way I’ve found to do it is the following:

  1. With the help of git-tfs tool convert tfs repository to git one with the following command:
    git tfs clone %FullUrlToYourTfsServer% $/%PathToProject%

    I suggest you to verify that your network connection to TFS is stable because this operation will take a lot of time and if it fail you will need to start from the beginning.
  2. Have hg installed (I’m using tortoisehg) and configure its ConvertExtension.
    In order to do that navigate to C:\Users\%UserName% and open mercurial.ini file, and add this at the end:
    [extensions] hgext.convert=
  3. Execute convert command on git repository with following command:
    hg convert -s git -d hg %PathToGitRepository%
  4. Have fun with hg