草庐IT

c# - 我可以重构模型 View 查询处理程序吗?

coder 2023-07-12 原文

在我们的 MVC 应用程序中,我们所有的读取操作作为参数采用查询实现:

public interface IQuery<out TResponse> { }

在操作中,查询被传递到定位处理程序并返回 View 模型的总线。所以 Controller 现在看起来像这样:

   public ActionResult Edit(DetailsQuery query)
    {
        var model = mediator.Request(query);
        return View(model);
    }

实际上只是将查询传递给我们的调解器并返回结果。我们有数百个看起来像这样的 Action 。有一个奇怪的 Action 会做一些有条件的事情(我会保留原样)但其余的只是一次又一次地相同的样板。我们有一百多个不同的查询

如何将其重构为更明确的内容?我想转移到模型 View 查询处理程序而不是样板 Controller 操作,它只是将查询传递给总线并将模型返回给 View 。

我应该在 MVC 中查看哪些扩展点?实际上,不必编写操作处理程序 - 只需使用一些自动方法将强类型查询连接在一起并返回正确的 ViewModel。

如果可以?我是不是该?我只是不喜欢看到数百个看起来都一样的 Action 。

最佳答案

首先,感谢帖子的链接 "Put your controllers on a diet: GETs and queries" .我的代码示例使用了它的类型。

我的解决方案还涉及使用 Action 过滤器作为注入(inject)通用行为的点。

Controller 非常简单,看起来像@Kambiz Shahim 的:

[QueryFilter]
public class ConferenceController : Controller
{
    public ActionResult Index(IndexQuery query)
    {
        return View();
    }

    public ViewResult Show(ShowQuery query)
    {
        return View();
    }

    public ActionResult Edit(EditQuery query)
    {
        return View();
    }
}

正在处理 QueryFilterAttribute我意识到 IMediator并且它的实现可以省略。知道解析 IQueryHandler<,> 实例的查询类型就足够了通过 IoC。

在我的示例中 Castle Windsor和实现 'Service Locator'模式被使用。

public class QueryFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        object query = filterContext.ActionParameters["query"];
        Type queryType = query.GetType();
        Type modelType = queryType.GetInterfaces()[0].GetGenericArguments()[0];

        var handlerType = typeof(IQueryHandler<,>).MakeGenericType(queryType, modelType);

        // Here you should resolve your IQueryHandler<,> using IoC
        // 'Service Locator' pattern is used as quick-and-dirty solution to show that code works.
        var handler = ComponentLocator.GetComponent(handlerType) as IQueryHandler;

        var model = handler.Handle(query);
        filterContext.Controller.ViewData.Model = model;
    }
}

IQueryHandler添加接口(interface)以避免使用反射

/// <summary>
/// All derived handlers can be refactored using generics. But in the real world handling logic can be completely different.
/// </summary>
/// <typeparam name="TQuery">The type of the query.</typeparam>
/// <typeparam name="TResponse">The type of the response.</typeparam>
public interface IQueryHandler<in TQuery, out TResponse> : IQueryHandler
    where TQuery : IQuery<TResponse>
{
    TResponse Handle(TQuery query);
}

/// <summary>
/// This interface is used in order to invoke 'Handle' for any query type.
/// </summary>
public interface IQueryHandler
{
    object Handle(object query);
}

/// <summary>
/// Implements 'Handle' of 'IQueryHandler' interface explicitly to restrict its invocation.
/// </summary>
/// <typeparam name="TQuery">The type of the query.</typeparam>
/// <typeparam name="TResponse">The type of the response.</typeparam>
public abstract class QueryHandlerBase<TQuery, TResponse> : IQueryHandler<TQuery, TResponse>
    where TQuery : IQuery<TResponse>
{
    public abstract TResponse Handle(TQuery query);

    object IQueryHandler.Handle(object query)
    {
        return Handle((TQuery)query);
    }
}

类型应该被注册 in Global.asax.cs

        container.Register(Component.For<ISession>().ImplementedBy<FakeSession>());
        container.Register(
            Classes.FromThisAssembly()
                .BasedOn(typeof(IQueryHandler<,>))
                .WithService.Base()
                .LifestylePerWebRequest());

有一个link to gist on github包含所有代码。

关于c# - 我可以重构模型 View 查询处理程序吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19833120/

有关c# - 我可以重构模型 View 查询处理程序吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  7. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  8. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  9. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  10. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

随机推荐