我有以下错误:
JsonSerializationException:无法将当前JSON数组(例如[1,2,3])反序列化为类型,'TenantManagementWebApi.Entities.Tenant' 因为该类型需要JSON对象(例如{"name":"value"})才能正确反序列化。 为了解决这个问题错误或者改变JSON来JSON对象(例如{"name":"value"})或改变反序列化类型的阵列或一种类型的工具的集合接口(例如ICollection, IList)等List<T>,可以从一个JSON阵列反序列化。也可以将JsonArrayAttribute添加到类型中,以强制其从JSON数组反序列化。路径’‘,第1行,位置1。
JsonSerializationException:无法将当前JSON数组(例如[1,2,3])反序列化为类型,'TenantManagementWebApi.Entities.Tenant' 因为该类型需要JSON对象(例如{"name":"value"})才能正确反序列化。
[1,2,3]
'TenantManagementWebApi.Entities.Tenant'
{"name":"value"}
为了解决这个问题错误或者改变JSON来JSON对象(例如{"name":"value"})或改变反序列化类型的阵列或一种类型的工具的集合接口(例如ICollection, IList)等List<T>,可以从一个JSON阵列反序列化。也可以将JsonArrayAttribute添加到类型中,以强制其从JSON数组反序列化。路径’‘,第1行,位置1。
ICollection, IList
List<T>
我的网络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<Tenant>(await modelContent.ReadAsStringAsync()); //model.Text = "<NativeTranslation>"; 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<IHttpActionResult> 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>(); 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 < files.length; i++) { data.append("file", files[i], files[i].name); } const options = { method: 'put', body: data, config: { headers: { 'Content-Type': 'multipart/form-data' } } }; adalApiFetch(fetch, "/Tenant", options) .then(response => 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 ( <div> <LayoutWrapper> <PageHeader>{<IntlMessages id="pageTitles.TenantAdministration" />}</PageHeader> <Row style={rowStyle} gutter={gutter} justify="start"> <Col md={12} sm={12} xs={24} style={colStyle}> <Box title={<IntlMessages id="pageTitles.TenantAdministration" />} subtitle={<IntlMessages id="pageTitles.TenantAdministration" />} > <ContentHolder> <form onSubmit={this.handleSubmit}> <label> TenantId: <input type="text" value={this.state.TenantId} onChange={this.handleChangeTenantId} /> </label> <label> TenantUrl: <input type="text" value={this.state.TenantUrl} onChange={this.handleChangeTenantUrl} /> </label> <label> TenantPassword: <input type="text" value={this.state.TenantPassword} onChange={this.handleChangeTenantPassword} /> </label> <label> Certificate: <input onChange = { e => this.upload(e) } type = "file" id = "files" ref = { file => this.fileUpload } /> </label> <input type="submit" value="Submit" /> </form> </ContentHolder> </Box> </Col> </Row> </LayoutWrapper> </div> ); } }
引发错误的行是这样的:
model = JsonConvert.DeserializeObject<Tenant>(await modelContent.ReadAsStringAsync());
您model以其string表示形式发帖,但不是JSON。 await modelContent.ReadAsStringAsync()将以array-notation:返回一个字符串[object Object]。
model
string
JSON
await modelContent.ReadAsStringAsync()
[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 }));