无法将当前JSON数组(例如)反序列化为类型’TenantManagementWebApi.Entities.Tenant

我有以下错误:

JsonSerializationException:无法将当前JSON数组(例如[1,2,3] )反序列化为类型'TenantManagementWebApi.Entities.Tenant'因为该类型需要JSON对象(例如{"name":"value"} )才能正确反序列化。

要修复此错误,请将JSON更改为JSON对象(例如{"name":"value"} )或将反序列化类型更改为数组或实现集合接口的类型(例如ICollection, IList ),如List可以从JSON数组反序列化。 JsonArrayAttribute也可以添加到类型中以强制它从JSON数组反序列化。 路径”,第1行,第1位。

我的网络api是这样的:

 public class TenantModelBinder : IModelBinder { public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { if (bindingContext.ModelType != typeof(Tenant)) { return false; } var task = Task.Run(async () => { var model = new Tenant(); if (!actionContext.Request.Content.IsMimeMultipartContent()) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "WebRequeest content 'multipart/form-data' is valid"); } else { var provider = await actionContext.Request.Content.ReadAsMultipartAsync(); //var fileContent = provider.Contents.FirstOrDefault(n => n.Headers.ContentDisposition.Name.Equals("file")); var fileContent = provider.Contents.FirstOrDefault(n => n.Headers.ContentDisposition.Name.Equals(@"""file""")); if (fileContent == null) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Section 'file' is missed"); } //var modelContent = provider.Contents.FirstOrDefault(n => n.Headers.ContentDisposition.Name.Equals("model")); var modelContent = provider.Contents.FirstOrDefault(n => n.Headers.ContentDisposition.Name.Equals(@"""model""")); if (modelContent == null) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Section 'model' is missed"); } if (fileContent != null && modelContent != null) { model = JsonConvert.DeserializeObject(await modelContent.ReadAsStringAsync()); //model.Text = ""; model.ContentType = provider.Contents[0].Headers.ContentType.MediaType; model.CertificateFile = await fileContent.ReadAsByteArrayAsync(); //model.TenantId = fileContent.Headers.ContentDisposition.FileName; } } return model; }); task.Wait(); bindingContext.Model = task.Result; return true; } } [HttpPut] public async Task PutTenant([ModelBinder(typeof(TenantModelBinder))] Tenant tenant) { //var provider = new MultipartMemoryStreamProvider(); //var contentType = ""; //var content = new byte[0]; //await base.Request.Content.ReadAsMultipartAsync(provider); //if (provider.Contents.Count > 0) //{ // contentType = provider.Contents[0].Headers.ContentType.MediaType; // content = await provider.Contents[0].ReadAsByteArrayAsync(); //} CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["AzureStorageKey"].ToString()); // Create the blob client. CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); // Retrieve reference to a previously created container. CloudBlobContainer container = blobClient.GetContainerReference(ConfigurationManager.AppSettings["certificatesContainer"].ToString()); // Retrieve reference to a blob named "myblob". CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob"); // Create or overwrite the "myblob" blob with contents from a local file. blockBlob.Properties.ContentType = tenant.ContentType; MemoryStream stream = new MemoryStream(tenant.CertificateFile); blockBlob.UploadFromStream(stream); var tenantStore = CosmosStoreFactory.CreateForEntity(); tenant.CertificatePath = blockBlob.Uri; if (!ModelState.IsValid) { return BadRequest(ModelState); } var added = await tenantStore.AddAsync(tenant); return StatusCode(HttpStatusCode.NoContent); } public class Tenant { public string TenantId { get; set; } public string TenantUrl { get; set; } public Uri CertificatePath { get; set; } public string CertificatePassword { get; set; } public byte[] CertificateFile { get; set; } public string ContentType { get; set; } public override string ToString() { return JsonConvert.SerializeObject(this); } } 

还有我的React组件

 import React, { Component } from 'react'; import { Row, Col } from 'antd'; import PageHeader from '../../components/utility/pageHeader'; import Box from '../../components/utility/box'; import LayoutWrapper from '../../components/utility/layoutWrapper.js'; import ContentHolder from '../../components/utility/contentHolder'; import basicStyle from '../../settings/basicStyle'; import IntlMessages from '../../components/utility/intlMessages'; import { adalApiFetch } from '../../adalConfig'; export default class extends Component { constructor(props) { super(props); this.state = {TenantId: '', TenantUrl: '', TenantPassword: '' }; this.handleChangeTenantUrl = this.handleChangeTenantUrl.bind(this); this.handleChangeTenantPassword = this.handleChangeTenantPassword.bind(this); this.handleChangeTenantId= this.handleChangeTenantId.bind(this); this.handleSubmit = this.handleSubmit.bind(this); }; handleChangeTenantUrl(event){ this.setState({TenantUrl: event.target.value}); } handleChangeTenantPassword(event){ this.setState({TenantPassword: event.target.value}); } handleChangeTenantId(event){ this.setState({TenantId: event.target.value}); } handleSubmit(event){ event.preventDefault(); let data = new FormData(); //Append files to form data data.append("model", {"TenantId": this.state.TenantId, "TenantUrl": this.state.TenantUrl, "TenantPassword": this.state.TenantPassword }); let files = this.state.selectedFiles; for (let i = 0; i  response.json()) .then(responseJson => { if (!this.isCancelled) { this.setState({ data: responseJson }); } }) .catch(error => { console.error(error); }); } upload(e){ let files = e.target.files; this.setState({ 'selectedFiles': files }); } render(){ const { data } = this.state; const { rowStyle, colStyle, gutter } = basicStyle; return ( 
{} <Box title={} subtitle={} >
); } }

抛出错误的行是这样的:

 model = JsonConvert.DeserializeObject(await modelContent.ReadAsStringAsync()); 

您的model以其string表示forms发布,而不是JSON
await modelContent.ReadAsStringAsync()将返回array-notation中的字符串: [object Object]

您必须自己处理JSON序列化。

更换

 data.append("model", { "TenantId": this.state.TenantId, "TenantUrl": this.state.TenantUrl, "TenantPassword": this.state.TenantPassword }); 

 data.append("model", JSON.stringify({ "TenantId": this.state.TenantId, "TenantUrl": this.state.TenantUrl, "TenantPassword": this.state.TenantPassword }));