Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MediatR和SimpleInjector的依赖范围问题_C#_Entity Framework_Simple Injector_Mediator_Mediatr - Fatal编程技术网

C# MediatR和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

我一直在使用WinForms应用程序中的库来试验中介模式和CQR,该应用程序使用实体框架进行数据访问。该应用程序用于批量生产工厂,允许用户查看活动批次和已完成批次的列表,并在必要时更新批次信息。每个批次都有大量与之相关的信息,如质量和过程测量。根据以下文章,读写数据被组织成查询和命令:

下面是一个查询和查询处理程序的简单示例<代码>数据上下文使用SimpleInjector注入查询处理程序

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的生存期。理想情况下,我希望每个独立事务使用一个实例,在本例中,它将包括以下内容:

  • 从数据库检索批列表
  • 检索批次的质量指标列表(这些指标存储在不同的数据库中,并通过存储过程访问)
  • 更新批次,这可能包括更新数据库中的多个实体
这将引导我走向DbContext的范围化或暂时的生活方式。但是,当使用暂时的生活方式时,SimpleInjector会引发以下错误,在按如下方式注册类型时会引发此错误:

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装饰工厂,