ExceptionMessage: "Can't bind multiple parameters ('tenant' and 'certificateFile') to the request's content

孤街浪徒 提交于 2021-02-17 05:14:03

问题


I am trying to call a webapi from react and I get this error

responseJson = {Message: "An error has occurred.", ExceptionMessage: "Can't bind multiple parameters ('tenant' and 'certificateFile') to the request's content.", ExceptionType: "System.InvalidOperationException", StackTrace: " at System.Web.Http.Controllers.HttpActionBindin…tpControllerDispatcher.d__1.MoveNext()"}

my react code is like this:

    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("TenanrUrl", 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>
        );
      }
    }

My web api is this:


public class TenantController : ApiController
    {
        public async Task<List<Tenant>> GetTenants()
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            return await tenantStore.Query().Where(x => x.TenantId != null ).ToListAsync();

        }

        public async Task<IHttpActionResult> GetTenant(string tenantId)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.TenantId == tenantId);
            if (tenant == null)
            {
                return NotFound();
            }
            return Ok(tenant);
        }

        public async Task<IHttpActionResult>  PutTenant([FromBody]Tenant tenant, HttpPostedFile certificateFile)
        {
            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 = certificateFile.ContentType;
            blockBlob.UploadFromStream(certificateFile.InputStream);

            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            tenant.CertificatePath = blockBlob.Uri;

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            //if (id != tenant.TenantId)
            //{
            //    return BadRequest();
            //}

            var added = await tenantStore.AddAsync(tenant);
            return StatusCode(HttpStatusCode.NoContent); 
        }

        public async Task<IHttpActionResult> PostTenant(string id, Tenant tenant)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var result = await tenantStore.UpdateAsync(tenant);
            return Ok(result);
        }

        public async Task<IHttpActionResult> DeleteTenant(string tenantId)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            await tenantStore.RemoveByIdAsync(tenantId);// Removes an entity with the specified ID
            return Ok(tenantId);
        }
    }

My tenant object is this:

public class Tenant
    {
        public string TenantId { get; set; }
        public string TenantUrl { get; set; }
        public Uri CertificatePath { get; set; }
        public string CertificatePassword { get; set; }

        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
    }

and the controller

public class TenantController : ApiController
    {
        public async Task<List<Tenant>> GetTenants()
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            return await tenantStore.Query().Where(x => x.TenantId != null ).ToListAsync();

        }

        public async Task<IHttpActionResult> GetTenant(string tenantId)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.TenantId == tenantId);
            if (tenant == null)
            {
                return NotFound();
            }
            return Ok(tenant);
        }

        public async Task<IHttpActionResult>  PutTenant([FromBody]Tenant tenant, HttpPostedFile certificateFile)
        {
            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 = certificateFile.ContentType;
            blockBlob.UploadFromStream(certificateFile.InputStream);

            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            tenant.CertificatePath = blockBlob.Uri;

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            //if (id != tenant.TenantId)
            //{
            //    return BadRequest();
            //}

            var added = await tenantStore.AddAsync(tenant);
            return StatusCode(HttpStatusCode.NoContent); 
        }

        public async Task<IHttpActionResult> PostTenant(string id, Tenant tenant)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var result = await tenantStore.UpdateAsync(tenant);
            return Ok(result);
        }

        public async Task<IHttpActionResult> DeleteTenant(string tenantId)
        {
            var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
            await tenantStore.RemoveByIdAsync(tenantId);// Removes an entity with the specified ID
            return Ok(tenantId);
        }
    }

回答1:


Problem is exactly what is specified in the exception message. You are binding multiple parameters to action body, you cannot do that with Web API. Please read Parameter binding in Web API.

Use following code to read uploaded file.

    using System.Net.Http;
    using System.IO;
    public async Task<IHttpActionResult>  PutTenant([FromBody]Tenant tenant)
    {
            var provider = new MultipartMemoryStreamProvider();
            var contentType = "";
            Stream content = new MemoryStream();
            await base.Request.Content.ReadAsMultipartAsync(provider);
            if(provider.Contents.Count > 0)
            {
                contentType = provider.Contents[0].Headers.ContentType.MediaType;
                content = await provider.Contents[0].ReadAsStreamAsync();
            }

        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;
        blockBlob.UploadFromStream(content);

        var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
        tenant.CertificatePath = blockBlob.Uri;

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        //if (id != tenant.TenantId)
        //{
        //    return BadRequest();
        //}

        var added = await tenantStore.AddAsync(tenant);
        return StatusCode(HttpStatusCode.NoContent); 
    }


来源:https://stackoverflow.com/questions/51365048/exceptionmessage-cant-bind-multiple-parameters-tenant-and-certificatefile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!