Postman 表单数据到 ASP.NET Core 2.2 控制器未绑定到具有私有设置器的命令

工具

  • 视觉工作室 2017

  • ASP.NET 核心 2.2

  • 邮递员 v7.2.0

我想做什么

将 FormData 从 Postman 发送到 ASP.NET Core 控制器,并将来自请求的数据绑定到具有私有设置器属性的命令类。

我已经使用相同的设置(私有设置器)毫无问题地发送了 JSON 数据。该FromBody属性将 JSON 字符串反序列化为模型而不会出现错误。

问题

如果模型具有私有设置器,则原始类型的属性不会绑定。但是,复杂类型与访问修饰符无关。

控制器

[HttpPost]

[ProducesResponseType((int)HttpStatusCode.OK)]

[ProducesResponseType((int)HttpStatusCode.BadRequest)]

public async Task<IActionResult> CreateItemAsync([FromForm]CreateItemCommand command)

{

    bool result = false;


    commandResult = await _mediator.Send(command);


    if (!commandResult)

    {

        return BadRequest();

    }


    return Ok();

}

命令


注意:该Title属性已被故意保留为 public setter 以说明行为


[DataContract]

public class CreateItemCommand

    :IRequest<bool>

{

    [DataMember]

    public string Title { get; set; }


    [DataMember]

    public string Description { get; private set; }


    [DataMember]

    public int Count { get; private set; }


    [DataMember]

    public HashSet<string> Tags { get; private set; }


    [DataMember]

    public string ItemDate { get; private set; }


    [DataMember]

    public List<IFormFile> Documents { get; private set; }


    public CreateItemCommand()

    {

        Skills = new HashSet<string>();

        Systems = new HashSet<string>();

    }


    public CreateItemCommand(string title, string description, 

        int count, HashSet<string> tags, string itemDate, 

        List<IFormFile> documents)

        : this()

    {

        Title = title;

        Description = description;

        Count = count

        Tags = tags;

        ItemDate = itemDate;

        Documents = documents;

    }

}

在 Postman 中,我现在将请求设置如下:

在此处输入图像描述

我不得不混淆一些信息,但您可以看到没有设置带有私有 setter 的原始类型。

在此处输入图像描述

问题

  1. 为什么属性访问修饰符只影响原始类型的属性?

  2. 为什么参数属性设置为时会出现这种情况,FromForm设置为时却不会FromBody


慕沐林林
浏览 121回答 1
1回答

繁星点点滴滴

为什么属性访问修饰符只影响原始类型的属性?对于 Asp.Net Core ModelBinder,它将通过下面的ComplexTypeModelBinder代码检查该属性是否为私有访问设置器:protected virtual object CreateModel(ModelBindingContext bindingContext){    if (bindingContext == null)    {        throw new ArgumentNullException(nameof(bindingContext));    }    // If model creator throws an exception, we want to propagate it back up the call stack, since the    // application developer should know that this was an invalid type to try to bind to.    if (_modelCreator == null)    {        // The following check causes the ComplexTypeModelBinder to NOT participate in binding structs as        // reflection does not provide information about the implicit parameterless constructor for a struct.        // This binder would eventually fail to construct an instance of the struct as the Linq's NewExpression        // compile fails to construct it.        var modelTypeInfo = bindingContext.ModelType.GetTypeInfo();        if (modelTypeInfo.IsAbstract || modelTypeInfo.GetConstructor(Type.EmptyTypes) == null)        {            var metadata = bindingContext.ModelMetadata;            switch (metadata.MetadataKind)            {                case ModelMetadataKind.Parameter:                    throw new InvalidOperationException(                        Resources.FormatComplexTypeModelBinder_NoParameterlessConstructor_ForParameter(                            modelTypeInfo.FullName,                            metadata.ParameterName));                case ModelMetadataKind.Property:                    throw new InvalidOperationException(                        Resources.FormatComplexTypeModelBinder_NoParameterlessConstructor_ForProperty(                            modelTypeInfo.FullName,                            metadata.PropertyName,                            bindingContext.ModelMetadata.ContainerType.FullName));                case ModelMetadataKind.Type:                    throw new InvalidOperationException(                        Resources.FormatComplexTypeModelBinder_NoParameterlessConstructor_ForType(                            modelTypeInfo.FullName));            }        }        _modelCreator = Expression            .Lambda<Func<object>>(Expression.New(bindingContext.ModelType))            .Compile();    }    return _modelCreator();}为什么当参数属性设置为 FromForm 时会出现这种情况,而设置为 FromBody 时不会出现这种情况对于FromBody,它用于JsonInputFormatter从正文请求中绑定模型,它用于JsonConvert.DeserializeObject反序列化对象并Newtonsoft.Json支持从 json 字符串中反序列化包含私有 setter 的对象。
打开App,查看更多内容
随时随地看视频慕课网APP