首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AspNet核心WebApi中的自定义模型绑定?

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

Stack Overflow用户
提问于 2020-05-18 17:00:39
回答 2查看 3.1K关注 0票数 7

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

我到目前为止的尝试是:

Dtos:

代码语言:javascript
复制
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; }
}

自定义模型绑定器实现:

代码语言:javascript
复制
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,
            };
        }
    }
}

我像这样注册模型绑定器提供程序:

代码语言:javascript
复制
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers(o => o.ModelBinderProviders.Insert(0, new DeviceModelBinderProvider()));
    }

然后我的控制器:

代码语言:javascript
复制
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
    [HttpPost]
    public IActionResult Test(Device dto)
    {
        var x = dto;
        return Ok();
    }
}

我发布了一个json请求正文,如下所示:

代码语言:javascript
复制
{
    "ScreenSize": "1",
    "Kind": "SmartPhone"
}

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

EN

回答 2

Stack Overflow用户

发布于 2020-08-11 23:14:56

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

更多信息:

相关信息

所有

票数 3
EN

Stack Overflow用户

发布于 2020-05-18 17:42:11

我已经尝试了你发布的完全相同的代码,它对我来说是有效的。

这是它的价值的图像。

这是邮递员请求的截图。

来自邮递员的卷曲请求。

代码语言:javascript
复制
curl --location --request POST 'https://localhost:44332/test' \
--header 'Content-Type: application/json' \
--form 'ScreenSize=1' \
--form 'Kind=SmartPhone'

startup.cs如下图所示。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61865980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档