• Code
  • Tags
  • Users
  • Titles
  • Log in
  • Feedback
  • FAQ
Share Code
Welcome to ForkCan.com

ForkCan is all about sharing code in a social way.

Discuss, debate or argue with other devs about their or your own code.

Give other devs feedback or make a Fork (Make a better version of a shared code).

Rate the code, if you use the code mark it as used so others can see if the shared code is used by someone.

Help each other to be better devs and to be more productive.


Features not working yet:

Flag a post


QR Code

Tiny Url

http://4kcan.com/s/MjE5

Related Code
Generic Entity Framework 4.0 Base Repository
Unity Service Locator for ASP.NET MVC 3.0 Beta 1
Generic Entity Framework 4.0 Base Repository with Paging
Generic linq-to-sql repository
Make sure the web.config pages/namespace can be used together with ASP.NET MVC 3 P1 and Razor
Extension to the HttpClient
ForEach Extension method for IEnumerable<T>
Invoke Extension Method
Loading Strategy for Entity Framework 4.0
Use of Extension methods to hide "infrastructure code"
PagedList class and paging code for ASP.Net MVC (Nothing new but kind of usefull.)
Null Dot "Operator" Extension Method
Fork of GZIP your Actions in MVC if not used as standard in IIS7 or only use IIS6
Keep Entity Framework ObjectContext in a WCF Service OperationContext
Google Analytics helper for ASP.NET Razor
Unity Controller Factory for ASP.NET MVC 3.0
WCF RIA Services Unity 2.0 DomainService Factory
A Default Entity Framework 4.0 ObjectContext Factory
StringFormat Extension method for HtmlHelper ASP.NET MVC
Custom C# exception class
Email validation with Regular Expression
Reflection dynamically get private fields or properties
GZIP your Actions in MVC if not used as standard in IIS7 or only use IIS6
Url Validation with Regular Expression
Method to hash passwords

UnitOfWork Action filter for ASP.NET MVC and nHibernate

Reuse unit of work among several repositories by using the HTTPContext

0
1.25k 0 0 0 0 3

This is a simple ActionFilter we can apply to controls that should reuse the same Unit of Work, Identity map etc between repositories used in an action method:

public class UnitOfWorkFilter : IActionFilter
{
    private readonly ISessionContainer _sessionContainer;


    public UnitOfWorkFilter(ISessionContainer sessionContainer)
    {
        Contract.Requires(sessionContainer != null);

        _sessionContainer = sessionContainer;
    }


    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        _sessionContainer.CloseSession();
    }


    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _sessionContainer.OpenSession();
    }
}

Here is the ISessionContainer interface:

public interface ISessionContainer : IDisposable
{
    ISession Session { get; set; }

    void OpenSession();

    void CloseSession();
}

Here is an implementation of the ISessionContainer that will get and store the nHibernate's ISession into the HttpContext:

public class HttpContextSessionContainer : ISessionContainer
{
    private readonly ISessionFactory _sessionFactory;


    public HttpContextSessionContainer(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }


    public void Dispose()
    {
        if (Session.IsConnected)
            Session.Close();

        Session.Dispose();

        HttpContext.Current.Items.Remove("NhibSession");
    }


    public ISession Session
    {
        get
        {
            return HttpContext.Current.Items["NhibSession"] as ISession;
        }
        set
        {
            HttpContext.Current.Items.Add("NhibSession", value);
        }
    }


    public void OpenSession()
    {
        Session = _sessionFactory.OpenSession();
    }


    public void CloseSession()
    {
        this.Dispose();
    }
}

Here is an example of a Controller that have dependencies to two Repositories:

Note: This is only an example so you can see how it can be used, so just dummy code

public class AccountController : Controller
{
    public AccountController(IUserRepository users, IRolesRepository roles)
    {
        Contract.Requires(users != null);
        Contract.Requires(roles != null);

        _users = users;
        _roles = roles;
    }


    public ActionResult NewUser(UserPM user)
    {
        _users.Create(...);

        _roles.AddUserToRole(...)

        return View();
    }

    ...
}

Here is an example of the IUserRepository:

public class UserRepository : BaseRepository<User>, IUserRepository
{

    public UserRepository(ISessionContainer sessionContainer) : base(sessionContainer)
    {
    }
}

The BaseRepository has some CRUD methods, the CRUD methods will get the ISession they need through the ISessionContainer's Session property. If the ISessionContainer's Session is empty, the BaseRepository will make a call to the ISessionCintainer's OpenSession to get an open session to work with, but will close the session when the operation is completed.

When the UnitOfWorkFilter is applied to Controllers, the ActionFilter will call the ISessionContainers's OpenSession method and put the ISession into the HTTPContext when an Action method is executing. The Repositories will then reuse the same ISession. When the execution of an Action method is done, the UnitOfWorkFilter's OnActionExecuted will be called and close the session (It will make sure the ISession.Dispose method is called to clear the ISession to avoid memory leaks etc).

There are other ways of sharing ISession between Repositories etc during an request, for example in the Global.asax, let it put the ISession into the HTTPContext and then in the Application_EndRequest dispose it. We can also create a Base Controller to handle it etc. But I wanted to apply an action filter instead to the Controllers that should reuse an ISession. In my current case, it was the best way (at least what I think).


Share: twitter | facebook   Action: used | fork | flag

.net

Mark '.net' tag as 'like'

Mark '.net' tag as 'ignore'

aspmvc

Mark 'aspmvc' tag as 'like'

Mark 'aspmvc' tag as 'ignore'

c#

Mark 'c#' tag as 'like'

Mark 'c#' tag as 'ignore'

nhibernate

Mark 'nhibernate' tag as 'like'

Mark 'nhibernate' tag as 'ignore'

repository

Mark 'repository' tag as 'like'

Mark 'repository' tag as 'ignore'


 @fredrikn "I'm the master"
3.11k
July 27, 2010 4:25 PM

Fork

 UnitOfWork Action filter for ASP.NET MVC and nHibernate -  @fredrikn Tuesday 27, 2010 4:25 PM


0 Feedback


You must log in before you can give any feedback


3 Discussion(s)

Newest Oldest
0

What is the difference to send around ISessionFactory and use ISessionFactory.GetCurrentSession() with the usage of NHibernate.Context.ManagedWebSessionContext in the configuration? Instead of create your own session holder? Of course you need to bind and unbind the session to the context as you do in ActionFilter, but the rest is only inventing the wheel again :).

Posted the same argument on the blog

link | flag  | Reply

 @NPehrsson
40
Tuesday 27, 2010 6:16 PM

1

Reply to: NPehrsson

Hi NPehrsson,

Great question. The ISessionContainer is used in different environment in my projects, WCF, Rich Client, Web etc (they all reuse the same Repository detail). The idea of the ISessionContainer is to hide the existence of nHibernate, but the problem is the ISession interface that I reuse from nHibernate, which makes it a leaking abstraction. But the time to replace the ISessionContainer and my code to use Entity Framework instead, takes a few minutes only (Even though, I don't often just replace an OR-mapper in a project). I don't want to pass around a dependency to the ISessionFactory down to the repositories, only the container of a Session that should be crossed shared. The ISessionFactory passed into my current ISessionContainer isn't needed at all, so if I simply make my own ISession instead of reusing the one with nHibernate, I have no dependencies to other frameworks and no leaking abstraction.

link | flag  | Reply

 @fredrikn "I'm the master"
3.11k
Tuesday 27, 2010 9:04 PM

0

Reply to: FredrikN

Sounds like a little bit of over design to create your own ISession interface that will be exactly like Nhibernate or EF context for example. And the same on replacing your O/R mapper there isn't that much work IF you want to need that, the problem will more be with the querying and saving than sending around ISessionFactory to some repositories that you could easy use search and replace on. But ok its an argument that some of us may buy and some of us not.

link | flag  | Reply

 @NPehrsson
40
Wednesday 28, 2010 12:51 AM


You must log in before you can post a comment

Squeed
Made by: Fredrik Normén 2010