簡體   English   中英

AspNet Core WebApi中的多態model綁定?

[英]Polymorphic model binding in AspNet Core WebApi?

任何人都有一個自定義 model 綁定與多態 model 綁定的工作示例? I'm trying this example (which is for Mvc not Api projects) with a web api project but it's not working for API projects. 我認為在填充ValueProvider方面缺少一些步驟,但我找不到與此相關的任何資源(AspNet Core 3.1)。

到目前為止我的嘗試:

Dtos:

public abstract class Device
{
    public string Kind { get; set; }
}

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

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

自定義 model 綁定器實現:

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);
    }
}

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.Kind));
        var modelTypeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        IModelBinder modelBinder;
        ModelMetadata modelMetadata;
        if (modelTypeValue.FirstValue == "Laptop")
        {
            (modelMetadata, modelBinder) = binders[typeof(Laptop)];
        }
        else if (modelTypeValue.FirstValue == "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,
            };
        }
    }
}

我像這樣注冊 model 活頁夾提供者:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(o => o.ModelBinderProviders.Insert(0, new DeviceModelBinderProvider()));
    }

然后我的 controller:

[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
    [HttpPost]
    public IActionResult Test(Device dto)
    {
        var x = dto;
        return Ok();
    }
}

我發布了一個 json 請求正文,例如:

{
    "ScreenSize": "1",
    "Kind": "SmartPhone"
}

真的厭倦了這方面的文檔,因為發生了太多的魔法。 我的后備是從請求中手動解析 HttpContent 並反序列化。 但我希望像示例中那樣使用 model 活頁夾方法。 我看到的唯一兩件奇怪的事情是bindingContext.ModelName是空的, bindingContext.ValueProvider只有一個包含actioncontroller鍵的路由值提供程序。 因此,看起來主體甚至沒有解析到值提供者中。

當 JSON 數據不與 model 綁定\值提供程序子系統的 rest 交互時使用的格式化程序。 對於這種情況,您必須為您正在使用的 JSON 庫編寫轉換器。

更多信息:

相關信息

我已經嘗試過與您發布的完全相同的代碼,並且它對我有用。

這是其價值的形象。

在此處輸入圖像描述

這是 postman 請求的屏幕截圖。

在此處輸入圖像描述

來自 postman 的 CURL 請求。

curl --location --request POST 'https://localhost:44332/test' \
--header 'Content-Type: application/json' \
--form 'ScreenSize=1' \
--form 'Kind=SmartPhone'

startup.cs如下圖所示。 在此處輸入圖像描述

暫無
暫無

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

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