Taritsyn / WebMarkupMin

The Web Markup Minifier (abbreviated WebMarkupMin) - a .NET library that contains a set of markup minifiers. The objective of this project is to improve the performance of web applications by reducing the size of HTML, XHTML and XML code.
Apache License 2.0
440 stars 48 forks source link

[WebMarkupMin.AspNetCore5] Sometimes a blank page is returned as the request has no response data available #147

Closed yankarinRG closed 12 months ago

yankarinRG commented 1 year ago

Sometimes, in an unspecified way, it happens that when a page is requested (for example, https://localhost:44300/Home/Index) a blank page (literally a white, empty page) is returned and shown because the request has no response data available, although it has status code 200. 99% of the time it only happens in the development environment on IIS Express, but I seemed to meet it also in a production environment where the web server is IIS.

Startup.ConfigureServices() is:

...

services
    .AddWebMarkupMin(options =>
    {
        options.DisablePoweredByHttpHeaders = true;
    })
    .AddHtmlMinification(options =>
    {
        var settings = new HtmlMinificationSettings
        {
            AttributeQuotesRemovalMode = HtmlAttributeQuotesRemovalMode.KeepQuotes,
            CollapseBooleanAttributes = true,
            EmptyTagRenderMode = HtmlEmptyTagRenderMode.NoSlash,
            MinifyAngularBindingExpressions = false,
            MinifyEmbeddedCssCode = true,
            MinifyEmbeddedJsCode = true,
            MinifyEmbeddedJsonData = true,
            MinifyInlineCssCode = true,
            MinifyInlineJsCode = true,
            MinifyKnockoutBindingExpressions = false,
            PreserveCase = false,
            RemoveCdataSectionsFromScriptsAndStyles = true,
            RemoveCssTypeAttributes = true,
            RemoveEmptyAttributes = true,
            RemoveHtmlComments = true,
            RemoveHtmlCommentsFromScriptsAndStyles = true,
            RemoveJsProtocolFromAttributes = true,
            RemoveJsTypeAttributes = true,
            RemoveOptionalEndTags = false,
            RemoveRedundantAttributes = true,
            RemoveTagsWithoutContent = false,
            WhitespaceMinificationMode = WhitespaceMinificationMode.Aggressive
        };

        options.MinificationSettings = settings;
    })
    .AddHttpCompression();

...

Startup.Configure() is:

...

app.UseHttpsRedirection();

app.UseWebMarkupMin();

app.UseStaticFiles();

...

Various versions: ASP.NET Core 5 WinVer: 21H2 (OS Build 22000.795) IIS Express version: 10.0.25095.1000

mehmet-erdogdu commented 1 year ago

when i was using visual studio and .net 6. i see a few times

Taritsyn commented 1 year ago

@yankarinRG @mehmet-erdogdu Do you use a Brotli compression?

mehmet-erdogdu commented 1 year ago
<TargetFramework>net6.0</TargetFramework>
<PackageReference Include="WebMarkupMin.AspNetCore5" Version="2.11.0" />

services.AddWebMarkupMin(options => { options.AllowMinificationInDevelopmentEnvironment = true; options.AllowCompressionInDevelopmentEnvironment = true; }).AddHtmlMinification(options => { options.MinificationSettings.RemoveRedundantAttributes = true; options.MinificationSettings.RemoveHttpProtocolFromAttributes = true; options.MinificationSettings.RemoveHttpsProtocolFromAttributes = true; }).AddHttpCompression();

Taritsyn commented 1 year ago

<TargetFramework>net6.0</TargetFramework> <PackageReference Include="WebMarkupMin.AspNetCore5" Version="2.11.0" />

@mehmet-erdogdu, it was logical to switch to the WebMarkupMin.AspNetCore6 module.

yankarinRG commented 1 year ago

@yankarinRG @mehmet-erdogdu Do you use a Brotli compression?

Hello, no I don't use the package WebMarkupMin.AspNet.Brotli

Taritsyn commented 1 year ago

Hello!

It is possible that this error will disappear after updating to version 2.13.0.

yankarinRG commented 1 year ago

@Taritsyn thank you for the quick fixing of the bug! I'll let you know if I'll experience this problem one more time!

yankarinRG commented 1 year ago

Hello @Taritsyn, I hope to find you well. I reencountered the issue while I was debugging an ASP.NET 6 MVC web app with the Prodution environment. The only difference with respect to the configuration I had when I initially reported this issue is that I migrated the web app from .NET Core 5 to .NET 6, and hence upgraded to WebMarkupMin.AspNetCore6 (version 2.13.8). I noticed this problem mostly only happen when using the Production environment (I have AllowMinificationInDevelopmentEnvironment and AllowCompressionInDevelopmentEnvironment set to false).

Since I was debugging, this time I was able to collect some more informations. In Chrome, the HTTP request for the page is blank and in the developer tools I see "The request has no response data available". Furthermore, here's a screenshot of the "timings" tabs: timings

That's all the relevant info I could gather which looks different compared to a normal and successful response. I can provide further assistance if you need to help troubleshoot this issue. Thanks, and have a nice day!

Taritsyn commented 1 year ago

Hello, @yankarinRG!

How do I understand such errors did not occur for four months?

yankarinRG commented 1 year ago

Hello @Taritsyn, from my perspective, there are two reasons why I haven't addressed this issue further. First, when I added the compression and minification functionality to the web app in November, my development work was already completed. I encountered the problem a couple of times, reported it, but didn't investigate it further. Second, I haven't received any reports from users, but this could be because (a) the issue only occurs when debugging visual studio with IIS Express using the production configuration, not when the application is released on IIS, or (b) users might think that a blank page is a network error, refresh the page, and move on. However, if we consider this problem to be specific to my situation and not reproducible, we can close the issue. Thanks!

Taritsyn commented 1 year ago

At the moment, I'm interested in whether the version for .NET 5 worked without errors, because in the version for .NET 6 has some differences.

It is also interesting to know if some information about errors is written to the log when blank pages are displayed.

… (a) the issue only occurs when debugging visual studio …

There may be side effects from using the Browser Link or Hot Reload.

If this error is really so unstable and non-reproducible, then I may have to make the BodyWrapperStreamBase class more thread-safe which will lead to some performance losses.

Taritsyn commented 1 year ago

Hello, @yankarinRG!

Try updating to version 2.13.9 Preview 1.

yankarinRG commented 1 year ago

Hello, @Taritsyn I upgraded from version 2.13.8 to version 2.13.9 Preview 1 and ran some standard tests to check if the issue persisted. I observed that the problem occurred consistently, neither before nor after the upgrade. However, I made an interesting discovery. If I manually set GenerateStatistics to true in AddHtmlMinification(), then the problem of blank pages seems to be resolved!

I also attempted to substitute NullLogger with my own ILogger implementation, and I verified that when a blank page occurred, ILogger.Info() was triggered with the category HTML_MINIFICATION_SUCCESS and the message Minification of the HTML code has been completed successfully..

I hope that this new information will be helpful in resolving the issue at hand.

Taritsyn commented 1 year ago

Hello, @yankarinRG!

If I manually set GenerateStatistics to true in AddHtmlMinification(), then the problem of blank pages seems to be resolved!

Very similar to untimely garbage collection.

I also attempted to substitute NullLogger with my own ILogger implementation, and I verified that when a blank page occurred, ILogger.Info() was triggered with the category HTML_MINIFICATION_SUCCESS and the message Minification of the HTML code has been completed successfully..

This message means that minification of code was successful. Apparently, this error occurs at ASP.NET Core middleware level (most likely here).

I'll try to make another pre-release today.

Taritsyn commented 1 year ago

Try updating to version 2.13.9 Preview 2.

yankarinRG commented 1 year ago

I updated to version 2.13.9 Preview 2 with the GC.KeepAlive on the minified content but I am able to reproduce the issue just like before, no changes :(

Taritsyn commented 1 year ago

It is possible that the GetBytes method sometimes returns an empty byte array. All this looks like some kind of error in the Encoding.GetBytes method or ArrayPool<byte> class which occurs when the garbage collector is heavily loaded.

Taritsyn commented 1 year ago

Does the GenerateStatistics option still prevent this error?

yankarinRG commented 1 year ago

Does the GenerateStatistics option still prevent this error?

Yes, it appears turning on GenerateStatistics keeps preventing the blank page issue, even on 2.13.9 Preview 2.

I made another interesting discovery: both in stable (2.13.8) and latest preview (2.13.9 Preview 2), if i remove AddHttpCompression() from the AddWebMarkupMin() chain, regardless if GenerateStatistics is set or unset, the blank page issue doesn't seem to happen.

Taritsyn commented 1 year ago

Removing AddHttpCompression() from the AddWebMarkupMin() chain reduces the load on CPU and RAM. In this case, it could just be lucky.

GenerateStatistics=true option on the contrary increases such a load, therefore, it is more interesting. There are two important aspects that this option can affect:

  1. An instance of the current encoding is held by an instance of the MinificationStatistics class.
  2. ArrayPool<byte>.Shared is warming up.
Taritsyn commented 1 year ago

I also attempted to substitute NullLogger with my own ILogger implementation, and I verified that when a blank page occurred, ILogger.Info() was triggered…

By the way, here it would be interesting to see the values of OriginalSize and MinifiedSize properties of the statistics parameter. For example, if the value of OriginalSize property is zero, it means that the minifier receives an empty string at the input.

yankarinRG commented 1 year ago

The problem is that unsless I set GenerateStatistics to true (which seems to "resolve" the issue) statistics is always null...

Taritsyn commented 1 year ago

... statistics is always null...

Here you are wrong, if the GenerateStatistics option is set to true and HTML minification was successful, then the Info method of logger will always be called with a statistics parameter not equal to null. I specially checked it now.

So let's not waste any more time. Try to reproduce this error in the form of demo project and send me a link to it.

yankarinRG commented 1 year ago

I'm sorry for any confusion my previous message may have caused. What I was trying to say is that if GenerateStatistics is not true, then statistics will be null and I won't be able to retrieve the OriginalSize and MinifiedSize properties as you had suggested earlier. So, we are actually in agreement on that point. I'll try to provide a demo project tomorrow

Taritsyn commented 1 year ago

… demo project and send me a link to it.

Here I mean a link to the source code of simple web application, not to a live demo website.

MenClapBadly commented 1 year ago

I'd like to add that I am using WebMarkupMin.AspNetCore6 (2.14.0) as part of another project and am experiencing the same issue.

Adding GenerateStatistics = true; does indeed make the issue go away.

It seemed to work fine when we just used MVC, but when I added scaffolded MS Identity code (RazorPages), this is when the issue started for us.

The project is too complex to link to, and I haven't had the time to repro the issue elsewhere.

Hope this helps.

MenClapBadly commented 1 year ago

Update: I have refactored the scaffolded code away from RazorPages into the classic MVC pattern we all know and love, and I still frequently get the blank page (unless I stall the process by adding the stats).

The only real difference between now and when the code previously seemed to work is the fact the Identity code still exists in a separate "Area". I'm going to refactor that next.

Taritsyn commented 1 year ago

@MenClapBadly, thanks for your research! When I have free time, I will definitely look for a solution to this problem.

MenClapBadly commented 1 year ago

@Taritsyn It looks like Areas are the problem, at least for me. I cannot speak for others on this issue.

Taritsyn commented 1 year ago

This error has been fixed in version 2.14.1.