【问题标题】:Indicate binding source for a model using a custom model binder?使用自定义模型绑定器指示模型的绑定源?
【发布时间】:2021-02-05 21:25:53
【问题描述】:

我创建了一个自定义模型绑定器来将文件和其他元数据关联在一起。因此,这要求端点接受multipart/form-data。据我了解,这可以通过在参数上应用FromForm 属性来暗示。

但是,我注意到如果我省略了 FromForm 属性,我们的 swagger 文档将无法区分并假定为 json 模型。

有没有一种方法可以注释活页夹提供者、活页夹或模型以表明它的绑定源是表单?

例如,如果我使用IFormFile,它会自动假定来自表单。如果使用我的类型,我希望它被推断出来,它也将被假定来自表单。也许这是我必须添加的一些 Swashbuckle 巫毒?

[HttpPost]
[Route("upload-files")]
public async Task<UploadFilesResult> UploadFiles(
    [FromForm] // how can I make it so this is implied so the attribute isn't needed?
    FileAndMetaModel<FileMeta> files)
{
    ...
}

【问题讨论】:

    标签: c# asp.net-core swagger model-binding swashbuckle


    【解决方案1】:
    // controller
    [HttpPost]
    public IActionResult Save([FromForm] CompanyViewModel company, IFormFileCollection files)
    {            
        // TODO           
        return Ok();
    }
    
    // startup.cs
    services.AddControllers(options => {
        options.ModelBinderProviders.Insert(0, new FromFormModelBinderProvider());
    });
    
    public class FromFormModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null) {
                throw new ArgumentNullException(nameof(context));
            }
            if (!context.Metadata.ModelType.IsPrimitive &&
                !context.Metadata.ModelType.Equals(typeof(string)) &&
                context.Metadata.BindingSource.Id == "Form") {
                return new FromFormModelBinder();
            }
            return null;
        }
    }
    
    public class FromFormModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
    
            // Fetch the value of the argument by name and set it to the model state
            string fieldName = bindingContext.FieldName;
            var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);
            if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
            else bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);
    
            // Do nothing if the value is null or empty
            string value = valueProviderResult.FirstValue;
            if (string.IsNullOrEmpty(value)) return Task.CompletedTask;
    
            try {
                // Deserialize the provided value and set the binding result
                var options = bindingContext.ActionContext.HttpContext.RequestServices.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value;
                object result = JsonConvert.DeserializeObject(value, bindingContext.ModelType, options.SerializerSettings);
                bindingContext.Result = ModelBindingResult.Success(result);
            }
            catch (JsonException) {
                bindingContext.Result = ModelBindingResult.Failed();
            }
            return Task.CompletedTask;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-07-31
      • 2018-08-22
      • 2012-02-18
      • 2012-01-29
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多