【问题标题】:MVC - one controller action with multiple model types/views or individual controller actions?MVC - 具有多种模型类型/视图或单个控制器操作的一个控制器操作?
【发布时间】:2012-02-07 06:36:10
【问题描述】:

在我的项目中,我有一个控制器,可让您创建多个不同类型的字母。所有这些字母类型都存储在数据库中,但每种字母类型都有不同的必填字段和不同的视图。

现在我为以下 URL 设置了一条路由:/Letters/Create/{LetterType}。我目前已将此映射到以下控制器操作:

public ActionResult Create(string LetterType)
{
    var model = new SpecificLetterModel();

    return View(model); 
}

我还有一个名为Create.cshtml 的视图和一个用于我特定字母类型的 EditorTemplate。这一切现在都很好,因为我只实现了一种字母类型。现在我需要继续添加其余部分,但我设置操作的方式与我实现的特定字母类型相关。

由于每个 Letter 都有自己的模型、自己的验证集和自己的视图,那么实现这些操作的最佳方式是什么?由于添加新的字母类型需要对模型/验证进行编码并创建视图,因此拥有单独的控制器操作是否更有意义:

 public ActionResult CreateABC(ABCLetterModel model);
 public ActionResult CreateXYZ(XYZLetterModel model);

或者有没有一种方法可以让我使用单个控制器操作并轻松返回正确的模型/视图?

【问题讨论】:

  • 您要求我们描述如何抽象事物,但没有解释它们的共同点

标签: asp.net-mvc


【解决方案1】:

您可以执行以下操作之一:

对每个输入都有不同的操作方法。这是因为 mvc 框架会看到 action 方法的输入,并使用默认的模型绑定器轻松绑定该类型的属性。然后,您可以拥有一个通用的私有方法来执行处理并返回视图。

假设 XYZLetterModel 和 ABCLetterModel 是某个基本模型的子类,您的控制器代码可能如下所示:

public class SomeController : Controller
    {
        private ISomeService _SomeService;

        public SomeController(ISomeService someService)
        {
            _SomeService = someService;
        }

        public ViewResult CreateABC(ABCLetterModel abcLetterModel)
        {
            // this action method exists to allow data binding to figure out the model type easily
            return PostToServiceAndReturnView(abcLetterModel);
        }

        public ViewResult CreateXYZ(XYZLetterModel xyzLetterModel)
        {
            // this action method exists to allow data binding to figure out the model type easily
            return PostToServiceAndReturnView(xyzLetterModel);
        }

        private ViewResult PostToServiceAndReturnView(BaseLetterModel model)
        {
            if (ModelState.IsValid)
            {
                // do conversion here to service input
                ServiceInput serviceInput = ToServiceInput(model);
                _SomeService.Create(serviceInput);

                return View("Success");
            }
            else
            {
                return View("Create", model);
            }
        }
    }

查看代码可能如下所示:

@model BaseLetterModel
@if (Model is ABCLetterModel)
{
    using (Html.BeginForm("CreateABC", "Some"))
    {
        @Html.EditorForModel("ABCLetter")
    }
}
else if (Model is XYZLetterModel)
{
    using (Html.BeginForm("CreateXYZ", "Some"))
    {
        @Html.EditorForModel("XYZLetter")
    }
}

您仍然可以为每种模型类型提供一个编辑器模板。

另一种选择是使用自定义模型绑定器,根据隐藏字段中的某个值确定类型,然后使用该类型对其进行序列化。

第一种方法更受欢迎,因为默认模型绑定器开箱即用,并且构建自定义模型绑定器需要大量维护。

【讨论】:

  • 您能否提供一些您所说的快速示例代码。我想我明白了,但我想确认一下。
  • 实际上,您的视图中并不需要您的 if 逻辑。如果您定义了强类型编辑器模板,只需执行 @Html.EditorForModel() 将确定要显示的适当编辑器模板
  • 那么,在您的示例中,每次添加新字母类型时我都需要创建一条新路线?我需要 URL 来保留 /letters/create/{type} 但如果我尝试使用 [ActionName] 属性,我会得到一个模棱两可的方法错误。
  • 是的,您需要为每种类型创建一个新路由,或者您可以执行 /letters/{action} 之类的路由,让它动态解析为一个操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 2011-11-21
相关资源
最近更新 更多