簡體   English   中英

ASP.NET MVC 2 - 綁定到抽象模型

[英]ASP.NET MVC 2 - Binding To Abstract Model

如果我有以下強類型視圖:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<XXX.DomainModel.Core.Locations.Location>" %>

位置是抽象類。

我有以下控制器,它通過POST接受強類型模型

[HttpPost]
public ActionResult Index(Location model)

我收到一個運行時錯誤,指出“無法創建抽象類

這當然有道理。 但是 - 我不確定這里最好的解決方案是什么。

我有很多具體的類型(大約8個),這是一個只能編輯抽象類屬性的視圖。

試圖做的是為所有不同的具體類型創建重載,並以通用方法執行我的邏輯。

[HttpPost]
public ActionResult Index(City model)
{
   UpdateLocationModel(model);
   return View(model);
}

[HttpPost]
public ActionResult Index(State model)
{
   UpdateLocationModel(model);
   return View(model);
}

等等

然后:

[NonAction]
private void UpdateLocationModel (Location model)
{
   // ..snip - update model
}

但這也不起作用 ,MVC抱怨動作方法含糊不清(也很有意義)。

我們做什么? 我們可以簡單地綁定到抽象模型嗎?

如何為這個抽象類編寫自定義模型綁定器:

public class CustomBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        // TODO: based on some request parameter choose the proper child type
        // to instantiate here
        return new Child();
    }
}

只有當您有一個基於某些用戶操作動態插入輸入元素的表單時,這才有意義。 在這種情況下,您需要傳遞一些額外的參數來指示您需要哪個具體類。 否則我會堅持使用具體的視圖模型作為動作參數。

您還可以構建適用於所有抽象模型的通用ModelBinder。 我的解決方案要求您在視圖中添加一個名為“ ModelTypeName ”的隱藏字段,其值設置為您想要的具體類型的名稱。 但是,應該可以使這個更聰明,並通過將類型屬性與視圖中的字段匹配來選擇具體類型。

Application_Start()中的 Global.asax.cs文件中:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

CustomModelBinder:

public class CustomModelBinder2 : DefaultModelBinder 
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var modelType = bindingContext.ModelType;
        if (modelType.IsAbstract)
        {
            var modelTypeValue = controllerContext.Controller.ValueProvider.GetValue("ModelTypeName");
            if (modelTypeValue == null)
                throw new Exception("View does not contain ModelTypeName");

            var modelTypeName = modelTypeValue.AttemptedValue;

            var type = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == modelTypeName);

            if (type != null)
            {
                var instance= bindingContext.Model ?? base.CreateModel(controllerContext, bindingContext, type);
                bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, type);
            }
        }
        return base.BindModel(controllerContext, bindingContext);
    }
}

只是把它扔出去 - 我對別人可能回答的問題非常感興趣,但這就是我在遇到類似情況時最終做的事情;

基本上,我沒有使用模型類作為Action方法中的參數,而是傳入FormCollection並測試一些已知的鑒別器來確定要創建/編輯的類型,然后從那里使用TryUpdateModel

似乎可能有更好的方式,但我從來沒有想過要更多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM