【问题标题】:Injecting into a different project/assembly注入不同的项目/程序集
【发布时间】:2016-11-15 19:32:09
【问题描述】:

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

这个论坛上已经有很多答案可以用来解决我的问题,但是我无法将我脑海中的所有点都联系起来;而且我还没完成。

我正在尝试将大型 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) { }

(...by magic...) 构造函数将使用 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项目和repository项目的通用接口)

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

比知道解决方案更重要的是,我想了解解决方案的工作原理,并克服过去几个小时试图理解和解决这个问题时遇到的困难。

【问题讨论】:

  • 嗯,StructureMap 中的上下文也应该有一个注册,也应该将其转换为其他语法。顺便说一句,这个Lifestyle.Singleton 不好看。
  • 我不明白你的实际问题是什么,你在哪里卡住了,你想了解什么。
  • @Gert Arnold,没有找到关于正在注入的 StructureMap 的上下文。当用户登录时它保持不变,直到它注销,我在哪里错过了什么?多个用户!?
  • @Steven,我希望能得到你的答复,你是所有#simple-injector 选项卡上的常数。我的不好,我不知道如何解释/表达我自己,这就是问题所在。已经解决了我的问题。不确定我是否完全理解我自己的解决方案。我质疑了很多次...作为程序员的我...哦,这个帖子应该被删除它很混乱。
  • 上下文必须已经注册。 IoC 容器如何知道如何将其注入存储库? (这对你来说是“魔法”,但只是配置)。

标签: c# entity-framework structuremap httpcontext simple-injector


【解决方案1】:

将运行时原始值作为参数传递给构造函数在 Simple Inject 中不能直接使用。相反,您可以注入一个允许您在运行时获取该值的组件,因此您使用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 范围:您可能不应该使用 Lifestyle.Singleton 作为此组件的范围,因为它只会被实例化一次并作为单例重用。在 Web 应用程序中,您通常希望应用 Per-HttpRequest 范围。您可以这样做:创建容器后,将其默认范围定义为 WebRequestLifestyleWebApiRequestLifestyle

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

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

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

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

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

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

【讨论】:

  • 我同意你的回答戴安娜,谢谢你的帮助。我在 LoginControler 上注入 IUserContext,然后在有效用户登录后获取用户名,在注销之前将保持不变,但在这种情况下可能看不到正确的东西。
  • 由于HttpSessionUserContext 类是无状态的,它可以注册为单例,因此我的建议是实际将其注册为单例。这样做没有坏处。事实上,我认为拥有尽可能多的单例注册是一个好习惯。
  • @Steven 你是对的,这样会更好,性能更好。如果性能不重要,我会根据请求将事物注册为每个请求,这只是一种保守的方法,但单例注册更有效。请注意非无状态的组件,或与其他组件有依赖关系。
  • @Diana 在单例组件存在依赖关系的情况下,Simple Injector 将始终为您检查是否存在生活方式不匹配的情况。如果该组件依赖于作用域或瞬态,Simple Injector 将抛出异常。
  • @Steven 好的,谢谢,我想的更像是一个组件,它有一种方法可以在某处修改数据,或者与其他可能是单例或不是单例的组件一起做非线程安全的事情。过去我遇到过这个问题(可能是因为实施不当和对作用域工作方式的误解)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 2020-08-09
相关资源
最近更新 更多