C# AspNet核心WebApi中的自定义模型绑定?

C# AspNet核心WebApi中的自定义模型绑定?,c#,asp.net-core,model-binding,custom-model-binder,C#,Asp.net Core,Model Binding,Custom Model Binder,有人有一个使用多态模型绑定的自定义模型绑定的工作示例吗?我正在尝试(针对Mvc而非Api项目)一个web Api项目,但它不适用于Api项目。我认为在填充ValueProvider方面缺少一些步骤,但我找不到与此相关的任何资源(AspNet Core 3.1) 我迄今为止的努力: DTO: 自定义模型绑定器实现: public class DeviceModelBinderProvider : IModelBinderProvider { public IModelBinder GetB

有人有一个使用多态模型绑定的自定义模型绑定的工作示例吗?我正在尝试(针对Mvc而非Api项目)一个web Api项目,但它不适用于Api项目。我认为在填充
ValueProvider
方面缺少一些步骤,但我找不到与此相关的任何资源(AspNet Core 3.1)

我迄今为止的努力:

DTO:

自定义模型绑定器实现:

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,
            };
        }
    }
}
然后我的控制器:

[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
    [HttpPost]
    public IActionResult Test(Device dto)
    {
        var x = dto;
        return Ok();
    }
}
我发布了一个json请求主体,如:

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

真的很费迪普与文件,这是因为有太多的魔术正在进行。我的退路是从请求中手动解析HttpContent并反序列化。但我希望使用模型绑定器方法,如示例中所示。我看到的唯一两件奇怪的事情是,
bindingContext.ModelName
为空,而
bindingContext.ValueProvider
只有一个包含
action
controller
键的路由值提供程序。因此,它的主体看起来甚至没有被解析为值提供者。

我已经尝试了与您发布的代码完全相同的代码,并且它对我有效

这是它的价值所在

这是邮递员请求的屏幕截图

邮递员的请求

curl --location --request POST 'https://localhost:44332/test' \
--header 'Content-Type: application/json' \
--form 'ScreenSize=1' \
--form 'Kind=SmartPhone'
startup.cs
如下图所示。

格式化程序(JSON数据时使用的格式化程序)不与模型绑定\值提供程序子系统的其余部分交互。对于这个场景,您必须为正在使用的JSON库编写一个转换器

更多信息:
相关信息
  • (此答案的学分归pranavkm所有)

您使用的是哪个版本的dotnet core?能否将整个项目上传到某个地方,以便我可以尝试运行它?
.Net Core 3.1
,我认为您的请求中可能缺少
内容类型
标题。请检查此信息:“JSON数据时使用的格式化程序不与model binding\value provider子系统的其余部分交互。对于这个场景,您必须为您正在使用的JSON库编写一个转换器。这里的Source和更多信息:[AspNetCore 3.1 Api中的多态模型绑定]()这就是为什么不使用表单时它不起作用data@richardsonwtr通过你在这里的评论,我也了解了真正的原因,这将是有益的,这也是我喜欢这个社区的原因。我们帮助他人,我们从他人那里获得帮助,同时我们也获得了知识。+1对你的努力也是如此。你能解释一下json格式化程序的作用是什么吗不与模型绑定的其余部分交互?您的意思是json请求没有得到正确的解析吗?
{
    "ScreenSize": "1",
    "Kind": "SmartPhone"
}
curl --location --request POST 'https://localhost:44332/test' \
--header 'Content-Type: application/json' \
--form 'ScreenSize=1' \
--form 'Kind=SmartPhone'