为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
饮歌长啸 2022-12-24 12:14:55
    我有一个在服务器上运行的服务,它侦听消息队列。收到消息时,将启动一个新线程并将消息传递给该线程进行处理。我已经定义了一个接口,它提供对当前用户的访问,以便在用于消息处理的各种类中使用: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 中实现它的正确方法吗?还有另一种模式会更正确吗?
查看完整描述

1 回答

?
慕村9548890

TA贡献1884条经验 获得超4个赞

让我们从特定于 ASP.NET 的IUserContext注册开始:


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

    User user = null;

    try {

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

    }

    catch { }


    return new UserContext(user);

});

这种注册是有问题的,因为UserContext组件依赖于运行时数据的可用性,而正如此处所述,对象图的创建应该与运行时数据分开,并且运行时数据应该流经系统。


换句话说,您应该将您的UserContext课程重写为以下内容:


public class AspNetUserContext : IUserContext

{

    User CurrentUser => (User)HttpContext.Current.Session[USER_CONTEXT];

}

这允许IUserContext按如下方式注册此特定于 ASP.NET 的实现:


container.RegisterInstance<IUserContext>(new AspNetUserContext());

当然,前面的并没有解决你的Windows Service中的问题,但是前面的确实为解决这个问题打下了基础。


对于 Windows 服务,您还需要自定义实现(适配器):


public class ServiceUserContext : IUserContext

{

    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())

{

    .....

    var userContext = container.GetInstance<ServiceUserContext>();


    // Set the user of the scoped ServiceUserContext

    userContext.CurrentUser = GetUserContext(message);


    var handler = container.GetInstance<IHandleMessages<SomeMessage>>();


    handler.Handle(message);


    .....

}

在这里,解决方案也是将对象图的创建与运行时数据的使用分开。在这种情况下,运行时数据在构造(即使用userContext.CurrentUser = GetUserContext(message))后提供给对象图。


查看完整回答
反对 回复 2022-12-24
  • 1 回答
  • 0 关注
  • 64 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信