多线程应用程序中基于上下文的依赖注入

    我有一个在服务器上运行的服务,它侦听消息队列。收到消息时,将启动一个新线程并将消息传递给该线程进行处理。


我已经定义了一个接口,它提供对当前用户的访问,以便在用于消息处理的各种类中使用:


public interface IUserContext {

    User CurrentUser { get; }

}

该用户可能会从消息更改为消息。


我的问题是如何在 SimpleInjector 中注册 IUserContext 的实现,以便 CurrentUser 属性正确返回传入消息中包含的正确用户?


在我的 Asp.Net 应用程序中,这是通过以下方式完成的:


container.Register<IUserContext>(() => {

    User user = null;

    try {

         user = HttpContext.Current?.Session[USER_CONTEXT] as IUser;

    }

    catch { }


    return new UserContext(user);

});

我想这将使用生命周期范围来完成,但我不能在静态类中定义它并在每个线程中设置用户,因为它可能会破坏另一个进程。这是我对实施的最佳猜测?


 public static Func<User> UserContext { get; set; }

然后在我的新线程中的代码中:


using (container.BeginLifetimeScope()) {

    .....

    var user = GetUserContext(message);

    UserContextInitializer.UserContext = () => new UserContext(user);

    .....

}

然后注册看起来像这样:


container.Register<IUserContext>(() => UserContextInitializer.UserContext);

除了线程安全之外,这是在 SimpleInjector 中实现它的正确方法吗?还有另一种模式会更正确吗?


饮歌长啸
浏览 65回答 1
1回答

慕村9548890

让我们从特定于 ASP.NET 的IUserContext注册开始:container.Register<IUserContext>(() => {&nbsp; &nbsp; User user = null;&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user = HttpContext.Current?.Session[USER_CONTEXT] as IUser;&nbsp; &nbsp; }&nbsp; &nbsp; catch { }&nbsp; &nbsp; return new UserContext(user);});这种注册是有问题的,因为UserContext组件依赖于运行时数据的可用性,而正如此处所述,对象图的创建应该与运行时数据分开,并且运行时数据应该流经系统。换句话说,您应该将您的UserContext课程重写为以下内容:public class AspNetUserContext : IUserContext{&nbsp; &nbsp; User CurrentUser => (User)HttpContext.Current.Session[USER_CONTEXT];}这允许IUserContext按如下方式注册此特定于 ASP.NET 的实现:container.RegisterInstance<IUserContext>(new AspNetUserContext());当然,前面的并没有解决你的Windows Service中的问题,但是前面的确实为解决这个问题打下了基础。对于 Windows 服务,您还需要自定义实现(适配器):public class ServiceUserContext : IUserContext{&nbsp; &nbsp; User CurrentUser { get; set; }}这个实现要简单得多,这里ServiceUserContext的CurrentUser属性是一个可写属性。这优雅地解决了您的问题,因为您现在可以执行以下操作:// Windows Service Registration:container.Register<IUserContext, ServiceUserContext>(Lifestyle.Scoped);container.Register<ServiceUserContext>(Lifestyle.Scoped);// Code in the new Thread:using (container.BeginLifetimeScope()){&nbsp; &nbsp; .....&nbsp; &nbsp; var userContext = container.GetInstance<ServiceUserContext>();&nbsp; &nbsp; // Set the user of the scoped ServiceUserContext&nbsp; &nbsp; userContext.CurrentUser = GetUserContext(message);&nbsp; &nbsp; var handler = container.GetInstance<IHandleMessages<SomeMessage>>();&nbsp; &nbsp; handler.Handle(message);&nbsp; &nbsp; .....}在这里,解决方案也是将对象图的创建与运行时数据的使用分开。在这种情况下,运行时数据在构造(即使用userContext.CurrentUser = GetUserContext(message))后提供给对象图。
打开App,查看更多内容
随时随地看视频慕课网APP