Asp.net mvc ASP.NETMVC新手的IoC容器障碍

Asp.net mvc ASP.NETMVC新手的IoC容器障碍,asp.net-mvc,dependency-injection,inversion-of-control,structuremap,ninject,Asp.net Mvc,Dependency Injection,Inversion Of Control,Structuremap,Ninject,我必须承认,我是ASP.NETMVC新手,目前正在研究如何启动我的新项目的所有最佳实践。到目前为止,我已经理解了存储库模式和工作单元的概念,并且已经讨论了依赖注入和控制反转(IoC)。在过去的两天里,我一直在研究这个问题,我得出结论,我喜欢两个IoC容器,它们是StructureMap和NInject,尽管两者都不完美,我还没有设法让StructureMap工作,尽管我喜欢轻量级语法 下面是我的应用程序的构造方式。首先,我的数据上下文和存储库有以下接口: public interface IDa

我必须承认,我是ASP.NETMVC新手,目前正在研究如何启动我的新项目的所有最佳实践。到目前为止,我已经理解了存储库模式和工作单元的概念,并且已经讨论了依赖注入和控制反转(IoC)。在过去的两天里,我一直在研究这个问题,我得出结论,我喜欢两个IoC容器,它们是StructureMap和NInject,尽管两者都不完美,我还没有设法让StructureMap工作,尽管我喜欢轻量级语法

下面是我的应用程序的构造方式。首先,我的数据上下文和存储库有以下接口:

public interface IDataContext : IDisposable
{
    IRepository<T> Repository<T>() where T : class;
    void Commit();
}

public interface IRepository<T> where T : class
{
    IEnumerable<T> GetAll();
    IEnumerable<T> Find(Expression<Func<T, bool>> where);
    T Single(Expression<Func<T, bool>> where);
    void Insert(T entity);
    void Delete(T entity);
}
公共接口IDataContext:IDisposable
{
i存储库(),其中T:class;
无效提交();
}
公共接口IRepository,其中T:class
{
IEnumerable GetAll();
IEnumerable Find(表达式where);
T单个(表达式,其中);
无效插入(T实体);
无效删除(T实体);
}
然后我有一个这样的LinqToSql实现:

public class LinqToSqlDataContext : IDataContext
{
    private readonly DataContext _context;

    public LinqToSqlDataContext(DataContext context)
    {
        _context = context;
    }

    public IRepository<T> Repository<T>() where T : class
    {
        return new LinqToSqlRepository<T>(_context);
    }

    public void Commit()
    {
        _context.SubmitChanges();
    }

    public void Dispose()
    {

    }
}

public class LinqToSqlRepository<T> : IRepository<T> where T : class
{
    private readonly DataContext _context;

    public LinqToSqlRepository(DataContext context)
    {
        _context = context;
    }

    public IEnumerable<T> GetAll()
    {
        return _context.GetTable<T>();
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> where)
    {
        return _context.GetTable<T>().Where(where);
    }

    public T Single(Expression<Func<T, bool>> where)
    {
        return _context.GetTable<T>().SingleOrDefault(where);
    }

    public void Insert(T entity)
    {
        _context.GetTable<T>().InsertOnSubmit(entity);
    }

    public void Delete(T entity)
    {
        _context.GetTable<T>().DeleteOnSubmit(entity);
    }
}
公共类LinqToSqlDataContext:IDataContext
{
私有只读数据上下文_上下文;
公共LinqToSqlDataContext(DataContext上下文)
{
_上下文=上下文;
}
公共IRepository存储库(),其中T:class
{
返回新的LinqToSqlRepository(_上下文);
}
公共无效提交()
{
_context.SubmitChanges();
}
公共空间处置()
{
}
}
公共类LinqToSqlRepository:IRepository,其中T:class
{
私有只读数据上下文_上下文;
公共LinqToSqlRepository(DataContext上下文)
{
_上下文=上下文;
}
公共IEnumerable GetAll()
{
返回_context.GetTable();
}
公共IEnumerable查找(表达式where)
{
返回_context.GetTable().Where(Where);
}
公共T单(表达式,其中)
{
返回_context.GetTable().SingleOrDefault(其中);
}
公共无效插入(T实体)
{
_context.GetTable().InsertOnSubmit(实体);
}
公共作废删除(T实体)
{
_context.GetTable().DeleteOnSubmit(实体);
}
}
目前,我发现有两个地方需要使用我的数据上下文

  • 在控制器构造函数中
  • 在数据注释属性中(不能有构造函数)
  • 我已尽我最大的努力消除任何依赖关系。如果你有什么建议,请告诉我

    现在来看看我的IoC容器实现。首先,我设法将Global.asax.cs文件修改为以下内容:

    public class MvcApplication : NinjectHttpApplication
    {
        protected override void OnApplicationStarted()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }
    
        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel(new ServiceModule());
    
            // Gives my wrapper class access to the kernel instance
            IoCContainer.Initialize(kernel);
    
            return kernel;
        }
    
        public static void RegisterRoutes(RouteCollection routes)
        {
            ...
        }
    }
    
    internal class ServiceModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IDataContext>().To<LinqToSqlDataContext>().InRequestScope();
            Bind<DataContext>().To<MyDataContext>().InRequestScope();
        }
    }
    
    public static class IoCContainer  
    { 
        private static IKernel _kernel;
    
        public static void Initialize(IKernel kernel)  
        {
            _kernel = kernel;
        }
    
        public static T Get<T>()
        {
            return _kernel.Get<T>();
        }
    
        public static object Get(Type type)
        {
            return _kernel.Get(type);
        }
    }
    
    public类mvcapapplication:NinjectHttpApplication
    {
    Application Started()上受保护的覆盖无效
    {
    RegisterAllAreas();
    注册地址(RouteTable.Routes);
    }
    受保护的覆盖IKernel CreateKernel()
    {
    var kernel=新的标准内核(新的ServiceModule());
    //允许我的包装器类访问内核实例
    初始化(内核);
    返回内核;
    }
    公共静态无效注册表项(路由收集路由)
    {
    ...
    }
    }
    内部类ServiceModule:NinjectModule
    {
    公共覆盖无效负载()
    {
    Bind().To().InRequestScope();
    Bind().To().InRequestScope();
    }
    }
    公共静态类IoCContainer
    { 
    私有静态IKernel_内核;
    公共静态void初始化(IKernel内核)
    {
    _内核=内核;
    }
    公共静态不获取()
    {
    返回_kernel.Get();
    }
    公共静态对象Get(类型)
    {
    return _kernel.Get(type);
    }
    }
    
    这很有效。控制器构造函数现在自动将其依赖项连接起来,在我的数据注释属性中,我可以说:

    var context = IoCContainer.Get<IDataContext>();
    
    var context=IoCContainer.Get();
    
    我喜欢NInject,但即使使用从NinjectHttpApplication继承的Global.asax.cs文件(它处理许多管道),我仍然觉得有很多事情需要删除

    接下来我看了结构图。StructureMap没有自带内置的ControllerFactory,但生成一个非常简单。在测试期间,我已将其临时放置在Global.asax.cs文件中。以下是该文件的最终内容:

    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
    
            // Configure structure map
            ObjectFactory.Initialize(x =>
            {
                x.For<IDataContext>()
                    .HttpContextScoped()
                    .Use<LinqToSqlDataContext>();
    
                x.For<DataContext>()
                    .HttpContextScoped()
                    .Use<MyDataContext>();
            });
        }
    
        protected void Application_EndRequest()
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        } 
    
        public static void RegisterRoutes(RouteCollection routes)
        {
            ...
        }
    }
    
    public class StructureMapControllerFactory : DefaultControllerFactory 
    {
        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            try
            {
                var controllerType = base.GetControllerType(requestContext, controllerName);
                return ObjectFactory.GetInstance(controllerType) as IController;
            }
            catch (Exception e)
            {
                return base.CreateController(requestContext, controllerName);
            }
        }
    }
    
    public类mvcapapplication:HttpApplication
    {
    受保护的无效应用程序\u Start()
    {
    RegisterAllAreas();
    注册地址(RouteTable.Routes);
    ControllerBuilder.Current.SetControllerFactory(新结构MapControllerFactory());
    //配置结构图
    ObjectFactory.Initialize(x=>
    {
    x、 For()
    .HttpContextScoped()
    .使用();
    x、 For()
    .HttpContextScoped()
    .使用();
    });
    }
    受保护的无效应用程序\u EndRequest()
    {
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
    } 
    公共静态无效注册表项(路由收集路由)
    {
    ...
    }
    }
    公共类结构MapControllerFactory:DefaultControllerFactory
    {
    公共重写IController CreateController(RequestContext RequestContext,string controllerName)
    {
    尝试
    {
    var controllerType=base.GetControllerType(requestContext,controllerName);
    返回ObjectFactory.GetInstance(controllerType)作为IController;
    }
    捕获(例外e)
    {
    返回base.CreateController(requestContext,controllerName);
    }
    }
    }
    
    我还应该能够在我的data annotation属性中获取数据上下文的实例,方法是:

    var context = ObjectFactory.GetInstance<IDataContext>();
    
    var context=ObjectFactory.GetInstance();
    
    对我来说,这在语法上确实感觉轻松多了。但是,当我运行我的应用程序时,它不工作

    我想知道的是:

    public class MvcApplication : NinjectHttpApplication
    {
        protected override void OnApplicationStarted()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }
    
        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel(new ServiceModule());
    
            // Gives my wrapper class access to the kernel instance
            IoCContainer.Initialize(kernel);
    
            return kernel;
        }
    
        public static void RegisterRoutes(RouteCollection routes)
        {
            ...
        }
    }
    
    internal class ServiceModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IDataContext>().To<LinqToSqlDataContext>().InRequestScope();
            Bind<DataContext>().To<MyDataContext>().InRequestScope();
        }
    }
    
    public static class IoCContainer  
    { 
        private static IKernel _kernel;
    
        public static void Initialize(IKernel kernel)  
        {
            _kernel = kernel;
        }
    
        public static T Get<T>()
        {
            return _kernel.Get<T>();
        }
    
        public static object Get(Type type)
        {
            return _kernel.Get(type);
        }
    }
    
  • 我的模式是否正确