如何启用的.NET Web-API接受G-ziped职位 [英] How do enable a .Net web-API to accept g-ziped posts

查看:221
本文介绍了如何启用的.NET Web-API接受G-ziped职位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相当沼泽标准.NET MVC 4个Web API应用。

I have a fairly bog standard .net MVC 4 Web API application.

 public class LogsController : ApiController
{

    public HttpResponseMessage PostLog(List<LogDto> logs)
    {
        if (logs != null && logs.Any())
        {
            var goodLogs = new List<Log>();
            var badLogs = new List<LogBad>();

            foreach (var logDto in logs)
            {
                if (logDto.IsValid())
                {
                    goodLogs.Add(logDto.ToLog());
                }
                else
                {
                    badLogs.Add(logDto.ToLogBad());
                }
            }

            if (goodLogs.Any())
            {
                _logsRepo.Save(goodLogs);
            }

            if(badLogs.Any())
            {
                _logsBadRepo.Save(badLogs);
            }


        }
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

这所有的工作很好,我有一个能够给我自己的记录设备和它工作得很好。不过现在我们已经开始有关于数据的大小担心被转移,我们要看看后接受已融为一体pressed使用GZIP?

This all work fine, I have devices that are able to send me their logs and it works well. However now we are starting to have concerns about the size of the data being transferred, and we want to have a look at accepting post that have been compressed using GZIP?

我怎么会去这样做呢?难道在IIS或设置可我的用户操作过滤器?

How would I go about do this? Is it setting in IIS or could I user Action Filters?

修改1

这是菲利普的回答跟进我的想法是,我需要拦截请求的处理它得到我的控制器之前。如果Web API框架尝试将请求的主体解析为我的业务对象,它失败,因为请求的主体仍然是COM pressed之前,我能赶上请求。然后,我可以DECOM preSS请求的身体,然后传递请求回到加工链,并希望在Web API框架将能够在(DECOM pressed)体解析为我的业务对象。

Following up from Filip's answer my thinking is that I need to intercept the processing of the request before it gets to my controller. If i can catch the request before the Web api framework attempts to parse the body of the request into my business object, which fails because the body of the request is still compressed. Then I can decompress the body of the request and then pass the request back into the processing chain, and hopefully the Web Api framework will be able to parse the (decompressed) body into my business objects.

它看起来像使用DelagatingHandler是要走的路。它让我获得了加工过程中的要求,但我的控制器之前。所以,我想下面的?

It looks Like using the DelagatingHandler is the way to go. It allows me access to the request during the processing, but before my controller. So I tried the following?

 public class gZipHandler : DelegatingHandler
{

    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        string encodingType = request.Headers.AcceptEncoding.First().Value;

        request.Content = new DeCompressedContent(request.Content, encodingType);

        return base.SendAsync(request, cancellationToken);
    }
}

public class DeCompressedContent : HttpContent
{
    private HttpContent originalContent;
    private string encodingType;

    public DeCompressedContent(HttpContent content, string encodType)
    {
        originalContent = content;
        encodingType = encodType;
    }

    protected override bool TryComputeLength(out long length)
    {
        length = -1;

        return false;
    }


    protected override Task<Stream> CreateContentReadStreamAsync()
    {
        return base.CreateContentReadStreamAsync();
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        Stream compressedStream = null;

        if (encodingType == "gzip")
        {
            compressedStream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: true);
        }

        return originalContent.CopyToAsync(compressedStream).ContinueWith(tsk =>
        {
            if (compressedStream != null)
            {
                compressedStream.Dispose();
            }
        });
    }



}

}

这似乎是工作确定。该SendAsync方法我的控制器之前被调用,并为DECOM pressedContent构造函数被调用。然而SerializeToStreamAsync永远不会被调用,所以我说的CreateContentReadStreamAsync,看看这其中的DECOM pressing应该发生,但是这不被任何调用。

This seems to be working ok. The SendAsync method is being called before my controller and the constructor for the DecompressedContent is being called. However the SerializeToStreamAsync is never being called so I added the CreateContentReadStreamAsync to see if that's where the decompressing should be happening, but that's not being called either.

我摔倒了,我接近解决方案,但只需要一点点额外得到它过线。

I fell like I am close to the solution, but just need a little bit extra to get it over the line.

推荐答案

我已经张贴同样的要求gzip压缩的数据到.NET网页API控制器。我想出了这个解决方案:

I had the same requirement to POST gzipped data to a .NET web api controller. I came up with this solution:

public class GZipToJsonHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                           CancellationToken cancellationToken)
    {
        // Handle only if content type is 'application/gzip'
        if (request.Content.Headers.ContentType == null ||
            request.Content.Headers.ContentType.MediaType != "application/gzip")
        {
            return base.SendAsync(request, cancellationToken);
        }

        // Read in the input stream, then decompress in to the outputstream.
        // Doing this asynronously, but not really required at this point
        // since we end up waiting on it right after this.
        Stream outputStream = new MemoryStream();
        Task task = request.Content.ReadAsStreamAsync().ContinueWith(t =>
            {
                Stream inputStream = t.Result;
                var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress);

                gzipStream.CopyTo(outputStream);
                gzipStream.Dispose();

                outputStream.Seek(0, SeekOrigin.Begin);
            });

        // Wait for inputstream and decompression to complete. Would be nice
        // to not block here and work async when ready instead, but I couldn't 
        // figure out how to do it in context of a DelegatingHandler.
        task.Wait();

        // This next section is the key...

        // Save the original content
        HttpContent origContent = request.Content;

        // Replace request content with the newly decompressed stream
        request.Content = new StreamContent(outputStream);

        // Copy all headers from original content in to new one
        foreach (var header in origContent.Headers)
        {
            request.Content.Headers.Add(header.Key, header.Value);
        }

        // Replace the original content-type with content type
        // of decompressed data. In our case, we can assume application/json. A
        // more generic and reuseable handler would need some other 
        // way to differentiate the decompressed content type.
        request.Content.Headers.Remove("Content-Type");
        request.Content.Headers.Add("Content-Type", "application/json");

        return base.SendAsync(request, cancellationToken);
    }
}

使用这种方法,现有的控制器,通常使用JSON内容和自动模型绑定工作,继续没有任何变化工作。

Using this approach, the existing controller, which normally works with JSON content and automatic model binding, continued to work without any changes.

我不知道为什么其他的答案被接受。它提供了一个解决方案,用于处理的反应(这是常见的),但不要求(这是不常见)。该Accept-Encoding头用于指定可接受的响应编码,并且是不相关的要求进行编码。

I'm not sure why the other answer was accepted. It provides a solution for handling the responses (which is common), but not requests (which is uncommon). The Accept-Encoding header is used to specify acceptable response encodings, and is not related to request encodings.

这篇关于如何启用的.NET Web-API接受G-ziped职位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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