javascript - Webapi Controller 参数为空

标签 javascript c# jquery angularjs reactjs

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

我的 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();

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

我的租户 Controller 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 组件才能使其正常工作?

最佳答案

Instead of sending multipart form data you should send JSON object to server from react component

这将使您的生活更轻松。

示例

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对于 C#

关于javascript - Webapi Controller 参数为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51375393/

相关文章:

javascript - 用换行符分割多个 JS 字符串

c# - 当我在组合框中返回 SelectedItem 时返回 System.Data.DataRowView

javascript - 如何在 iframe 内单击没有 id 或名称的按钮?

jquery - 简单面板脚本无法工作,关闭脚本标签不正确?

javascript - jQuery "loading"微调器停止工作

javascript - 如何在域下导航时停止添加未在 Service Worker 中声明的内容

javascript - 如何为需要测试其发射的 Angular Directive(指令)进行 Jasmine 单元测试?

c# - 处理器数量是否会影响 ASP.NET MVC 4 Web 应用程序中异步线程的性能?

c# - 这可能是 : c# collection of Type with constrains, 还是通用类型的集合?

javascript - 在 jQuery slimScroll 1.3.3 插件中的 Firefox 中跳跃滚动