将字节数组从WPF传递到WebApi

时间:2015-10-12 16:38:16

标签: wpf asp.net-web-api

tl; dr 将两个数据(最多1MBish)从WPF应用程序传递到WebAPI服务方法的最佳方法是什么?

我目前正在尝试将二进制数据从WPF应用程序传递到WebAPI Web服务,并且结果可变。小文件(< 100k)通常可以正常工作,但任何更大的成功几率都会降低。

标准OpenFileDialog,然后File.ReadAllBytes将byte []参数传递给WPF中的客户端方法。这总是成功的,然后我通过PostAsync调用和ByteArrayContent参数将数据发布到WebAPI。

这是正确的方法吗?我开始使用PostJSONAsync调用,并将byte []传递给它,但认为ByteArrayContent看起来更合适,但都不能可靠地工作。

WPF中的客户端方法

public static async Task<bool> UploadFirmwareMCU(int productTestId, byte[] mcuFirmware)
{
    string url = string.Format("productTest/{0}/mcuFirmware", productTestId);

    ByteArrayContent bytesContent = new ByteArrayContent(mcuFirmware);
    HttpResponseMessage response = await GetClient().PostAsync(url, bytesContent);

    ....
}

WebAPI方法

[HttpPost]
[Route("api/productTest/{productTestId}/mcuFirmware")]
public async Task<bool> UploadMcuFirmware(int productTestId)
{
    bool result = false;

    try
    {
        Byte[] mcuFirmwareBytes = await Request.Content.ReadAsByteArrayAsync();

        ....
    }

网络配置设置

AFAIK web.config中的这些限制应该足以允许1MB文件到服务吗?

  <security>
    <requestFiltering>
    <requestLimits maxAllowedContentLength="1073741824" />
    </requestFiltering>
  </security>

<httpRuntime targetFramework="4.5" maxRequestLength="2097152"/>

调用ReadAsByteArrayAsync()时,我在WebAPI中收到错误。这些情况各不相同,可能是由于IIS Express中的应用程序池崩溃/进入了糟糕的状态,但它们包括以下内容(其中没有一个通过谷歌导致任何有希望的潜在客户):

Specified argument was out of the range of valid values. Parameter name: offset
at System.Web.HttpInputStream.Seek(Int64 offset, SeekOrigin origin)\r\n   
at System.Web.HttpInputStream.set_Position(Int64 value)\r\n   at System.Web.Http.WebHost.SeekableBufferedRequestStream.SwapToSeekableStream()\r\n   at System.Web.Http.WebHost.Seek

OR

Message = "An error occurred while communicating with the remote host. The error code is 0x800703E5."

InnerException = {"Overlapped I/O operation is in progress. (Exception from HRESULT: 0x800703E5)"}

at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)\r\n   
at System.Web.Hosting.IIS7WorkerRequest.ReadEntityCoreSync(Byte[] buffer, Int32 offset, Int32 size)\r\n   
at System.Web.Hosting.IIS7WorkerRequ...

最初我认为这很可能取决于IIS Express的限制(在我的开发人员的Windows 7上运行)但我们在运行Server 2012的登台服务器上遇到了同样的问题。

任何有关如何使其工作的建议都会很棒,甚至只是从WPF上传文件到WebAPI的基本示例都会很棒,因为我发现的大部分代码都与上传文件有关来自多部分表格网页。

非常感谢您的任何帮助。

1 个答案:

答案 0 :(得分:0)

tl; dr 这是WebApi服务中我们代码的一个独立部分导致它出错,呃!

啊,好吧,这很令人尴尬。

事实证明我们的问题归结为我们在WebApiConfig.Register(HttpConfiguration config)注册的请求记录器类,而且我已经忘记了。

它通过async作为StringContent读取请求内容,然后尝试将其记录到ncarchar(max)字段中的数据库。这本身可能没问题,但我猜测当LoggingHandler以及主WebApi控制器都试图通过异步访问请求内容时,所有奇怪的问题都会发生?

删除LoggingHandler会立即修复问题,我们现在可以上传最高100MB的文件而不会出现任何问题。为了更加永久地修复它,我想我需要重写LoggingHandler来设置对它尝试记录/忽略某些内容类型的最大内容大小的限制。

令人怀疑,但我希望有一天这对某人有用!

public class LoggingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        LogRequest(request);

        return base.SendAsync(request, cancellationToken).ContinueWith(task =>
        {
            var response = task.Result;

            // ToDo: Decide if/when we need to log responses
            // LogResponse(response);

            return response;
        }, cancellationToken);
    }

    private void LogRequest(HttpRequestMessage request)
    {
        (request.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
        {
            try
            {
                var callerId = CallerId(request);
                var callerName = CallerName(request);

                // Log request
                LogEntry logEntry = new LogEntry
                {
                    TimeStamp = DateTime.Now,
                    HttpVerb = request.Method.ToString(),
                    Uri = request.RequestUri.ToString(),
                    CorrelationId = request.GetCorrelationId(),
                    CallerId = callerId,
                    CallerName = callerName,
                    Controller = ControllerName(request),
                    Header = request.Headers.ToString(),
                    Body = x.Result
                };

                ...........