Webapi 控制器参数为空
Posted
技术标签:
【中文标题】Webapi 控制器参数为空【英文标题】:Webapi controller parameters are null 【发布时间】:2018-12-24 19:15:12 【问题描述】:我有将 PUT 请求发送到 Web api 控制器的 reactjs 组件,但是接收到的对象(租户)为空。我可以附加远程调试器并注意到这一点。
我的反应组件:
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();
const formData = new FormData();
formData.append("TenantId", this.state.TenantId);
formData.append("TenantUrl", this.state.TenantUrl);
formData.append("TenantPassword", this.state.TenantPassword);
const options =
method: 'put',
data: formData,
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 data = new FormData();
//Append files to form data
let files = e.target.files;
for (let i = 0; i < files.length; i++)
data.append('files', files[i], files[i].name);
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>
);
我的租户控制器Put方法
[HttpPut]
public async Task<IHttpActionResult> PutTenant([FromBody]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 = contentType;
MemoryStream stream = new MemoryStream(content);
blockBlob.UploadFromStream(stream);
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
tenant.content = content;
tenant.CertificatePath = blockBlob.Uri;
if (!ModelState.IsValid)
return BadRequest(ModelState);
var added = await tenantStore.AddAsync(tenant);
return StatusCode(HttpStatusCode.NoContent);
和租户 POCO
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[] content get; set;
public override string ToString()
return JsonConvert.SerializeObject(this);
堆栈跟踪:
" at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser.ValidateArguments(HttpContent content, Int64 maxMessageSize, Boolean throwOnError)
at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser..ctor(HttpContent content, MultipartStreamProvider streamProvider, Int64 maxMessageSize, Int32 maxBodyPartHeaderSize)
at System.Net.Http.HttpContentMultipartExtensions.<ReadAsMultipartAsync>d__0`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TenantManagementWebApi.Controllers.TenantController.<PutTenant>d__2.MoveNext() in C:\Users\levm3\source\repos\TenantManagementWebApi\Controllers\TenantController.cs:line 48
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
我猜我的问题出在 react 而不是 webapi 中,如何更改我的 react 组件以使其正常工作?
【问题讨论】:
【参考方案1】:您应该发送 JSON 对象,而不是发送多部分表单数据 来自反应组件的服务器
这将使您的生活更轻松。
示例
fetch('https://mywebsite.com/endpoint/',
method: 'POST',
headers:
'Accept': 'application/json',
'Content-Type': 'application/json',
,
body: JSON.stringify(
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
)
)
参考:- React Native Docs
在 c# 中改变这个
public async Task<IHttpActionResult> PutTenant(Tenant tenant)
更新:- 如何将文件上传到服务器
根据this,你有3个选择
但如果您不经常交流,我更愿意转换为 base64。
所以你必须遵循这些步骤
-
将文件转换为base64字符串参考this
将该 base64 字符串与其他数据一起发送到服务器
在服务器端接收文件作为base64字符串
在服务器上解码base64字符串,c#参考this
【讨论】:
您还没有解释最重要的部分,文件上传,请提供如何发送json数据的示例,同时根据我的需要处理文件上传。谢谢 不是一个坏主意,所以基本上文件本身就是一个字符串参数(base 64)。我喜欢这种方式以上是关于Webapi 控制器参数为空的主要内容,如果未能解决你的问题,请参考以下文章
Protobuf : WebApi -> JS - 解码对象为空