Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
452 views
in Technique[技术] by (71.8m points)

c# - Sharing a Unit of Work among many Services in ASP.NET MVC 3

my controllers use 2 or more services. In turn, my services construct and consume their own instance of a Unit of Work class (with access to the repositories).

I would like my services to share a same Unit of Work instance, and make it unit-testable. My questions are:

  1. Should I inject the Unit of Work and services to my controllers?
  2. I would need to inject the Unit of Work to my services as well. Where should I do that? Thank you so much.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I like to combine DI with an action filter, this way the container can managed the scope of the unit of work, but begin/commit/rollback are called for you automatically and you don't have to fuss with that on every action.

This is a bit tricky, because normally, actionfilters are NOT re-instantiated per request, so when you have a dependency that you DO want to be per request (the unit of work) you need to work some magic.

Here is how I do this using Ninject, and Ninject.Web.Mvc

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class UnitOfWorkAction : Attribute
    {
    }

    public class UnitOfWorkActionFilter : IActionFilter
    {
        private IUnitOfWork _unitOfWork;

        public UnitOfWorkActionFilter(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            _unitOfWork.Begin();
        }

        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.Exception == null)
                {
                    try
                    {
                        _unitOfWork.Commit();
                    }
                    catch
                    {
                        _unitOfWork.Rollback();
                        throw;
                    }
                }
                else
                {
                    _unitOfWork.Rollback();
                }
        }
    }

I then configure how the attribute should be used in the App_Start/NinjectMVC3.cs

kernel.BindFilter<UnitOfWorkActionFilter>(FilterScope.Action, 0)
                .WhenActionMethodHas<UnitOfWorkAction>();
//also make sure your IUnitOfWork is bound per request, obviously

And finally, an example Action

[UnitOfWorkAction]
public ActionResult SomeAction(int id)
{
     //invoke your services here, and the uow will be automatically committed or rolled back when the action returns
 }

Also worth noting is that this approach lets you do constructor injection of dependencies to your action filter, rather than just property injection, which I very much prefer.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...