问题描述
我正在构建 WebAPI &WebApp,两者都使用 ASP.NET Core 2.1
我的 Web 应用程序正在尝试使用包含 IFormFile 和其他属性的 ViewModel 向 Web API 发送发布请求.我知道我必须使用 MultipartFormDataContent
来发布 IFormFile,但我不知道如何用我的 ViewModel 实现它,因为我的 ViewModel 有其他模型的 List
.
我已经尝试在谷歌上搜索一些解决方案,但我只找到了没有 List 的简单 ViewModel 解决方案,如下所示:
I'm building WebAPI & WebApp, both of them using ASP.NET Core 2.1
My Web App is trying to send post request to the Web API using ViewModel that contains IFormFile and other properties. I know I have to use MultipartFormDataContent
to post IFormFile, but I don't know how to implement it with my ViewModel because my ViewModel has List
of other model.
I already try to google some solutions, but I only found solutions with simple ViewModel without List like these :
https://stackoverflow.com/a/41511354/7906006
https://stackoverflow.com/a/55424886/7906006.
Is there any solution like
var multiContent = new MultipartFormDataContent();
var viewModelHttpContent= new StreamContent(viewModel);
MultiContent.Add(viewModelHttpContent, "viewModel");
var response = await client.PostAsJsonAsync("/some/url", multiContent);
so i don't have to add my property to MultipartFormDataContent
one by one and post it as json.
Here's my Web App 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
}
Here's my Web App controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreateDataViewModel viewModel)
{
//How to implement MultipartFormDataContent with my ViewModel in here ?
//My code below returns Could not create an instance of type Microsoft.AspNetCore.Http.IHeaderDictionary. Type is an interface or abstract class and cannot be instantiated. Path 'Attachment.Headers.Content-Disposition', line 1, position 723.
//It works fine if I don't upload a file
HttpResponseMessage res = await _client.PostAsJsonAsync<CreateDataViewModel>("api/data/create", viewModel);
var result = res.Content.ReadAsStringAsync().Result;
if (res.IsSuccessStatusCode)
{
TempData["FlashMessageSuccess"] = "Data have been submitted";
return RedirectToAction("Index", "Home"); ;
}
//Code for error checking
}
Here's my Web API controller that catches the post response using CreateDataViewModel
as parameter.
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> Create(CreateDataViewModel viewModel)
{
//Code to validate then save the data
}
You can refer to following code snippet and implement a custom model binder to achieve your requirement.
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);
Implement a custom model binder to convert incoming request data
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;
}
Apply it on API action method
public async Task<IActionResult> Create([ModelBinder(BinderType = typeof(CustomModelBinder))]CreateDataViewModel viewModel)
Test Result
这篇关于ASP.NET Core Post 表单数据 IFormFile 和 ViewModel 使用 HTTPClient的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!