gpt4 book ai didi

c# - 如何将验证处理从 Controller 操作转移到装饰器

转载 作者:可可西里 更新时间:2023-11-01 09:14:54 26 4
gpt4 key购买 nike

维护编辑

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

[Route("items/add", RouteMethod.Post)]
public class AddItemCommand { public Guid Id { get; set; } }

[Route("items", RouteMethod.Get)]
public class GetItemsQuery : IQuery<GetItemsResponse> { }

// The response inherits from a base type that handles
// validation messages and the like
public class GetItemsResponse : ServiceResponse { }

然后我实现了一个 MVC 主机,它提取带注释的命令/查询并在启动时为我生成 Controller 和处理程序。有了这个,我的应用程序逻辑终于摆脱了 MVC 的束缚。查询响应也会自动填充验证消息。我的 MVC 应用程序现在看起来像这样:

+ MvcApp  +- Global.asax  +- Global.asax.cs - Startup the host and done  +- Web.config

After realizing I really don't use MVC outside the host - and constantly having issues with the bazillion dependencies the framework has - I implemented another host based on NServiceKit. Nothing had to be changed in my application logic and the dependencies are down to System.Web, NServiceKit and NServiceKit.Text that takes good care of the model binding. I know it's a very similar approach to how NServiceKit/ServiceStack does their stuff but I'm now totally decoupled from the web framework in use so in case a better one comes along I just implement another host and that's it.

The situation

I'm currently working on an ASP.NET MVC site that's implementing the businesslogic-view separation via the IQueryHandler and ICommandHandler abstractions (using the almighty SimpleInjector for dependency injection).

The Problem

I've got to attach some custom validation logic to a QueryHandler via a decorator and that's working pretty well in and of itself. The problem is that in the event of validation errors I want to be able to show the same view that the action would have returned but with information on the validation error of course. Here is a sample for my case:

public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;

public ActionResult Index()
{
try
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
return this.View(new HomeViewModel());
}
catch (ValidationException exception)
{
this.ModelState.AddModelErrors(exception);
return this.View(new HomeViewModel());
}
}
}

在这种情况下,我有一些由 queryHandler 处理的业务逻辑装饰有 ValidationQueryHandlerDecorator抛出 ValidationException在适当的时候。

我想让它做什么

我想要的是:

public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;

public ActionResult Index()
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
// There is a catch-all in place for unexpected exceptions but
// for ValidationExceptions I want to do essentially the same
// view instantiation but with the model errors attached
return this.View(new HomeViewModel());
}
}

我一直在想一个特别的ValidationErrorHandlerAttribute但后来我失去了上下文,我无法真正返回正确的 View 。我只是包装 IQueryHandler<,> 的方法也是如此。使用装饰器...我看到了一些奇怪的代码片段,它们在路由上进行了一些字符串嗅探,然后通过 Activator.CreateInstance 实例化了一个新的 Controller 和 View 模型。 - 这似乎不是个好主意。

所以我想知道是否有一个很好的方法来做到这一点……也许我只是没有从树上看到木头。谢谢!

最佳答案

我不认为有什么方法可以让 action 方法忽略这一点,因为 action 方法控制着返回的 View 模型,并且在验证异常的情况下,您需要返回一个包含所有实际数据(以防止用户丢失他的更改)。但是,为了使这更方便,您可以做的是添加一个扩展方法来在操作中执行查询:

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 扩展方法可能如下所示:

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;
}
}

请注意,如果验证是针对用户输入的数据,您应该只捕获此类验证异常。如果您发送带有以编程方式设置的参数的查询,则验证异常仅意味着编程错误,您应该写博客、记录异常并向用户显示友好的错误页面。

关于c# - 如何将验证处理从 Controller 操作转移到装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24010538/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com