发生错误.",ExceptionMessage:“提供了无效的'HttpContent'实例 [英] An error has occurred.", ExceptionMessage: "Invalid 'HttpContent' instance provided

查看:216
本文介绍了发生错误.",ExceptionMessage:“提供了无效的'HttpContent'实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试将文件添加到http REST调用中,出现此错误:

Trying to add a file to an http rest call I get this error:

responseJson = {消息:发生错误.",ExceptionMessage: 提供了无效的'HttpContent'实例. 'multipart/'. ↵参数名称:内容",异常类型: "System.ArgumentException",StackTrace:位于 System.Net.Http.Formatting.Parsers.MimeMulti…tpControllerDispatcher.d__1.MoveNext()}

responseJson = {Message: "An error has occurred.", ExceptionMessage: "Invalid 'HttpContent' instance provided. It does n…rting with 'multipart/'. ↵Parameter name: content", ExceptionType: "System.ArgumentException", StackTrace: " at System.Net.Http.Formatting.Parsers.MimeMulti…tpControllerDispatcher.d__1.MoveNext()"}

我的反应成分:

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方法

My tenant controller Put method

[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:

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()"

更新1:

当我远程连接调试器时,承租人参数为null,因此在客户端组件上设置参数时一定出错了.

When I attach the debugger remotely the tenant parameter is null, so something must be wrong when setting the parameters on the client component.

推荐答案

我猜您的[FromBody]Tenant tenant为空,因为您使用的是multipart/form-data.

I guess your [FromBody]Tenant tenant is null because you use multipart/form-data.

在这种情况下,默认的模型绑定器无法解析您的模型.

The default model binder can not resolve your model in this case.

请查看Microsoft 文档(

Please review example from Microsoft documentation (section Reading Form Control Data).

您需要使用MultipartFormDataStreamProvider读取模型数据.如我所见,您仅将提供程序用于读取文件内容.而且,您还可以从FormData属性读取模型数据(例如TenantId,TenantUrl等).

You need to read your model data using MultipartFormDataStreamProvider. As I can see you use the provider only for file content reading. But also you can read your model data (like TenantId, TenantUrl, etc) from FormData property.

作为第二种(也是更通用的)方法,您可以创建自己的

As second (and more general) approach you can create your own IModelBinder implementation.

在这里您可以查看我实现IModelBinder的示例(这是来自真实项目的代码):

Here you can review example of my implementation of IModelBinder (It is code from real project):

public class NativeTranslateModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(NativeTranslateViewModel))
        {
            return false;
        }

        var task = Task.Run(async () =>
        {
            var model = new NativeTranslateViewModel();

            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"));
                if (fileContent == null)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Section 'file' is missed");
                }

                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<NativeTranslateViewModel>(await modelContent.ReadAsStringAsync());
                    model.Text = "<NativeTranslation>";
                    model.FileData = await fileContent.ReadAsByteArrayAsync();
                    model.FileName = fileContent.Headers.ContentDisposition.FileName;
                }
            }

            return model;
        });

        task.Wait();

        bindingContext.Model = task.Result;
        return true;
    }
}

我们可以很容易地使用新型活页夹:

We can use new model binder very easy:

[HttpPost]
public HttpResponseMessage UploadNativeDocument([ModelBinder(typeof(NativeTranslateModelBinder))] NativeTranslateViewModel model)

现在,我们可以在控制器动作中使用模型和模型属性.

Now we can use our model and model properties inside controller action.

这篇关于发生错误.",ExceptionMessage:“提供了无效的'HttpContent'实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆