C# MediatR和SimpleInjector的依赖范围问题
我一直在使用WinForms应用程序中的库来试验中介模式和CQR,该应用程序使用实体框架进行数据访问。该应用程序用于批量生产工厂,允许用户查看活动批次和已完成批次的列表,并在必要时更新批次信息。每个批次都有大量与之相关的信息,如质量和过程测量。根据以下文章,读写数据被组织成查询和命令: 下面是一个查询和查询处理程序的简单示例<代码>数据上下文使用SimpleInjector注入查询处理程序C# MediatR和SimpleInjector的依赖范围问题,c#,entity-framework,simple-injector,mediator,mediatr,C#,Entity Framework,Simple Injector,Mediator,Mediatr,我一直在使用WinForms应用程序中的库来试验中介模式和CQR,该应用程序使用实体框架进行数据访问。该应用程序用于批量生产工厂,允许用户查看活动批次和已完成批次的列表,并在必要时更新批次信息。每个批次都有大量与之相关的信息,如质量和过程测量。根据以下文章,读写数据被组织成查询和命令: 下面是一个查询和查询处理程序的简单示例数据上下文使用SimpleInjector注入查询处理程序 public class GetAllBatchesQuery: IRequest<IEnumerabl
public class GetAllBatchesQuery: IRequest<IEnumerable<Batch>> { }
public class GetAllBatchesQueryHandler :
IRequestHandler<GetAllBatchesQuery, IEnumerable<Batch>>
{
private readonly DataContext _context;
public GetAllBatchesQueryHandler(DataContext context)
{
_context= context;
}
public IEnumerable<Batch> Handle(GetAllBatchesQueryrequest)
{
return _db.Batches.ToList();
}
}
我遇到的问题是DbContext的生存期。理想情况下,我希望每个独立事务使用一个实例,在本例中,它将包括以下内容:
- 从数据库检索批列表
- 检索批次的质量指标列表(这些指标存储在不同的数据库中,并通过存储过程访问)
- 更新批次,这可能包括更新数据库中的多个实体
var batches = mediator.Send(new GetAllBatchesQuery());
container.Register<DataContext>();
public class LifetimeScopeDecorator<TRequest, TResponse> :
IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IRequestHandler<TRequest, TResponse> _decorated;
private readonly Container _container;
public LifetimeScopeDecorator(
IRequestHandler<TRequest, TResponse> decorated,
Container container)
{
_decorated = decorated;
_container = container;
}
public TResponse Handle(TRequest message)
{
using (_container.BeginLifetimeScope())
{
var result = _decorated.Handle(message);
return result;
}
}
}
...
container.RegisterDecorator(
typeof(IRequestHandler<,>),
typeof(ExecutionContextScopeDecorator<,>));
public class LifetimeScopeDecorator<TRequest, TResponse> :
IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly Func<IRequestHandler<TRequest, TResponse>> _decorateeFactory;
private readonly Container _container;
public LifetimeScopeDecorator(
Func<IRequestHandler<TRequest, TResponse>> decorateeFactory,
Container container)
{
_decorateeFactory = decorateeFactory;
_container = container;
}
public TResponse Handle(TRequest message)
{
using (_container.BeginLifetimeScope())
{
var result = _decorateeFactory.Invoke().Handle(message);
return result;
}
}
}
MediatR.dll中发生类型为“System.InvalidOperationException”的未处理异常
其他信息:找不到MediatorTest.GetAllBatchesQuery类型请求的处理程序
容器或服务定位器未正确配置,或者处理程序未在容器中注册
调试并查看MediatR代码后,似乎在调用mediator.Send(…)
方法时,通过调用container.GetInstance()
创建了GetAllBatchesQueryHandler
类的新实例。但是,由于此时DataContext
不在执行范围内,因此它可能未正确初始化,从而导致异常
我相信我理解问题的根本原因,但不知如何有效地解决它。为了更好地说明这个问题,我开发了以下示例。任何实现了IDisposable
的类都会导致与DataContext
相同的问题
using System;
using System.Collections.Generic;
using System.Reflection;
using MediatR;
using SimpleInjector;
using SimpleInjector.Extensions.LifetimeScoping;
namespace MediatorTest
{
public class GetRandomQuery : IRequest<int>
{
public int Min { get; set; }
public int Max { get; set; }
}
public class GetRandomQueryHandler : IRequestHandler<GetRandomQuery, int>
{
private readonly RandomNumberGenerator _r;
public GetRandomQueryHandler(RandomNumberGenerator r)
{
_r = r;
}
public int Handle(GetRandomQuery request)
{
return _r.Next(request.Min, request.Max);
}
}
public class RandomNumberGenerator : IDisposable
{
private Random _random = new Random();
public RandomNumberGenerator() { }
public void Dispose() { }
public int Next(int min, int max)
{
var result = _random.Next(min, max);
return result;
}
}
public class LifetimeScopeDecorator<TRequest, TResponse> :
IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IRequestHandler<TRequest, TResponse> _decorated;
private readonly Container _container;
public LifetimeScopeDecorator(
IRequestHandler<TRequest, TResponse> decorated,
Container container)
{
_decorated = decorated;
_container = container;
}
public TResponse Handle(TRequest message)
{
using (_container.BeginLifetimeScope())
{
var result = _decorated.Handle(message);
return result;
}
}
}
class Program
{
static void Main(string[] args)
{
var assemblies = GetAssemblies();
var container = new Container();
container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle();
container.RegisterSingleton<IMediator, Mediator>();
container.Register<RandomNumberGenerator>(Lifestyle.Scoped);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.RegisterSingleton(new SingleInstanceFactory(container.GetInstance));
container.RegisterSingleton(new MultiInstanceFactory(container.GetAllInstances));
container.RegisterDecorator(
typeof(IRequestHandler<,>),
typeof(LifetimeScopeDecorator<,>));
container.Verify();
var mediator = container.GetInstance<IMediator>();
var value = mediator.Send(new GetRandomQuery() { Min = 1, Max = 100 });
Console.WriteLine("Value = " + value);
Console.ReadKey();
}
private static IEnumerable<Assembly> GetAssemblies()
{
yield return typeof(IMediator).GetTypeInfo().Assembly;
yield return typeof(GetRandomQuery).GetTypeInfo().Assembly;
}
}
}
使用系统;
使用System.Collections.Generic;
运用系统反思;
使用MediatR;
使用SimpleInjector;
使用SimpleInjector.Extensions.LifetimeScope;
命名空间中介测试
{
公共类GetRandomQuery:IRequest
{
公共int Min{get;set;}
公共int Max{get;set;}
}
公共类GetRandomQueryHandler:IRequestHandler
{
专用只读RandomNumberGenerator\u r;
公共GetRandomQueryHandler(RandomNumberGenerator r)
{
_r=r;
}
公共int句柄(GetRandomQuery请求)
{
返回下一步(request.Min,request.Max);
}
}
公共类RandomNumberGenerator:IDisposable
{
私有随机_Random=新随机();
公共RandomNumberGenerator(){}
public void Dispose(){}
公共整数下一个(整数最小值,整数最大值)
{
var结果=_random.Next(最小值、最大值);
返回结果;
}
}
公共类LifetimeScopeDecorator:
IRequestHandler
TRequest在哪里:IRequest
{
私有只读IRequestHandler\u;
私有只读容器_容器;
公共生活时间记录器(
IRequestHandler,
集装箱(集装箱)
{
_装饰的=装饰的;
_容器=容器;
}
公共响应句柄(TRequest消息)
{
使用(_container.BeginLifetimeScope())
{
var result=_.Handle(消息);
返回结果;
}
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var assemblies=GetAssemblies();
var container=新容器();
container.Options.DefaultScopedLifestyle=new LifetimeScopeLifestyle();
container.RegisterSingleton();
容器。寄存器(生活方式。范围);
容器寄存器(typeof(IRequestHandler),程序集);
RegisterSingleton(新的SingleInstanceFactory(container.GetInstance));
RegisterSingleton(新的多实例工厂(container.GetAllInstances));
container.RegisterDecorator(
类型(IRequestHandler),
类型(LifetimeScopeDecorator));
container.Verify();
var mediator=container.GetInstance();
var value=mediator.Send(新的GetRandomQuery(){Min=1,Max=100});
Console.WriteLine(“Value=“+Value”);
Console.ReadKey();
}
私有静态IEnumerable getAssemblys()
{
产生返回typeof(IMediator).GetTypeInfo()程序集;
产生返回typeof(GetRandomQuery).GetTypeInfo().Assembly;
}
}
}
问题在于,您的decoratee(及其DbContext
依赖项)是在创建decorator时创建的,并且当时没有活动范围(因为您在稍后的时间点创建它)。你应该使用所描述的装饰工厂。换句话说,您的LifetimeScopeDecorator
应按如下方式实现:
var batches = mediator.Send(new GetAllBatchesQuery());
container.Register<DataContext>();
public class LifetimeScopeDecorator<TRequest, TResponse> :
IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IRequestHandler<TRequest, TResponse> _decorated;
private readonly Container _container;
public LifetimeScopeDecorator(
IRequestHandler<TRequest, TResponse> decorated,
Container container)
{
_decorated = decorated;
_container = container;
}
public TResponse Handle(TRequest message)
{
using (_container.BeginLifetimeScope())
{
var result = _decorated.Handle(message);
return result;
}
}
}
...
container.RegisterDecorator(
typeof(IRequestHandler<,>),
typeof(ExecutionContextScopeDecorator<,>));
public class LifetimeScopeDecorator<TRequest, TResponse> :
IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly Func<IRequestHandler<TRequest, TResponse>> _decorateeFactory;
private readonly Container _container;
public LifetimeScopeDecorator(
Func<IRequestHandler<TRequest, TResponse>> decorateeFactory,
Container container)
{
_decorateeFactory = decorateeFactory;
_container = container;
}
public TResponse Handle(TRequest message)
{
using (_container.BeginLifetimeScope())
{
var result = _decorateeFactory.Invoke().Handle(message);
return result;
}
}
}
公共类LifetimeScopeDecorator:
IRequestHandler
TRequest在哪里:IRequest
{
私有只读功能装饰工厂;
私有只读容器_容器;
公共生活时间记录器(
Func装饰工厂,