实现Container Per Request模式

时间:2015-07-22 07:13:14

标签: c# asp.net-mvc ioc-container structuremap global-asax

我将添加必要的基础结构来将每个请求绑定到它自己的嵌套容器,所以在这种情况下,每个请求的容器给我们一个唯一的会话(每个请求的上下文),在我的代码我正在使用ObjectFactory的新实现:

public static class SmObjectFactory
{
        private static readonly Lazy<Container> _containerBuilder =
            new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication);

        public static IContainer Container
        {
            get { return _containerBuilder.Value; }
        }

        private static Container defaultContainer()
        {
            return new Container(ioc =>
            {
                ioc.For<IUnitOfWork>()
                   .HybridHttpOrThreadLocalScoped()
                   .Use<ApplicationDbContext>();

        // config

            });
        }
} 

所以,例如,如果我只是在ApplicationDbContext的构造函数中设置一个断点,每次创建一个实例。例如,在我的情况下,我有这些控制器:

public partial class HomeController : Controller
{
        private readonly IUnitOfWork _uow;

        public HomeController(IUnitOfWork uow)
        {
            _uow = uow;
        }
        public virtual ActionResult Index()
        {
            return View();
        }
}
public class TestController : Controller
{
        private readonly IUnitOfWork _uow;

        public TestController(IUnitOfWork uow)
        {
            _uow = uow;
        }

        public ActionResult GetData()
        {
            return Content("Data");
        }
}

因此,Index操作返回的视图使用此代码从TestController中提取内容:

@Html.Action("GetData", "Test")

在该示例中,每个请求创建了几个实例! 所以我用这种方式改变了SmObjectFactory

public class NewObjectFactory
{
        public static IContainer Container { get; set; }

        static NewObjectFactory()
        {
            Container = new Container();
            Container.Configure(ioc =>
            {
        ioc.For<IUnitOfWork>()
                   .HybridHttpOrThreadLocalScoped()
                   .Use<ApplicationDbContext>();

        // config
        }

}

然后在Global.asax我添加了这些代码行以使用嵌套容器:

public IContainer Container
{
            get
            {
                return (IContainer)HttpContext.Current.Items["_Container"];
            }
            set
            {
                HttpContext.Current.Items["_Container"] = value;
            }
}
public void Application_BeginRequest()
{
            Container = NewObjectFactory.Container.GetNestedContainer();
        }
        public void Application_EndRequest()
        {
                Container.Dispose();
                Container = null;
}

Application_Start内:

DependencyResolver.SetResolver(
                new StructureMapDependencyResolver(() => Container ?? NewObjectFactory.Container));

在DependencyResolver中,我以这种方式实现了工厂功能:

public class StructureMapDependencyResolver : IDependencyResolver
{
            private readonly Func<IContainer> _factory;

            public StructureMapDependencyResolver(Func<IContainer> factory)
            {
                _factory = factory;
            }

            public object GetService(Type serviceType)
            {
                if (serviceType == null)
                {
                    return null;
                }

                var factory = _factory();

                return serviceType.IsAbstract || serviceType.IsInterface
                    ? factory.TryGetInstance(serviceType)
                    : factory.GetInstance(serviceType);
            }

            public IEnumerable<object> GetServices(Type serviceType)
            {
                return _factory().GetAllInstances(serviceType).Cast<object>();
            }
}

最后,当我运行应用程序时,我收到此错误:

  

未注册默认实例,无法自动生成   确定类型   'Microsoft.Owin.Security.DataProtection.IDataProtectionProvider'

但是当我在Startup.cs文件中评论此行时:

ConfigureAuth(app)

一切正常,这次ApplicationDbContext创建一次,然后处理掉。这就是我想要的:现在只创建一个上下文实例,并在Web请求结束时正确处理它,这意味着嵌套容器重用上下文来满足两个控制器的依赖关系。 :) 有什么想法吗?

0 个答案:

没有答案