Style sheet not working after upgrade of ASP.NET Core MVC 7.0 application to 8.0
This issue has been moved from a ticket on Developer Community.
[severity:I'm unable to use this version] Dear Friends, I have just tried to upgrade an ASP.NET Core MVC 7.0 application to ASP.NET Core MVC 8.0. All I have done so far is to change the TargetFramework in the project file from netcoreapp7.0 to netcoreapp8.0 and to update all outdated NuGet packages. Now my style sheet no longer works. The reference in my Layout file looks like this:
. Could you please tell me what to do to make the stylesheet work again? Thank you for your trouble, and best regards, Eric WeinbergerOriginal Comments
Feedback Bot on 4/14/2024, 06:48 PM:
(private comment, text removed)
Eric Weinberger on 4/15/2024, 02:12 PM:
(private comment, text removed)
Original Solutions
(no solutions)
Thanks for contacting us. This is most probably due to incorrect / incomplete migration. Hopefully you can identify the issue yourself once you try to build a minimal repro project for us to investigate. if you do so, we'll look into it to see what may have changed.
Please forgive me to taking so long to respond.
In my _Layout.cshtml, I had
<link href="~/StyleSheet.css" rel="stylesheet" asp-append-version="true" />
which worked fine in .NET 7.0.
In .NET 8.0 the following seems to work, at least in development:
<environment names="Development"><link href="~/StyleSheet.css" rel="stylesheet" /></environment>
<environment names="Production"><link href="~/StyleSheet.css" rel="stylesheet" asp-append-version="true" /></environment>
I have not yet checked how this affects the effect of edits to the style sheet.
I have just experimented with a change in the style sheet, in development. The browser uses the previous version of the style sheet. This is, of course, undesirable. Could you please advise me on how to avoid this problem without causing others? Thank you for your trouble.
After I had uploaded the application, the styles did not work.
@xenophilios thanks for contacting us.
Does it work with "in-private" mode?
@javiercn
Thank you for responding so promptly. Could you please elaborate on your question? I'm not sure what it means. Are you referring to a setting in the browser, in Visual Studio, or in my code?
There is, however, some information I could add to what I have supplied so far.
In my _Layout view I have the following:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="expires" content="0" />
In Program.cs, I have the following (plus a lot of other code before, after, and in-between):
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(
new ResponseCacheAttribute
{
NoStore = true,
Location = ResponseCacheLocation.None
});
});
If the instructions in the layout conflict with the instructions in Program.cs, or if either set of instructions is problematic in any way, I would appreciate it if you could let me know.
Thank you very much in advance for your trouble, and best regards,
@xenophilios
@xenophilios the InPrivate mode was the mode of the browser that doesn't store any user preferences. @javiercn suggested that as a test to confirm it's caching what causes this. With Edge (on Windows) you can open the InPrivate mode with Ctrl+Shif+N.
Dear @mkArtakMSFT ,
Thank you for your kind response.
I have run two tests with Edge in InPrivate mode, both on the development server.
If I use asp-append-version="true" with the reference to the style sheet in my layout, the styles are ignored. Without this feature, they work as intended.
The same is true of references to JavaScript files in Razor views. With asp-append-version="true" they are ignored, otherwise they work.
I do not have these problems with .NET 7.0; only with 8.0.
With best regards, @xenophilios
I have just upgraded VS 2022 (Community Edition) from Version 17.9.6 to 17.9.7. It looks as though the problem has now been resolved. Thank you to all those who worked on dealing with this issue.
I'm sorry, but I spoke too soon. Things seem to work in development, but on the remote site the style sheet is not used. I cannot afford to leave it up long enough to do extensive testing on it.
@xenophilios thanks for the additional details.
This is very likely a caching issue in your configuration/deployment environment. To validate that:
- Check that the file in the wwwroot folder of your published app is up to date.
- Check that the file that your browser is retrieving is the older version.
- Check that navigating with InPrivate mode on Edge, does not show the issue https://support.microsoft.com/en-us/microsoft-edge/browse-inprivate-in-microsoft-edge-cd2c9a48-0bc4-b98e-5e46-ac40c84e27e2
- Make sure you do a clean build (remove any bin/obj folder from your project/solution before building).
@javiercn
Thank you for your kind message.
In both development and production, if I use "asp-append-version" set to "true" with a style sheet, the style sheet will be ignored, i.e. it will not work. If I use "asp-append-version" set to "true" with a JavaScript file, the JavaScript file will be ignored. This means that my previous remark to the effect that things seem to work in development was mistaken.
I could not find any bin/obj folder related to the project or solution.
As I have mentioned before, this problem only occurs with .NET 8.0, not with .NET 7.0.
In the process of trying to produce a minimal repo, I have discovered the following:
The problem with both the style sheet and the JS files was connected with a custom middleware component that triggered a redirection if the query string had a value. The purpose of this middleware component was to defend the application against hacker attacks with query strings.
I encountered a similar problem in .NET 6.0, but not in .NET 7.0.
In the current case, with .NET 8.0, functions in JS files marked with "asp-append-version" are invoked properly by buttons of type "submit", but not by buttons of type "button".
For security reasons, I would appreciate it if you could modify .NET 8.0 (and subsequent versions of .NET) to prevent a problem from arising in connection with asp-append-version when middleware causes a redirection in response to the existence of a query string.
@xenophilios thanks for the additional details.
It's not completely clear what you are saying, but from what we can tell you are mentioning that this is happening because of a third-party middleware that your app has in the pipeline (as opposed to anything built-in in the framework) is that correct?
For security reasons, I would appreciate it if you could modify .NET 8.0 (and subsequent versions of .NET) to prevent a problem from arising in connection with asp-append-version when middleware causes a redirection in response to the existence of a query string.
What exactly is the problematic behavior here from asp-append-version, that a value gets appended to the query string?
@javiercn Thank you for your kind message, and sorry for the obscurity of my explanation.
When I had a previous application online, I kept track of hacker attacks involving query strings, and there were many of them, mainly from Russia and Bulgaria.
So when I started working on my current project, I decided not to use query strings at all and to redirect any hackers who tried to attack my site with query strings.
For this purpose, I created a middleware component with the following function:
public async Task InvokeAsync(HttpContext c)
{
if (c.Request.QueryString.HasValue)
{
c.Response.Redirect("/");
}
}
I also tried the following a few days ago:
public async Task InvokeAsync(HttpContext c)
{
if (c.Request.QueryString.HasValue)
{
c.Request.QueryString = QueryString.Empty;
}
}
In each of these two cases, this middleware component prevented the loading of my style sheet and of some JavaScript files that were marked (in Razor views) with asp-append-version='true'.
In the case of the JavaScript files, if an invocation was assigned to onclick in a button of type submit, things seemed to work properly, but not if the button was of type button.
For security reasons, I think it is important to be able to deflect any requests involving query strings. However, for practical purposes it is equally important to have a device equivalent to asp-append-version="true".
As I mentioned in my previous post, the conflict between the two features occurred in .NET 6.0 and is now occurring in .NET 8.0, but did not occur in .NET 7.0, at least not recently. This seems to indicate that there is a way to prevent the conflict.
(By the way, I'm surprised, looking at the code now, that compiler never complained about the lack of an await in a function marked as async.)
By way of reminder, my project is an MVC web application using controllers and views.
Thank you for your efforts to resolve this issue.
As I mentioned in my previous post, the conflict between the two features occurred in .NET 6.0 and is now occurring in .NET 8.0, but did not occur in .NET 7.0, at least not recently. This seems to indicate that there is a way to prevent the conflict.
We haven't changed anything in this area in the last 3 releases.
For security reasons, I think it is important to be able to deflect any requests involving query strings. However, for practical purposes it is equally important to have a device equivalent to asp-append-version="true".
Blindly blocking query strings on the requests without reason doesn't look like a sound approach IMO. That said, it's up to you how to handle this within your app. However, the framework won't make any change to avoid query strings as there is not an inherent security problem with them and appending a query string to files is a very common pattern for versioning resources, especially static files.
Our recommendation would be that you apply your middleware selectively, for example by doing a quick check to see if the request contains an extension and skipping your middleware in that case.
@javiercn Thank you for your kind message.
I appreciate your advice on how to handle query strings, and I can certainly take a more sophisticated approach than I have until now.
I would, however, submit that something must have changed between .NET 7.0 and .NET 8.0 to cause a difference in behavior, even if this difference in behavior was not intended. It could have been a change in a NuGet package, for all I know.
All I had to do to trigger the problem was to change the target framework in the project file and update the NuGet packages.
I have found a way to deal with query strings without sabotaging asp-append-version.
Instead of using
if ([HttpContext].Request.QueryString.HasValue),
I use
if ([HttpContext].Request.GetDisplayUrl().Contains('?')).
We are now on VS Version 17.10.3. It looks as though the original problem has been fixed. If I'm not mistaken this time, as I have been on more than one occasion in the past, thank you to whoever took care of it.