簡體   English   中英

ASP.NET Core和formdata綁定文件和json屬性

[英]ASP.NET Core and formdata binding with file and json property

我有以下型號:

public class MyJson
{
 public string Test{get;set;}
}

public class Dto
{
 public IFormFile MyFile {get;set;}
 public MyJson MyJson {get;set;}
}

在客戶端,我想發送一個文件和一個json。 所以我使用以下鍵在formData中發送它:

var formData = new FormData();
formData["myFile"] = file//here is my file
formData["myJson"] = obj; // object to be serialized to json.

我的動作如下:

public void MyAction(Dto dto) // or with [FromForm], doesn't really matter
{
  //dto.MyJson is null here
  //dto.myFile is set correctly.
}

如果我將dto.MyJson更改為字符串然后它完全正常,但我必須在操作中手動將其反序列化為我的對象。 將它作為一個字符串的第二個問題是我不能使用swagger UI來正確處理它,因為它會問我一個json字符串而不是對象,無論如何將它作為一個字符串聽起來不正確。 是否有一種本機方式來處理json並在操作參數中正確歸檔,而不是使用Request.Form手動解析它?

這可以使用自定義模型綁定器來完成:

public class FormDataJsonBinder : 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
            object result = JsonConvert.DeserializeObject(value, bindingContext.ModelType);
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        catch(JsonException)
        {
            bindingContext.Result = ModelBindingResult.Failed();
        }

        return Task.CompletedTask;
    }
}

然后,您可以在DTO類中使用ModelBinder屬性來指示應該使用此綁定器來綁定MyJson屬性:

public class Dto
{
    public IFormFile MyFile {get;set;}

    [ModelBinder(BinderType = typeof(FormDataJsonBinder))]
    public MyJson MyJson {get;set;}
}

請注意,您還需要在客戶端中正確地序列化JSON數據:

const formData = new FormData();
formData.append(`myFile`, file);
formData.append('myJson', JSON.stringify(obj));

上面的代碼可以使用,但您也可以更進一步定義自定義屬性和自定義IModelBinderProvider這樣您每次執行此操作時都不需要使用更詳細的ModelBinder屬性。 請注意,我已經為此重新使用了現有的[FromForm]屬性,但您也可以定義自己的屬性來代替使用。

public class FormDataJsonBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if(context == null) throw new ArgumentNullException(nameof(context));

        // Do not use this provider for binding simple values
        if(!context.Metadata.IsComplexType) return null;

        // Do not use this provider if the binding target is not a property
        var propName = context.Metadata.PropertyName;
        var propInfo = context.Metadata.ContainerType?.GetProperty(propName);
        if(propName == null || propInfo == null) return null;

        // Do not use this provider if the target property type implements IFormFile
        if(propInfo.PropertyType.IsAssignableFrom(typeof(IFormFile))) return null;

        // Do not use this provider if this property does not have the FromForm attribute
        if(!propInfo.GetCustomAttributes(typeof(FromForm), false).Any()) return null;

        // All criteria met; use the FormDataJsonBinder
        return new FormDataJsonBinder();
    }
}

在獲取之前,您需要將此模型綁定程序提供程序添加到啟動配置中:

services.AddMvc(options =>
{
    // add custom model binders to beginning of collection
    options.ModelBinderProviders.Insert(0, new FormDataJsonBinderProvider())
});

然后你的DTO可以更簡單一些:

public class Dto
{
    public IFormFile MyFile {get;set;}

    [FromForm]
    public MyJson MyJson {get;set;}
}

您可以在ASP.NET Core文檔中閱讀有關自定義模型綁定的更多信息: https//docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding

暫無
暫無

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

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