Simple Injector, .NET Core 3.1, Context对象的短寿命

问题描述 投票:0回答:1

我想通过 correlationId 我将通过控制器接收到我的 IEventDispatcher 我想让这个对象拥有 correlationId 尽快处理 EventHandler 是完成了它。

另外,我在听 ServiceBus queuetopic 而我有实例 IEventDispatcher 我也想在那里应用同样的逻辑。

我注入了 EventDispatcher 在控制器中,我设置了内部的 Context 我希望能在 EventHandler 但不通过 context 直接访问 context 通过DI。

public class CommandController : ControllerBase
{
    private readonly IEventDispatcher eventDispatcher;

    public CommandController(IEventDispatcher eventDispatcher)
    {
        this.eventDispatcher = eventDispatcher;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody]TAction action)
    {
        try
        {
            // I want this context to be disposed after handler 
            // that is called inside of eventDispatcher is done with execution
            var context = new HttpRequestContext(HttpContext); 

            await eventDispatcher.Dispatch<TAction>((TAction)action, context);
            return Ok();
        } catch (Exception e)
        {
            return BadRequest((new BadExceptionResult { Error = e.Message }));
        }
    }
}    

我使用的是dotnet core 3.1 web api,并且我有SimpleInjector这样的设置。

class ServiceSetup    
    private Container container = new Container();

    public void ConfigureServices(IServiceCollection services)
    {
        container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
        // here I set RequestContextRegistrator 
        // and then I set this context inside EventHandler to set context 
        // and hope to have it available in handler
        container.Register<IRequestContextRegistrator, RequestContextRegistrator>(
            Lifestyle.Scoped);
        container.Register(() => container.GetInstance<IRequestContextRegistrator>().Get(),
            Lifestyle.Scoped);

        // ...
        // EventHandlers are registered just before EventDispatcher as EventDispatcher is
        // is depending on eventHandlers to be registered before eventDispatcher can send
        // a request to them
        var eventDispatcher = new EventDispatcher(container);

        services.AddSingleton<IEventDispatcher>(eventDispatcher);
        // ...
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseSimpleInjector(container);
        // ...
        container.Verify();
    }
}    

RequestContextRegistrator : IRequestContextRegistrator

internal class RequestContextRegistrator : IRequestContextRegistrator
{
    private readonly IContext context = new Context();

    public IContext RegisterContext(IContext context)
    {
        context.CorrelationId = new Guid().ToString();

        return context;
    }

    public Context Get()
    {
        return new Context()
        {
            CorrelationId = context.CorrelationId
        };
    }
}

这里是这样的 EventDispatcher 有点像

public class EventDispatcher : IEventDispatcher
{
    Container container;

    public EventDispatcher(Container container)
    {
        this.container = container;
    }

    public async Task Dispatch<TAction>(TAction action, IContext context)
    {
        using (AsyncScopedLifestyle.BeginScope(container))
        {
            // this is registered in `ConfigureServices` before  
            var handler = container.GetInstance(IEventHandler<TAction>);
        }
    }
}    

如你所见,我使用了 using (AsyncScopedLifestyle.BeginScope(container)) 但在处理程序的构造函数中,我从来没有得到过 Context 注入的对象,它总是 null.

c# dependency-injection simple-injector
1个回答
1
投票

你可以存储 IContext 内的Scoped组件(如您的 RequestContextRegistrator)在你的作用域的开头。例如,你的处理程序现在可以在你的作用域的开始处注入

public async Task Dispatch<TAction>(TAction action, IContext context)
{
    using (AsyncScopedLifestyle.BeginScope(container))
    {
        container.GetInstance<IContextProvider>().SetContext(context);

        var handler = container.GetInstance<IEventHandler<TAction>>();
        await handler.Handle(action);
    }
}

你的处理程序现在可以被注入到 IContextProvider 进入 IContext:

public class OrderShippedHandler : IEventHandler<OrderShipped>
{
    private readonly IContextProvider provider;

    public OrderShippedHandler(IContextProvider provider) => this.provider = provider;

    public async Task Handle(OrderShipped e)
    {
        IContext context = this.provider.Context;
    }
}

不要忘记注册 IContextProvider 实现为作用域。

这种在对象图内部存储状态的方式称为 封口构成模型.

© www.soinside.com 2019 - 2024. All rights reserved.