Asp.net mvc 使用HTTPClient的ASP.NET核心Post表单数据文件和ViewModel

Asp.net mvc 使用HTTPClient的ASP.NET核心Post表单数据文件和ViewModel,asp.net-mvc,rest,api,asp.net-core,asp.net-web-api,Asp.net Mvc,Rest,Api,Asp.net Core,Asp.net Web Api,我正在构建WebAPI和WebApp,它们都使用ASP.NET Core 2.1 我的Web应用程序正在尝试使用包含文件和其他属性的ViewModel向Web API发送post请求。我知道我必须使用MultipartFormDataContent发布IFormFile,但我不知道如何用我的ViewModel实现它,因为我的ViewModel有其他模型的列表 我已经尝试用谷歌搜索了一些解决方案,但我只找到了带有简单ViewModel的解决方案,没有如下列表: 有没有类似的解决方案 var

我正在构建WebAPI和WebApp,它们都使用ASP.NET Core 2.1

我的Web应用程序正在尝试使用包含文件和其他属性的ViewModel向Web API发送post请求。我知道我必须使用
MultipartFormDataContent
发布IFormFile,但我不知道如何用我的ViewModel实现它,因为我的ViewModel有其他模型的
列表

我已经尝试用谷歌搜索了一些解决方案,但我只找到了带有简单ViewModel的解决方案,没有如下列表:


有没有类似的解决方案

var multiContent = new MultipartFormDataContent();
var viewModelHttpContent= new StreamContent(viewModel);
MultiContent.Add(viewModelHttpContent, "viewModel");
var response = await client.PostAsJsonAsync("/some/url", multiContent);
因此,我不必将我的属性逐个添加到
MultipartFormDataContent
并将其作为json发布


这是我的Web应用程序ViewModel

public class CreateDataViewModel
{
    public string PrimaryKeyNumber{ get; set; }

    public List<Currency> ListOfCurrency { get; set; }

    public IList<DataDetail> dataDetails { get; set; }

    [DataType(DataType.Upload)]
    public IFormFile Attachment { get; set; }

    //And other properties like Boolean, Datetime?, string
}
我不知道如何用我的ViewModel实现它,因为我的ViewModel有其他模型的列表

您可以参考以下代码片段并实现自定义模型绑定器以实现您的需求

var multipartContent = new MultipartFormDataContent();

multipartContent.Add(new StringContent(viewModel.PrimaryKeyNumber), "PrimaryKeyNumber");


multipartContent.Add(new StringContent(JsonConvert.SerializeObject(viewModel.ListOfCurrency)), "ListOfCurrency");
multipartContent.Add(new StringContent(JsonConvert.SerializeObject(viewModel.dataDetails)), "dataDetails");


multipartContent.Add(new StreamContent(viewModel.Attachment.OpenReadStream()), "Attachment", viewModel.Attachment.FileName);


var response = await client.PostAsync("url_here", multipartContent);
实现自定义模型绑定器以转换传入的请求数据

public Task BindModelAsync(ModelBindingContext bindingContext)
{
    if (bindingContext == null)
    {
        throw new ArgumentNullException(nameof(bindingContext));
    }
    // code logic here
    // ...


    // ...
    // fetch the value of the argument by name
    // and populate corresponding properties of your view model

    var model = new CreateDataViewModel()
    {
        PrimaryKeyNumber = bindingContext.ValueProvider.GetValue("PrimaryKeyNumber").FirstOrDefault(),
        ListOfCurrency = JsonConvert.DeserializeObject<List<Currency>>(bindingContext.ValueProvider.GetValue("ListOfCurrency").FirstOrDefault()),
        dataDetails = JsonConvert.DeserializeObject<List<DataDetail>>(bindingContext.ValueProvider.GetValue("dataDetails").FirstOrDefault()),
        Attachment = bindingContext.ActionContext.HttpContext.Request.Form.Files.FirstOrDefault()
    };

    bindingContext.Result = ModelBindingResult.Success(model);
    return Task.CompletedTask;
}
公共任务BindModelAsync(ModelBindingContext bindingContext) { if(bindingContext==null) { 抛出新ArgumentNullException(nameof(bindingContext)); } //这里的代码逻辑 // ... // ... //按名称获取参数的值 //并填充视图模型的相应属性 var model=new CreateDataViewModel() { PrimaryKeyNumber=bindingContext.ValueProvider.GetValue(“PrimaryKeyNumber”).FirstOrDefault(), ListOfCurrency=JsonConvert.DeserializeObject(bindingContext.ValueProvider.GetValue(“ListOfCurrency”).FirstOrDefault()), dataDetails=JsonConvert.DeserializeObject(bindingContext.ValueProvider.GetValue(“dataDetails”).FirstOrDefault()), 附件=bindingContext.ActionContext.HttpContext.Request.Form.Files.FirstOrDefault() }; bindingContext.Result=ModelBindingResult.Success(model); 返回Task.CompletedTask; } 将其应用于API操作方法

public async Task<IActionResult> Create([ModelBinder(BinderType = typeof(CustomModelBinder))]CreateDataViewModel viewModel)
公共异步任务创建([ModelBinder(BinderType=typeof(CustomModelBinder))]CreateDataViewModel视图模型)
测试结果

public Task BindModelAsync(ModelBindingContext bindingContext)
{
    if (bindingContext == null)
    {
        throw new ArgumentNullException(nameof(bindingContext));
    }
    // code logic here
    // ...


    // ...
    // fetch the value of the argument by name
    // and populate corresponding properties of your view model

    var model = new CreateDataViewModel()
    {
        PrimaryKeyNumber = bindingContext.ValueProvider.GetValue("PrimaryKeyNumber").FirstOrDefault(),
        ListOfCurrency = JsonConvert.DeserializeObject<List<Currency>>(bindingContext.ValueProvider.GetValue("ListOfCurrency").FirstOrDefault()),
        dataDetails = JsonConvert.DeserializeObject<List<DataDetail>>(bindingContext.ValueProvider.GetValue("dataDetails").FirstOrDefault()),
        Attachment = bindingContext.ActionContext.HttpContext.Request.Form.Files.FirstOrDefault()
    };

    bindingContext.Result = ModelBindingResult.Success(model);
    return Task.CompletedTask;
}
public async Task<IActionResult> Create([ModelBinder(BinderType = typeof(CustomModelBinder))]CreateDataViewModel viewModel)