簡體   English   中英

Razor Pages - 如何使用帶有抽象類的 EditorFor 模板

[英]Razor Pages - How to Use EditorFor Templates with Abstract Classes

我已經嘗試了一百萬零一種不同的東西,並傾注了無數的 SO 解決方案,但我還沒有找到一個可行的解決方案。 我有一個頁面模型,其中將包含所有從abstract class派生的不同類的列表。 對於每種類類型,我都有不同的編輯器模板。 因此,當頁面加載並且我的項目被加載時,正確的模板會顯示出來,一切都如預期的那樣。 但是,當我嘗試將表單發回時,出現了問題。 我從來沒有得到正確的值,我最終得到一個關於嘗試提交一個需要抽象類/接口的表單的錯誤。

為了退后一步並嘗試以最簡單的形式讓思想發揮作用,我們有以下場景:

public class Device
{
    public string Type => GetType().FullName;
}

public class Laptop : Device
{
    public string CPUIndex { get; set; }
}

public class SmartPhone : Device
{
    public string ScreenSize { get; set; }
}

測試頁.cshtml

<form method="post">
    @Html.EditorFor(m => m.Item, Model.Item.GetType().Name)

    <input type="submit" value="Submit"/>
</form>

筆記本電腦編輯器模板

@model Laptop

<p>Laptop</p>
<input asp-for="CPUIndex"/>

TestPage.cs(頁面模型)

public Device Item { get; set; }

public void OnGet()
{
    Item = new Laptop { CPUIndex = "Random Value" };
}

public void OnPost(Device item)
{

}

這將在我發布表單時引發異常,因為我正在嘗試訪問一個抽象類。 我在多態綁定下找到我需要創建自定義綁定的地方。

public class DeviceModelBinder : IModelBinder
{
    private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;

    public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
    {
        this.binders = binders;
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var modelKindName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(Device.Type));
        var modelTypeValue = bindingContext.ValueProvider.GetValue(modelKindName).FirstValue;

        IModelBinder modelBinder;
        ModelMetadata modelMetadata;
        if (modelTypeValue == "Laptop")
        {
            (modelMetadata, modelBinder) = binders[typeof(Laptop)];
        }
        else if (modelTypeValue == "SmartPhone")
        {
            (modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
        }
        else
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return;
        }

        var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
            bindingContext.ActionContext,
            bindingContext.ValueProvider,
            modelMetadata,
            bindingInfo: null,
            bindingContext.ModelName);

        await modelBinder.BindModelAsync(newBindingContext);
        bindingContext.Result = newBindingContext.Result;

        if (newBindingContext.Result.IsModelSet)
        {
            // Setting the ValidationState ensures properties on derived types are correctly 
            bindingContext.ValidationState[newBindingContext.Result] = new ValidationStateEntry
            {
                Metadata = modelMetadata,
            };
        }
    }
}

public class DeviceModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context.Metadata.ModelType != typeof(Device))
        {
            return null;
        }

        var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };

        var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
        foreach (var type in subclasses)
        {
            var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
            binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
        }

        return new DeviceModelBinder(binders);
    }
}

然后,我在 Startup.cs 中注冊它

 services.AddMvc(options =>
            {
                options.ModelBinderProviders.Insert(0, new DeviceModelBinderProvider());
            })

即使這一切,當我提交表單的值item在onPOST等為null。 我在這里缺少什么?

我找到了。 缺失的部分是我沒有在 HTML 中放置一個input字段來保存Type屬性。

我從此改變了我的TestPage.cshtml

<form method="post">
    @Html.EditorFor(m => m.Item, Model.Item.GetType().Name)

    <input type="submit" value="Submit"/>
</form>

對此

<form method="post">
    @Html.HiddenFor(m => m.Item.Type)
    @Html.EditorFor(m => m.Item, Model.Item.GetType().Name)

    <input type="submit" value="Submit"/>
</form>

暫無
暫無

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

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