C# 文件上载WCF WEB API时出错(预览6):向缓冲区写入的字节数不能超过配置的最大缓冲区大小65536

C# 文件上载WCF WEB API时出错(预览6):向缓冲区写入的字节数不能超过配置的最大缓冲区大小65536,c#,asp.net,wcf,httpclient,wcf-web-api,C#,Asp.net,Wcf,Httpclient,Wcf Web Api,我对WCFWebAPI有一个真正的问题 我有一个简单的方法上传文件并保存到磁盘。我似乎已经设置了所有正确的参数,但当我尝试上载2mb文件时,会收到上面的错误消息 服务器代码: public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); HttpServiceHostFactory _factory = new HttpS

我对WCFWebAPI有一个真正的问题

我有一个简单的方法上传文件并保存到磁盘。我似乎已经设置了所有正确的参数,但当我尝试上载2mb文件时,会收到上面的错误消息

服务器代码:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    HttpServiceHostFactory _factory  = new HttpServiceHostFactory();

    var config = new HttpConfiguration() 
    { 
        EnableTestClient = true, 
        IncludeExceptionDetail = true,
        TransferMode = System.ServiceModel.TransferMode.Streamed,
        MaxReceivedMessageSize = 4194304,
        MaxBufferSize = 4194304    
    };

    _factory.Configuration = config;

    RouteTable.Routes.Add(new ServiceRoute("api/docmanage", _factory, typeof(WorksiteManagerApi)));
}
客户:

HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.MaxRequestContentBufferSize = 4194304;

var byteArray = 
    Encoding.ASCII.GetBytes(ConnectionSettings.WebUsername + ":" + ConnectionSettings.WebPassword);

HttpClient httpClient = new HttpClient(httpClientHandler);
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
httpClient.BaseAddress = new Uri(ConnectionSettings.WebApiBaseUrl);
httpClient.MaxResponseContentBufferSize = 4194304;

...

multipartFormDataContent.Add(new FormUrlEncodedContent(formValues));
multipartFormDataContent.Add(byteArrayContent);

var postTask = httpClient.PostAsync("api/docmanage/UploadFile", multipartFormDataContent);
然后,在服务器上:

[WebInvoke(Method = "POST")]
public HttpResponseMessage UploadFile(HttpRequestMessage request)
{
    // Verify that this is an HTML Form file upload request
    if (!request.Content.IsMimeMultipartContent("form-data"))
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    // Create a stream provider for setting up output streams
    MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider();

    // Read the MIME multipart content using the stream provider we just created.
    IEnumerable<HttpContent> bodyparts = request.Content.ReadAsMultipart(streamProvider);

    foreach (var part in bodyparts)
    {
        switch (part.Headers.ContentType.MediaType)
        {
            case "application/octet-stream":
                if (part.Headers.ContentLength.HasValue)
                {
                    // BLOWS UP HERE:            
                    var byteArray = part.ReadAsByteArrayAsync().Result;

                    if (null == fileName)
                    {
                        throw new HttpResponseException(HttpStatusCode.NotAcceptable);
                    }
                    else
                    {
                        uniqueFileId = Guid.NewGuid().ToString();
                        string tempFilename = Path.GetTempPath() + @"\" + uniqueFileId + fileName;

                        using (FileStream fileStream = File.Create(tempFilename, byteArray.Length))
                        {
                            fileStream.Write(byteArray, 0, byteArray.Length); 
                        }
                    }

                }
                break;
        }
    }
}
[WebInvoke(Method=“POST”)]
公共HttpResponseMessage上载文件(HttpRequestMessage请求)
{
//确认这是一个HTML表单文件上传请求
if(!request.Content.IsMimeMultipartContent(“表单数据”))
{
抛出新的HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
//创建用于设置输出流的流提供程序
MultipartFormDataStreamProvider streamProvider=新的MultipartFormDataStreamProvider();
//使用我们刚刚创建的流提供程序读取MIME多部分内容。
IEnumerable bodyparts=request.Content.ReadAsMultipart(streamProvider);
foreach(车身零件中的var零件)
{
开关(part.Headers.ContentType.MediaType)
{
案例“应用程序/八位字节流”:
if(part.Headers.ContentLength.HasValue)
{
//在这里爆炸:
var byteArray=part.ReadAsByteArrayAsync().Result;
if(null==文件名)
{
抛出新的HttpResponseException(HttpStatusCode.NotAcceptable);
}
其他的
{
uniqueFileId=Guid.NewGuid().ToString();
字符串tempFilename=Path.GetTempPath()++“\”+uniqueFileId+fileName;
使用(FileStream FileStream=File.Create(tempFilename,byteArray.Length))
{
Write(byteArray,0,byteArray.Length);
}
}
}
打破
}
}
}

有什么想法吗?我正在使用web api的最新预览。。。。我注意到支持文档中缺少很多内容,但似乎存在一些缓冲区限制,我无法确定如何指定或被忽略……

是否在web.config中设置了maxRequestLength:

<httpRuntime maxRequestLength="10240" />

HttpContent类的(缺少)文档中没有明确说明的一点是,默认的内部缓冲区是64K,因此任何非流的内容都会在内容超过64Kb时抛出异常

解决方法是使用以下方法:

part.LoadIntoBufferAsync(bigEnoughBufferSize).Result();
var byteArray = part.ReadAsByteArrayAsync().Result;

我假设HttpContent类缓冲区上的64K限制是为了防止在服务器上发生过多的内存分配。我想知道您是否会更好地将字节数组内容作为StreamContent传递?这样,在不增加HttpContent缓冲区大小的情况下,它仍然可以工作。

几天来,我一直在努力解决WCF WinAPI的类似问题,当时我试图发布一个12Mb的文件,但我不知道发生了什么。我的服务器端是托管在IIS中的WCF服务;我的问题不是WCF设置,而是Toni提到的。在IIS中托管时,请记住增加此设置。MS文档表明默认值为4Mb,这解释了为什么我可以发布400Kb的文件


希望这能帮助其他有同样问题的人。

发布代码时,请确保其格式尽可能可读。要求人们花时间挑选格式不正确的样本是不礼貌的。您在服务器和客户端上有任何配置条目吗?如果是这样的话,那么你能把它们发布到tooleft上吗?把所有的配置只发布到代码中。。。您可以看到在创建时(以及在客户端)将配置参数传递给服务…在请求端这不是问题。。。请求到达服务器正常。。。当代码试图将内容读入字节数组时,唯一的问题就会出现。。。在这一点上,它违反了缓冲区大小限制,即使这是在服务托管时明确设置的…感觉它是wcf中的一个bug…谢谢,我将在周一尝试一下。谢谢。。把它整理好。我花了很长时间才回来重温代码。。。让我们只说我延迟依赖它的功能是有原因的!