【问题标题】:Using custom ModelBinder to have strongly typed TPH models in controller actions-- is this smelly?使用自定义 ModelBinder 在控制器操作中拥有强类型 TPH 模型——这很臭吗?
【发布时间】:2009-08-28 00:02:18
【问题描述】:

以下是我的解决方案的一些背景知识:

  • ASP.Net MVC 应用程序
  • 将 Linq-to-SQL 与逐层表继承结合使用
  • 默认使用 DataAnnotationsModelBinder

所以我有一个Device 抽象类,然后是一系列派生类(ServerDeviceDiskDevicePSUDevice 等),它们以被禁止的 Linq-to-SQL 方式从它继承。我有一个控制器来处理所有这些不同的相关模型类型,它会根据类型呈现不同的部分,并通过一个方便的下拉菜单来选择它们。我的 (GET) Create 方法如下所示:

// GET: /Devices/Create/3
public ActionResult Create(int? deviceTypeID)
{
    return View(DeviceFactory(deviceTypeID);
}

DeviceFactory 是一个静态方法,它返回一个基于 int 鉴别器的派生类的新实例。 POST Create 方法如下所示:

// POST: /Devices/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([ModelBinder(typeof(DeviceModelBinder))]Device device)
{
    if (!ModelState.IsValid)
            return View(device);

    _repository.Add(device);
    _repository.Save();
    TempData["message"] = string.Format("Device was created successfully.");
    return RedirectToAction(Actions.Index);
}

我的自定义模型绑定器如下所示:

public class DeviceModelBinder : DataAnnotationsModelBinder
{
    private readonly Dictionary<string, Type> _deviceTypes = 
                   new Dictionary<string, Type>
                  {
                      {"1", typeof (ServerDevice)},
                      {"2", typeof (DiskDevice)}
                      // And on and on for each derived type
                  };

    protected override object CreateModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext, Type modelType)
    {
        return base.CreateModel(controllerContext, bindingContext,
        _deviceTypes[bindingContext.ValueProvider["deviceTypeID"].AttemptedValue]);
    }
}

所以在尝试了一天之后,阅读了有关 ActionInvoker、自定义 ActionFilters 和各种其他 MVC 内容的信息,我想知道我得出的解决方案是否是一个好的解决方案。帮助减轻我对错过一些非常明显的概念并重新发明轮子的恐惧。 有更好或更简洁的方法吗?

谢谢!

【问题讨论】:

    标签: asp.net-mvc linq-to-sql inheritance binding model


    【解决方案1】:

    我的观点是,将实体/域类型绑定到 UI 是“难闻的”。我在this answer 中更详细地解释了这一点。恕我直言,您几乎应该始终使用专用的演示模型。模型绑定做一个表示模型要容易得多,这是一个很好的附带好处,但更重要的好处在链接的答案中讨论。

    【讨论】:

    • 如果模型是 POCO 怎么办?它仍然像听起来那样糟糕吗?
    • 考虑单一职责原则很重要。如果您需要向视图添加字段或重新组织视图(例如,从表格格式到层次结构),则可能需要更改视图模型。但是如果你重构你的数据库,那么你的实体/域模型需要改变。由于一个类型应该只有一个改变的理由,因此您的实体/域模型和您的视图模型应该是不同的类型。因此,决定它们应该不同的是类型的使用,而不是它们的祖先类型恰好是什么。
    • 我之前知道的事情 - 视图模型为验证和格式化添加了一个很好的扩展点。不管怎样——你说服了我。要做一些严肃的管道。
    • 实际上,我在实际代码中使用了由几个不同实体组成的 ViewModel——为了简洁起见,我只是在示例中删除了它。不幸的是,表示模型不能解决问题,因为 DefaultModelBinder 仍然不知道要绑定到基类的哪个继承者。不过,我同意您的评估,即人们应该几乎总是使用演示模型。
    • Kelly,我不久前将此报告为一个错误:connect.microsoft.com/VisualStudio/feedback/… 不幸的是,团队称其为“按设计”。解决方法是自定义 TryUpdateModel,它查看 model.GetType() 而不是 typeof(TModel)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多