我正在构建WebAPI&WebApp,它们都使用ASP.NET Core 2.1
我的Web应用程序正尝试使用包含IFormFile和其他属性的ViewModel将发布请求发送到Web API.我知道我必须使用 MultipartFormDataContent 来发布IFormFile,但是我不知道如何使用ViewModel来实现它,因为我的ViewModel具有其他模型的 List .
我已经尝试过搜索一些解决方案,但是我只找到了简单的ViewModel而没有类似List的解决方案:
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 :
stackoverflow/a/41511354/7906006
stackoverflow/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 }解决方案
don't know how to implement it with my ViewModel because my ViewModel has List of other model
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使用HTTPClient使用ViewModel发布表单数据IFormFile
发布评论