SessionPerWebRequest UoW SimpleInjector ActionFilt

2019-08-14 09:18发布

问题:

I am using SimpleInjector and want to create a UnitOfWork Per WebRequest Using an UnitOfWorkFactory.

I want to do this by using an ActionLiterAttribute so that every web request will begin a new UnitOfWork

The only problem that I have is to pass the IUnitOfWorkFactory to the ActionFilterAttribute class.

There is a similar question about this online but there is a solution given using Ninject, Unfortunately with SimpleInjection there is no equivalent to Bind a filter.

This is what I have done so far, not sure if it is correct.

I have created a SessionPerRequestActionFilter

public class SessionPerRequestActionFilter : ActionFilterAttribute
{
    private readonly Func<IUnitOfWorkFactory> _unitOfWorkFactory;
    private IUnitOfWork _unitOfWork;

    public SessionPerRequestActionFilter(Func<IUnitOfWorkFactory> unitOfWorkFactoryProvider)
    {
        if (unitOfWorkFactoryProvider == null) throw new ArgumentNullException("_unitOfWorkFactory");

        _unitOfWorkFactory = unitOfWorkFactoryProvider;
    }        

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var unitOfWorkFactory = _unitOfWorkFactory.Invoke();
        _unitOfWork = unitOfWorkFactory.BeginUnitOfWork();
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
            _unitOfWork.Commit();

        _unitOfWork.Dispose();
    }
}

Then I added it to GlobalFilters in my Global.ascx page, but not happy with how I did it here. See my thoughts in the code snippet bellow.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); // <-- So First register all filters
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);


    #region Initialize SimpleInjector
    var container = new Container();           

    InitializeContainer(container);            

    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());            

    container.RegisterMvcIntegratedFilterProvider();

    new AppHost(container).Init();

    GlobalFilters.Filters.Add(new SessionPerRequestActionFilter(() => container.GetInstance<IUnitOfWorkFactory>())); // <-- Then in here I go and register the filter again.

    container.Verify();

    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    #endregion                
}

Surely there is a better way to do this? Is it perhaps more appropriate to use Property Injection in SessionPerRequestActionFilter?

Or is it perhaps better to remove this from the ActionFilter and implement the UnitOfWork in the BaseController then injecting the factory into the controller?

I have seen so many examples online but not sure which one is the more modern approach.