Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.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# 使用CQR处理中介管道中的错误/异常?_C#_Asp.net Web Api2_Autofac_Cqrs_Mediatr - Fatal编程技术网

C# 使用CQR处理中介管道中的错误/异常?

C# 使用CQR处理中介管道中的错误/异常?,c#,asp.net-web-api2,autofac,cqrs,mediatr,C#,Asp.net Web Api2,Autofac,Cqrs,Mediatr,我正试图跟随Jimmy Bogard实现一个中介管道,这样我就可以使用请求前/后处理程序来做一些工作。根据对那篇文章的评论,我得出了这个结论。我还不太明白如何把所有这些联系起来,所以这是我的第一次尝试。仅供参考-我正在使用Autofac进行DI和Web Api 2。在CQR之后,这里是一个查询 public class GetAccountRequest : IAsyncRequest<GetAccountResponse> { public int Id { get; se

我正试图跟随Jimmy Bogard实现一个中介管道,这样我就可以使用请求前/后处理程序来做一些工作。根据对那篇文章的评论,我得出了这个结论。我还不太明白如何把所有这些联系起来,所以这是我的第一次尝试。仅供参考-我正在使用Autofac进行DI和Web Api 2。在CQR之后,这里是一个查询

public class GetAccountRequest : IAsyncRequest<GetAccountResponse>
{
    public int Id { get; set; }
}

//try using fluent validation
public class GetAccountRequestValidationHandler 
    : AbstractValidator<GetAccountRequest>, IAsyncPreRequestHandler<GetAccountRequest>
{
    public GetAccountRequestValidationHandler() {
        RuleFor(m => m.Id).GreaterThan(0).WithMessage("Please specify an id.");
    }

    public Task Handle(GetAccountRequest request) {
        Debug.WriteLine("GetAccountPreProcessor Handler");   
        return Task.FromResult(true);
    }
}

public class GetAccountResponse
{
    public int AccountId { get; set; }
    public string Name { get; set; }
    public string AccountNumber { get; set; }
    public string Nickname { get; set; }
    public string PhoneNumber { get; set; }
    public List<OrderAckNotification> OrderAckNotifications { get; set; }

    public class OrderAckNotification {
        public int Id { get; set; }
        public bool IsDefault { get; set; }
        public string Description { get; set; }
        public string Type { get; set; }
    }
}
公共类GetAccountRequest:IAsyncRequest
{
公共int Id{get;set;}
}
//尝试使用fluent验证
公共类GetAccountRequestValidationHandler
:AbstractValidator,IAsyncPrequestHandler
{
public GetAccountRequestValidationHandler(){
RuleFor(m=>m.Id).greater大于(0).WithMessage(“请指定一个Id.”);
}
公共任务句柄(GetAccountRequest请求){
WriteLine(“GetAccountPreProcessor处理程序”);
返回Task.FromResult(true);
}
}
公共类GetAccountResponse
{
public int AccountId{get;set;}
公共字符串名称{get;set;}
公共字符串AccountNumber{get;set;}
公共字符串昵称{get;set;}
公共字符串PhoneNumber{get;set;}
公共列表OrderAckNotifications{get;set;}
公共类OrderAckNotification{
公共int Id{get;set;}
公共布尔值是默认值{get;set;}
公共字符串说明{get;set;}
公共字符串类型{get;set;}
}
}
GetAccountRequestHandler:

public class GetAccountRequestHandler 
    : IAsyncRequestHandler<GetAccountRequest, GetAccountResponse>
{
    private readonly IRedStripeDbContext _dbContext;

    public GetAccountRequestHandler(IRedStripeDbContext redStripeDbContext)
    {
        _dbContext = redStripeDbContext;
    }

    public async Task<GetAccountResponse> Handle(GetAccountRequest message)
    {
        //some mapping code here.. omitted for brevity
        Mapper.AssertConfigurationIsValid();

        return await _dbContext.Accounts.Where(a => a.AccountId == message.Id)
            .ProjectToSingleOrDefaultAsync<GetAccountResponse>();
    }
公共类GetAccountRequestHandler
:IAsyncRequestHandler
{
私有只读IRedStripeDbContext _dbContext;
公共GetAccountRequestHandler(IRedStripeDbContext redStripeDbContext)
{
_dbContext=redStripeDbContext;
}
公共异步任务句柄(GetAccountRequest消息)
{
//此处的一些映射代码..为简洁起见省略
assertConfigurationsValid();
return await _dbContext.Accounts.Where(a=>a.AccountId==message.Id)
.ProjectToSingleOrDefaultAsync();
}
下面是显示HttpGet的当前web api 2控制器

[RoutePrefix("api/Accounts")]
public class AccountsController : ApiController
{
    private readonly IMediator _mediator;

    public AccountsController(IMediator mediator)
    {
        _mediator = mediator;
    }

    // GET: api/Accounts/2
    [Route("{id:int}")]
    [HttpGet]
    public async Task<IHttpActionResult> GetById([FromUri] GetAccountRequest request)
    {
        var model = await _mediator.SendAsync<GetAccountResponse>(request);

        return Ok(model);
    }
}
[RoutePrefix(“api/账户”)]
公共类帐户控制器:ApiController
{
专用只读IMediator\u中介;
公共账户控制人(IMediator调解人)
{
_调解人=调解人;
}
//获取:api/Accounts/2
[路由(“{id:int}”)]
[HttpGet]
公共异步任务GetById([FromUri]GetAccountRequest请求)
{
var model=wait\u mediator.SendAsync(请求);
返回Ok(型号);
}
}
最后,这里是依赖项解析代码:

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();

    ConfigureDependencyInjection(app, config);

    WebApiConfig.Register(config);
    app.UseWebApi(config);
}

private static void ConfigureDependencyInjection(IAppBuilder app, 
    HttpConfiguration config)
{
    var builder = new ContainerBuilder();
    builder.RegisterSource(new ContravariantRegistrationSource());
    builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();

    builder.Register<SingleInstanceFactory>(ctx =>
    {
        var c = ctx.Resolve<IComponentContext>();
        return t => c.Resolve(t);
    });

    builder.Register<MultiInstanceFactory>(ctx =>
    {
        var c = ctx.Resolve<IComponentContext>();
        return t => (IEnumerable<object>)c.Resolve(
            typeof(IEnumerable<>).MakeGenericType(t));
    });

    //register all pre handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(t => t.IsClosedTypeOf(typeof(IAsyncPreRequestHandler<>))));

    //register all post handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(t => t.IsClosedTypeOf(typeof(IAsyncPostRequestHandler<,>))));


    //register all handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(t => t.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
            .Select(t => new KeyedService("asyncRequestHandler", t)));

    //register pipeline decorator
    builder.RegisterGenericDecorator(typeof(AsyncMediatorPipeline<,>), 
        typeof(IAsyncRequestHandler<,>), "asyncRequestHandler");

    // Register Web API controller in executing assembly.
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();

    //register RedStripeDbContext
    builder.RegisterType<RedStripeDbContext>().As<IRedStripeDbContext>()
        .InstancePerRequest();

    builder.RegisterType<AutofacServiceLocator>().AsImplementedInterfaces();
    var container = builder.Build();

    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

    // This should be the first middleware added to the IAppBuilder.
    app.UseAutofacMiddleware(container);

    // Make sure the Autofac lifetime scope is passed to Web API.
    app.UseAutofacWebApi(config);
}
public void配置(IAppBuilder应用程序)
{
var config=新的HttpConfiguration();
ConfigureDependencyInjection(应用程序,配置);
WebApiConfig.Register(配置);
app.UseWebApi(配置);
}
私有静态无效配置依赖注入(IAppBuilder应用程序,
HttpConfiguration(配置)
{
var builder=new ContainerBuilder();
RegisterSource(新的ContrariantRegistrationSource());
RegisterAssemblyTypes(typeof(IMediator.Assembly).assemplementedInterfaces();
builder.Register(ctx=>
{
var c=ctx.Resolve();
返回t=>c.Resolve(t);
});
builder.Register(ctx=>
{
var c=ctx.Resolve();
返回t=>(IEnumerable)c.Resolve(
typeof(IEnumerable).MakeGenericType(t));
});
//注册所有预处理程序
builder.RegisterAssemblyTypes(Assembly.getExecutionGassembly())
.As(type=>type.GetInterfaces()
其中(t=>t.IsClosedTypeOf(typeof(iasyncprequestHandler)));
//注册所有post处理程序
builder.RegisterAssemblyTypes(Assembly.getExecutionGassembly())
.As(type=>type.GetInterfaces()
其中(t=>t.IsClosedTypeOf(typeof(IAsyncPostRequestHandler)));
//注册所有处理程序
builder.RegisterAssemblyTypes(Assembly.getExecutionGassembly())
.As(type=>type.GetInterfaces()
.Where(t=>t.IsClosedTypeOf(typeof(IAsyncRequestHandler)))
.Select(t=>newkeyedservice(“asyncRequestHandler”,t));
//注册管道装饰器
builder.RegisterGenericDecorator(typeof(AsyncMediaPipeline),
typeof(IAsyncRequestHandler),“asyncRequestHandler”);
//在执行程序集中注册Web API控制器。
RegisterAppController(Assembly.getExecutionGassembly()).InstancePerRequest();
//注册RedStripeDbContext
builder.RegisterType().As()
.InstancePerRequest();
builder.RegisterType().AsImplementedInterfaces();
var container=builder.Build();
config.DependencyResolver=新的AutoFacWebApidencyResolver(容器);
//这应该是第一个添加到IAppBuilder的中间件。
app.useautofac中间件(容器);
//确保Autofac生存期范围已传递给Web API。
app.UseAutofacWebApi(配置);
}

我正在进入GetAccountRequestValidationHandler。但是,当验证失败(传递的id为0)时,如何引发异常或停止管道的执行?如何返回.WithMessage?

我也在努力解决这个问题。似乎有两个/三个选项:

使用预处理程序…

1) 您可以将错误加载到请求中,并让主处理程序在处理命令/查询之前检查错误

2) 让预处理程序抛出一个异常。似乎在这个实践中有相当多的分歧。一方面,它感觉像是用异常管理控制流,但“pro”camp认为客户端应该首先负责发送一个有效的命令。也就是说,它可以发送ajax查询以确认用户名是否可用,然后再让用户单击“创建帐户”。在这种情况下,违反此规则的异常将是由于竞争条件

将验证处理程序直接放入管道。

我相信这更重要
public class AsyncValidationPipeline<TRequest, TResponse> : IAsyncRequestHandler<TRequest, TResponse>
    where TRequest : IAsyncRequest<TResponse>
{
    private IAsyncRequestHandler<TRequest, TResponse> _inner;
    private IValidator<TRequest>[] _validators;

    public AsyncValidationPipeline(IAsyncRequestHandler<TRequest, TResponse> inner,
        IValidator<TRequest>[] validators)
    {
        _inner = inner;
        _validators = validators;
    }
    public Task<TResponse> Handle(TRequest message)
    {
        List<string> errors = new List<string>();
        if (_validators != null && _validators.Any())
        {
            errors = _validators.Where(v => v.Fails(message))
                .Select(v => v.ErrorMessage);
        }

        if (errors.Any())
        {
            throw new ValidationException(errors);
        }
        return _inner.Handle(message);
    }
}
            //register all pre handlers
            builder.RegisterAssemblyTypes(assembliesToScan)
                .AsClosedTypesOf(typeof(IAsyncPreRequestHandler<>));

            //register all post handlers
            builder.RegisterAssemblyTypes(assembliesToScan)
                .AsClosedTypesOf(typeof(IAsyncPostRequestHandler<,>));

            const string handlerKey = "async-service-handlers";
            const string pipelineKey = "async-service-pipelines";

            // Request/Response for Query

            builder.RegisterAssemblyTypes(assembliesToScan)
                .AsKeyedClosedTypesOf(typeof(IAsyncRequestHandler<,>), handlerKey)
                ;

            // Decorate All Services with our Pipeline
            //builder.RegisterGenericDecorator(typeof(MediatorPipeline<,>), typeof(IRequestHandler<,>), fromKey: "service-handlers", toKey: "pipeline-handlers");
           builder.RegisterGenericDecorator(typeof(AsyncMediatorPipeline<,>), typeof(IAsyncRequestHandler<,>), fromKey: handlerKey, toKey: pipelineKey);

            // Decorate All Pipelines with our Validator
           builder.RegisterGenericDecorator(typeof(AsyncValidationHandler<,>), typeof(IAsyncRequestHandler<,>), fromKey: pipelineKey);//, toKey: "async-validator-handlers");

           // Add as many pipelines as you want, but the to/from keys must be kept in order and unique