Webapi控制器参数为空

时间:2018-07-17 07:18:02

标签: javascript c# jquery angularjs reactjs

我有reactjs组件,该组件将PUT请求发送到Web api控制器,但是接收到的对象(租户)为null。我可以附加远程调试器并注意到这一点。

我的反应成分:

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);
        }
    }

stacktrace:

"   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 个答案:

答案 0 :(得分:2)

  

应该发送JSON对象而不是发送多部分表单数据   来自React组件的服务器

这将使您的生活更轻松。

示例

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。

所以您必须遵循以下步骤

  1. 将文件转换为base64字符串,请参考this
  2. 将该base64字符串与其他数据一起发送到服务器
  3. 在服务器端将文件接收为base64字符串
  4. 在服务器上解码base64字符串,请参考this for c#