代码之家  ›  专栏  ›  技术社区  ›  chapas

注入到不同的项目/程序集中

  •  3
  • chapas  · 技术社区  · 8 年前

    我已经研究这个问题几个小时了,所以我决定写信寻求帮助。

    在这个论坛上已经有很多答案,我可以找到解决我问题的方法,但我只是无法连接我头脑中的所有点;而我没有完成它。

    我正在尝试在一个大型MVC应用程序上改变注入器,从StructureMap到SimpleInjector。

    我需要正确地将HttpContext的当前用户传递给同一解决方案上的另一个项目,该项目包含所有存储库和DBContext,以便在执行一些CRUD操作时可以使用/编写它。

    我显然不理解StructureMap是如何连接的;我觉得很复杂。我在MVC项目中有这个(可以提供更多信息,因为有十几个类使用StructureMap):

    public class GlobalRegistry : StructureMap.Registry
    {
        public GlobalRegistry()
        {
            For<INotificationRepository>().Use<NotificationRepository>();
            ...
    

    在存储库项目/类中:

    public class NotificationRepository : BaseRepository,INotificationRepository
    {
        public NotificationRepository(string userContext) : base(userContext) { }
    

    (…通过魔术…)构造函数将获取userContext参数,以便稍后在被调用的方法中使用。

    在用SimpleInjector替换之后,我不明白这个参数是如何被注入的。

    出于测试目的,这项工作:

    container.Register<INotificationRepository>(() => new NotificationRepository("username"), 
        Lifestyle.Singleton);
    

    我读到我不应该注射 HttpContext

    接下来,我尝试了 IUserContextFactory

    在同一个MVC项目中,我有他的课:

    public static class ObjectFactory
    {
        private static SimpleInjector.Container _container;
    
        public static void SetContainer(Container container)
        {
            ObjectFactory._container = container;
        }
    
        public static T GetInstance<T>() where T : class
        {
            return _container.GetInstance<T>();
        }
    }
    

    我使用这个类来存储容器 container.Verify();

    ObjectFactory.SetContainer(container);
    

    在任何MVC控制器上,我都这样使用它:

    IUserContext ctxUser = ObjectFactory.GetInstance<IUserContext>();
    

    在我的整个尝试中,我也在存储库中尝试了类似以下的方法,但结果总是为空 UserName .

    public NotificationRepository(IUserContext userContext) : base(userContext) { }
    

    (MVC项目和存储库项目之间的公共接口)

    public interface IUserContext
    {
        string Username { get; set; }
    }
    

    比了解解决方案更重要的是,我想了解解决方案是如何工作的,并克服过去几个小时我一直试图理解和解决的困难。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Community kfsone    7 年前

    将运行时原语值作为参数传递给构造函数在简单注入中不直接可用。相反,您可以注入一个组件,该组件允许您在运行时获取该值 IUserContext 这似乎是个好办法,应该会奏效。修改类以将该组件添加到构造函数中,而不是 userName 一串注册新组件,并在调用构造函数时让容器自动注入。

    class HttpSessionUserContext : IUserContext 
    {
        //Your specific implementation of getting the user name from your context
        public string CurrentUserName => (string)HttpContext.Session["userName"];
    }
    

    注册:

    container.Register<IUserContext, HttpSessionUserContext>(Lifestyle.Scoped);
    container.Register<INotificationRepository, NotificationRepository> (Lifestyle.Scoped);
    

    Here 关于为什么在简单注入中没有实现向构造函数传递基元运行时参数的原因,您有更多的信息。

    关于生活方式范围:您可能不应该使用 Lifestyle.Singleton 作为这个组件的作用域,因为它只会被实例化一次并作为一个单例重用。在web应用程序中,通常需要应用每个HttpRequest范围。您可以这样做:创建容器后,将其默认范围定义为 WebRequestLifestyle WebApiRequestLifestyle :

    var container = new Container();
    container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
    

    然后,当您注册组件时,使用该值 Lifestyle.Scoped ,这将应用默认的作用域生活方式:

    container.Register<SomeInterface, SomeClass>(Lifestyle.Scoped);
    

    编辑: 根据 Steven 的评论,在这种情况下,最好注册 HttpSessionUserContext Singleton ,因为它是无状态的。一般来说 独生子女 具有更好的性能,因为它只实例化一次并共享,但要小心那些不是无状态的组件或对其他组件有依赖关系的组件。

    此外,请确保已注册MVC控制器并将容器的实例分配给MVC DependencyResolver 这才真正实现了控制器中构造函数中参数的自动解析和注入。我猜你是在你的 Application_Start 事件处理程序。

    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    container.Verify();
    DependencyResolver.SetResolver(
            new SimpleInjectorDependencyResolver(container));