【搬運(yùn)】ASP.NET Core, response compression, response buffering and subtle difference between .NET Framework and .NET Core

原文地址:https://www.tpeczek.com/2017/08/aspnet-core-response-compression.html

I've received a question from a user of my Server-Sent Events Middleware. In general the user was asking if it can be used together with Response Compression Middleware because he had hard time making it work. As there shouldn't be any technical limitation to such scenario I've decided to quickly test it in my simple demo.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression(options =>
        {
            options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
            {
                "text/event-stream"
            });
        });

        services.AddServerSentEvents();
        ...
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseResponseCompression()
            .MapServerSentEvents("/see-heartbeat")
            ...;

        ...
    }
}

It worked without any issues.

I've quickly written a response including my snippet. Unfortunately the user was doing exactly same thing and while for me it was working perfectly for him it seemed to be doing nothing (there was no error or any other side effect, just events not arriving to the client). We have exchanged couple emails until we have finally discovered a difference in our scenarios - my target framework was netcoreapp1.0 while his was net451. I've switched my project to net451 and I could observe the same behavior.

Difference between .NET Framework and .NET Core

I've started looking for the root cause. It was obviously somehow related to the response compression but I didn't had an idea what could that be. Until I've found below fragment inside of GzipCompressionProvider.

public bool SupportsFlush
{
    get
    {
#if NET451
        return false;
#elif NETSTANDARD1_3
        return true;
#else
        // Not implemented, compiler break
#endif
    }
}

This clearly shows that GZipStream(which is being internally used by GzipCompressionProvider) doesn't support flushing in .NET Framework (and my Server Sent Events implementation is flushing the events when they are completely written). This difference is not documented, in fact the documentation states that GZipStream.Flush
has not functionality regardless of implementation. I was able to find this issue which shed some light on how GZipStream
has started actually flushing. The bottom line is that when used over .NET Framework the Response Compression Middleware is also buffering the response.

Response Buffering in ASP.NET Core

In ASP.NET Core component which provides response buffering capabilities should implement IHttpBufferingFeature. The Response Compression Middleware does it through BodyWrapperStream in which it wraps the original body stream. This means that it should be possible to disable the buffering with following code.

private void DisableResponseBuffering(HttpContext context)
{
    IHttpBufferingFeature bufferingFeature = context.Features.Get<IHttpBufferingFeature>();
    if (bufferingFeature != null)
    {
        bufferingFeature.DisableResponseBuffering();
    }
}

I've added this to ServerSentEventsMiddleware.


public class ServerSentEventsMiddleware
{
    ...

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers[Constants.ACCEPT_HTTP_HEADER] == Constants.SSE_CONTENT_TYPE)
        {
            DisableResponseBuffering(context);

            ...
        }
        else
        {
            await _next(context);
        }
    }

    ...
}

After this change running the demo application with net451 as target framework resulted in events correctly reaching the client. The difference was that the response wasn't compressed.

This is how Response Compression Middleware handles the DisableResponseBuffering method. If compression provider which is supposed to be used doesn't support flushing (the SupportsFlush property above) it disables the compression.

This is an interesting and worth to remember difference in behavior between .NET Framework and .NET Core.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容