C# 如何将验证处理从控制器操作移动到装饰器 维护编辑

C# 如何将验证处理从控制器操作移动到装饰器 维护编辑,c#,asp.net-mvc,decorator,simple-injector,C#,Asp.net Mvc,Decorator,Simple Injector,在使用这种方法一段时间后,我发现自己只在每个控制器中添加了完全相同的样板代码,所以我决定做一些反射魔术。与此同时,我放弃了在视图中使用MVC——Razor是如此乏味和丑陋——所以我基本上使用我的处理程序作为JSON后端。我目前使用的方法是使用Route属性装饰我的查询/命令,该属性位于一些常见程序集中,如下所示: + MvcApp +- Global.asax +- Global.asax.cs - Startup the host and done +- Web.config pu

在使用这种方法一段时间后,我发现自己只在每个控制器中添加了完全相同的样板代码,所以我决定做一些反射魔术。与此同时,我放弃了在视图中使用MVC——Razor是如此乏味和丑陋——所以我基本上使用我的处理程序作为JSON后端。我目前使用的方法是使用
Route
属性装饰我的查询/命令,该属性位于一些常见程序集中,如下所示:

+ MvcApp +- Global.asax +- Global.asax.cs - Startup the host and done +- Web.config
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
    this IQueryHandler<TQuery, TResult> handler,
    TQuery query, ModelStateDictionary modelState)
{
    try
    {
        return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
    }
    catch (ValidationException ex)
    {
        modelState.AddModelErrors(ex);
        return ValidatedResult<TResult>.Invalid;
    }
}
[路线(“项目/添加”,路线方法.发布)]
公共类AddItemCommand{public Guid Id{get;set;}}
[路线(“项目”,路线方法获取)]
公共类GetItemsQuery:IQuery{}
//响应继承自处理
//验证消息等
公共类GetItemsResponse:ServiceResponse{}
然后,我实现了一个MVC主机,它提取带注释的命令/查询,并在启动时为我生成控制器和处理程序。有了它,我的应用程序逻辑终于摆脱了MVC的束缚。查询响应也会自动填充验证消息。我的MVC应用程序现在都是这样的:

+ MvcApp +- Global.asax +- Global.asax.cs - Startup the host and done +- Web.config
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
    this IQueryHandler<TQuery, TResult> handler,
    TQuery query, ModelStateDictionary modelState)
{
    try
    {
        return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
    }
    catch (ValidationException ex)
    {
        modelState.AddModelErrors(ex);
        return ValidatedResult<TResult>.Invalid;
    }
}
在这个场景中,我有一些由
queryHandler
处理的业务逻辑,该逻辑由
validationqueryhandledecorator
修饰,在适当的时候抛出
ValidationException
s

我想要它做什么 我想要的东西大致如下:

公共类HomeController:控制器
{
专用只读IQueryHandler查询处理程序;
公共行动结果索引()
{
var dto=this.queryHandler.Handle(newsomequery{/*…*/});
//用数据做一些很棒的事情。。。
//对于意外的异常,有一个全面的解决方案,但是
//对于ValidationException,我基本上也要这样做
//视图实例化,但附加了模型错误
返回此.View(新的HomeViewModel());
}
}
我一直在考虑一个特殊的
ValidationErrorHandlerAttribute
,但是我失去了上下文,无法返回正确的视图。我只是用一个装饰器包装
IQueryHandler
的方法也是如此。。。我见过一些奇怪的代码片段,它们在路由上进行了一些字符串嗅探,然后通过
Activator.CreateInstance
,实例化了一个新的控制器和视图模型,这似乎不是一个好主意


所以我想知道是否有一个很好的方法来做到这一点。。。也许我只是看不见树林。谢谢

我认为没有办法让action方法忽略这一点,因为action方法控制着返回的视图模型,如果出现验证异常,您需要返回一个包含所有实际数据的视图模型(以防止用户丢失其更改)。但是,为了使此操作更加方便,您可以添加一个扩展方法,用于在操作中执行查询:

public ActionResult Index()
{
    var result = this.queryHandler.ValidatedHandle(this.ModelState, new SomeQuery { });

    if (result.IsValid) {
        return this.View(new HomeViewModel(result.Data));
    }
    else
    {
        return this.View(new HomeViewModel());
    }
}
ValidatedHandle
扩展方法可能如下所示:

+ MvcApp +- Global.asax +- Global.asax.cs - Startup the host and done +- Web.config
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
    this IQueryHandler<TQuery, TResult> handler,
    TQuery query, ModelStateDictionary modelState)
{
    try
    {
        return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
    }
    catch (ValidationException ex)
    {
        modelState.AddModelErrors(ex);
        return ValidatedResult<TResult>.Invalid;
    }
}
public static ValidatedResult ValidatedHandle(
这是一个处理程序,
TQuery查询,modelState字典(modelState)
{
尝试
{
返回新的ValidatedResult.CreateValid(handler.Handle(query));
}
捕获(ValidationException ex)
{
modelState.AddModelErrors(ex);
返回ValidatedResult.Invalid;
}
}

请注意,只有在用户输入的数据上进行验证时,才应捕获此类验证异常。如果用编程方式设置的参数发送查询,则验证异常仅仅意味着编程错误,并且您应该进行日志记录,记录异常并向用户显示友好的错误页。< / P>这是一个很好的触摸,我确实考虑了控制器上的扩展方法,但不考虑<代码> IQueryHandler < /代码>。我试试看。再次感谢@vanhelgen:在我最近做的一个win forms项目中,我们没有注入我们的
ICommandHandler
,而是注入了一个
IPromptableCommandHandler
(我谈到了这一点)。实现捕获了异常并将其显示给用户。使用扩展方法几乎是相同的。我们定义了一个新的抽象,因为实现需要一些额外的服务,否则就需要调用方传递这些服务。我一直在玩弄这个,我也看不到比你更好的方法,所以我现在将使用这个方法。感谢您的建议和
IPromptableCommandHandler
链接。我已经有了通知用户验证错误的功能,但我会在将来记住它。总是很荣幸:-)