Open hallidev opened 4 years ago
Thanks for contacting us. This may be potentially related to another reported issue: https://github.com/dotnet/aspnetcore/issues/21992
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
@mkArtakMSFT
I'm curious why this is considered minor severity and has been pushed from Next sprint planning? This is a pretty major issue and a deviation from how everything else in the .NET Core ecosystem works. It also makes managing configuration across environments very difficult. We have to manually edit appSettings.json to match the environment we're about to deploy to every single time we need to do a deployment.
I'm surprised that this issue hasn't been reported frequently. Am I missing something?
We solved it like this:
In Visual Studio project properties -> "Build Event" -> "Pre-build event command line", add the following line:
echo window.BlazorEnvironment = '$(ConfigurationName)'; > $(ProjectDir)wwwroot\js\BlazorEnvironment.js
In index.html, BEFORE bootstrapping Blazor with this tag: , add the following to make sure the "blazor-environment" header is set to the correct value:
<script src="js/BlazorEnvironment.js"></script>
<script>
const originalFetch = fetch;
fetch = async (url, options) => {
const response = await originalFetch(url, options);
return url.endsWith('/blazor.boot.json')
? new Response(await response.blob(), { headers: { 'blazor-environment': window.BlazorEnvironment } })
: response;
};
</script>
@trygvelo Thanks - will give this a try
I am also having this exact issue when hosting inside an nginx container.
I can see that the ASPNETCORE_ENVIRONMENT variable is set correctly, and that the files are present. However, only appsettings.json is ever loaded.
The script above will not work for my use-case, as I feed the variable through from an azure-pipeline script.
This got resolved by using Pascal Case ASPNETCORE_ENVIRONMENT=Dev , ASPNETCORE_ENVIRONMENT=Production
This got resolved by using Pascal Case ASPNETCORE_ENVIRONMENT=Dev , ASPNETCORE_ENVIRONMENT=Production
I'm not sure what you mean, we have the configuration in uppercase and it's not working,
Any update on progress on this feature?
Any updates on this? Not sure how this could be treated as a minor issue!!! The entire development and debugging (via visual studio) works just fine and it blasts out on the very first deployment (I'm using docker with Nginx as the server).
While it is logical to think that "Environment Variable" does not make sense for a static website application, it is very sad that no proper warning is provided in the MSDN - https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/configuration?view=aspnetcore-5.0
From the source code, it is evident that app settings transformation will work ONLY for ASPNET hosted WASM apps, and for the rest of others, it will default to "Production":
UPDATE - My Workaround
As I'm deploying the Blazor wasm in a Linux container (as Nginx as the server), I did the config "transform" during the build process. Updated docker file (pasting only relevant parts):
FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build
WORKDIR /src
..... deleting copy and restore lines for brevity...........
RUN dotnet publish "myblazorproj.csproj" -c Release -o /app/publish
# Use official nginx image as the base image
FROM nginx:latest as final
ARG BUILD_ENVIRONMENT
RUN echo $BUILD_ENVIRONMENT
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/publish/wwwroot /usr/share/nginx/html
# This is to fix the bug mentioned here - https://github.com/dotnet/aspnetcore/issues/25152
# Everything works (appsettings transformation) during local debugging, but the environment is not getting picked properly on publish
# Fixing it by replacing the appsettings.json file with the env specific file
# NOTE - This is a blind file replace and hence appsettings transformation will not work; make sure all settings are present in the enc specifci files as well
COPY --from=build /app/publish/wwwroot/appsettings.${BUILD_ENVIRONMENT}.json /usr/share/nginx/html/appsettings.json
EXPOSE 80
And during Docker build, pass the argument BUILD_ENVIRONMENT=
I'd love to see updates on this, as well. I see the "affected-very-few" label, but I feel like there is a fundamental and subtle issue with appsettings and non-dotnet blazorwasm hosts.
It seems it is not only an Azure problem, the same problem occurs on local machines as well. I followed the instructions told in https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-5.0 and then I do receive a HTTP 404 Not Found error message, Blazor WASM does not start at all. It seems it only works with one single or only in specific environments. The problem was also discussed here: https://github.com/dotnet/aspnetcore/issues/21992 - The answer was there that the problem will not be fixed in the near future by Microsoft. But in companies, multiple environments are often needed, e.g. if the same Blazor WASM shall e.g. run in two different production environments with different app settings. I would also love to have multiple environment support in Blazor WASM as soon as possible.
Same problem here, Microsoft wtf do you wanna fix that ?!
Blazor WASM can't read the Environment variables. MS has two documented options here, https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/environments?view=aspnetcore-5.0 Either, set the env in JS on in the web.config by setting a http header that Blazor can read.
I'm using the web.config approach and have my ci/cd pipeline replace the environment on build.
Kudos to @trygvelo for such a creative answer, even if it only works for WebAssembly deployments from Visual Studio. It feels dirty and I can't say I like it, but it did work for me using .NET 5 with a few tweaks that I'll describe for others.
As mentioned, I added a Pre-build event, but with a minor directory change (removing '\js' from the directory path):
In Visual Studio project properties -> "Build Event" -> "Pre-build event command line", add the following line:
echo window.BlazorEnvironment = '$(ConfigurationName)'; > $(ProjectDir)wwwroot\BlazorEnvironment.js
In index.html, BEFORE bootstrapping Blazor with this tag: , add the following to make sure the "blazor-environment" header is set to the correct value (again removing the '/js' directory from the path).
<script src="BlazorEnvironment.js"></script>
<script>
const originalFetch = fetch;
fetch = async (url, options) => {
const response = await originalFetch(url, options);
return url.endsWith('/blazor.boot.json')
? new Response(await response.blob(), { headers: { 'blazor-environment': window.BlazorEnvironment } })
: response;
};
</script>
If you do not do this, then all calls to the IsDevelopment() and IsProduction() methods will always return false. i.e.
[Inject]
public IWebAssemblyHostEnvironment env { get; set; }
...
if (env.IsDevelopment())
{
// Do something in DEV that isn't done in PROD
}
{ }
I did this because it seemed like the inheritance of values from appsettings.json to, say, appsettings.Production.json was not working correctly. In other words, when I had settings in both files, I believe I was getting the original configuration values from appsettings.json instead of the environment-specific ones. Transferring all DEV/Debug values from appsettings.json to the appsettings.Development.json file seemed to work best.
public string OidcConfigurationString
{
get
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("OidcConfiguration: ");
var oidcConfigSection = Configuration.GetSection("OidcConfiguration");
var itemArray = oidcConfigSection.AsEnumerable();
foreach (var item in itemArray)
{
sb.AppendLine($"{item.Key}: {item.Value}");
}
return sb.ToString();
}
}
The output from this can simply be displayed in a razor page as such:
<div style="margin-left:15px;">
@((MarkupString)OidcConfigurationString)
</div>
As you can guess, this was a big, frustrating, time sink and I have a hard time believing there isn't a better way. But, until I am enlightened by that better way, this will get me (and hopefully you) past the issue.
It's not only a problem of WASM and Azure. I've been running into the same bug on my local Blazor server app with IISExpress. Everything worked fine when I had set ASPNETCORE_ENVIRONMENT=Development
but as soon as i switched to Production
, I got this 404 error.
I reported this back in reported this in May of 2020 #21992 and it is still a lingering issues in .net Core 3.1, .net 5 and potentially .net 6? We are now a year and a half removed and this is still not fixed. Unless you have 2 environment, it is unthinkable that this could be an acceptable state.
Incase anyone would like to know, I was able to work around it by adding a second environment variable enviro
and set that to my sites environment (dev, qa, uat, prod, etc.). I read that variable out like I would ASPNETCORE_ENVIRONMENT
and created a middleware that sets the blazor-environment header with this value. This allows hosted WASM sites to properly pull in the environment from inside Blazor and things work as they should. It also allows me to pull in the proper appsettings.*.json files on the server.
I hope that one day this gets solved by the framework.
Encountered the same issue with dotnet 6.0.100
After setting "ASPNETCORE_ENVIRONMENT": "Production"
or anything other than Development
, Blazor WASM failed to serve, like what mentioned in #21992
It's very annoying as I want to change LogLevel
between my dev machine and production machine by just setting launch profile (not changing appsettings.json files) as doc suggested Use multiple environments in ASP.NET Core
, especially after several frustrating days.
Or I'd like to propose that we can have some note in the docs mentioned above that
For Blazor WASM project, Do NOT change
ASPNETCORE_ENVIRONMENT
to anything other thanDevelopment
, this won't work
I reported this back in reported this in May of 2020 #21992 and it is still a lingering issues in .net Core 3.1, .net 5 and potentially .net 6? We are now a year and a half removed and this is still not fixed. Unless you have 2 environment, it is unthinkable that this could be an acceptable state.
Incase anyone would like to know, I was able to work around it by adding a second environment variable
enviro
and set that to my sites environment (dev, qa, uat, prod, etc.). I read that variable out like I wouldASPNETCORE_ENVIRONMENT
and created a middleware that sets the blazor-environment header with this value. This allows hosted WASM sites to properly pull in the environment from inside Blazor and things work as they should. It also allows me to pull in the proper appsettings.*.json files on the server.I hope that one day this gets solved by the framework.
Hi Knight1219 you mentioned a middleware, you implemented by yourself. Do you think that getting this middleware could be possible? Maybe we could find an arrangement? I would like to setup a proper staging/production environment and I am stuck at this topic as well.
I am having this same issue using .NET 6.0.2. I have confirmed that blazor.boot.json Response Header does not have "blazor-environment" set
Questions from similar bug: Could you check the following things?
appsettings.{environment}.json file are being published Server process is setting the ASPNETCORE_ENVIRONMENT variable blazor.boot.json does not have the response header (Blazor-Environment) appSettings.json is requested by the browser instead of appsettings.{environment}.json file
Please escalate this bug.
Note: I am not sure why this bug has a label of "affected-very-few" or "severity-minor".
"affected-very-few", "severity-minor", ".NET 7 planning" - utterly ridiculous. This is such a fundamental aspect of app configuration and there is no stable workaround. Thanks a bunch Microsoft.
For ASP.NET Core Hosted Blazor WASM, This is the middleware I created. The enviro
variable is an additional environment variable I use to set dev/qa/prod. This should be the first middleware you register.
public class BlazorEnviromentMiddleware
{
private readonly RequestDelegate next;
private readonly IConfiguration configuration;
public BlazorEnviromentMiddleware(RequestDelegate next, IConfiguration configuration)
{
this.next = next;
this.configuration = configuration;
}
public async Task Invoke(HttpContext context)
{
// Call the next delegate/middleware in the pipeline
context.Response.OnStarting(async o => {
if (o is HttpContext ctx)
{
if(ctx.Response.Headers.ContainsKey("blazor-environment"))
{
ctx.Response.Headers.Remove("blazor-environment");
}
ctx.Response.Headers.Add("blazor-environment", this.configuration.GetValue<string>("enviro"));
}
await Task.CompletedTask;
}, context);
await this.next(context);
}
}
@knight1219 your middleware worked for me as well to fix the same issue I was having. My hosted blazor wasm app was published to IIS. The server had the aspnetcore environment variable correctly, but it wasn't being passed down to the client wasm app.
I ended up going a slightly different direction though. Correct me if I'm wrong, but the middleware is appending the response header to all responses? I instead let the UseStaticFiles AppBuilder extension append the blazor-environment header to the response serving the blazor.boot.json file only. I was already doing another response header modification to fix another blazor wasm problem with integrity here: https://github.com/dotnet/aspnetcore/issues/38552
Here is what I went with that combined the environment variable with the caching issue.
app.UseStaticFiles(new StaticFileOptions {
OnPrepareResponse = context => {
if (context.File.Name == "service-worker-assets.js") {
context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Context.Response.Headers.Add("Expires", "-1");
}
if (context.File.Name == "blazor.boot.json") {
if (context.Context.Response.Headers.ContainsKey("blazor-environment")) {
context.Context.Response.Headers.Remove("blazor-environment");
}
context.Context.Response.Headers.Add("blazor-environment", env.EnvironmentName);
}
}
});
"affected-very-few", "severity-minor", ".NET 7 planning" - utterly ridiculous. This is such a fundamental aspect of app configuration and there is no stable workaround. Thanks a bunch Microsoft.
Agreed, I don't understand how this is minor and very few affected. This makes Blazor WASM unusable in a production environment. Can someone from the team explain how this is a minor issue? What is the recommended method for deploying into multiple environments with the same code?
Here is the very hacky workaround that we ended up with in the index.html file we replaced:
<script src="_framework/blazor.webassembly.js"></script>
with:
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
<script>
if (window.location.hostname.includes("localhost") || window.location.hostname.includes("dev")) {
Blazor.start({
environment: "Development"
});
}
else if (window.location.hostname.includes("demo")) {
Blazor.start({
environment: "Demo"
});
}
else if (window.location.hostname.includes("stage")) {
Blazor.start({
environment: "Staging"
});
}
else {
Blazor.start({
environment: "Production"
});
}
</script>
We switched the standalone WASM application to hosted WASM application and followed the environment approach described in https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/environments?view=aspnetcore-6.0#set-the-environment-for-azure-app-service.
Same issue. Thought we were missing something, but as it seems it's impossible to resolve, unless you only want to use this during the production environment while deploying.
I'm trying to fix it via my deploy pipeline where I modify the name of the appsettings.{environment} to production.
Same issue here. @CameronVetter 's work-around is working for us, Thank you for sharing it.
I did have to make sure it was authentication line below:
<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
I like @gilm0079 use of the UseStaticFiles
middleware. I might even modify my code to do that to help not expose that in every API call i make to my backend. I'm not fond of using a URL or hostname to try and figure out what environment is being used (qa/staging/test are all urls used in my environments for the same stage of deployment).
I did see this was added to the .NET 7 preview milestone last month, is there active work being done on this issue? It's been a outstanding issue since Blazor's launch (not sure why my issue was closed #21992 about this.) I would love to tell my Architecture team we don't need an extra environment variable and we can go back to using ASPNETCORE_ENVIRONMENT.
It still is a bit hard to understand how this isn't an issue for more people and how the Blazor team doesn't see this as a critical issue.
Thanks for contacting us.
We're moving this issue to the .NET 7 Planning
milestone for future evaluation / consideration. Because it's not immediately obvious that this is a bug in our framework, we would like to keep this around to collect more feedback, which can later help us determine the impact of it. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Can someone on the team please comment? I'm baffled how Blazor WASM is considered even production worthy with this very basic feature broken. Seeing this issue keep getting kicked down the road makes me feel like we are all missing something. What is the official stance on what we are supposed to do to make Blazor suitable for multi-environment deployments? The documentation implies what this thread is labeling as a bug should work, yet the bot is telling us this is not a bug and the team appears disinterested.
@CameronVetter I'm just a user of Blazor like you. It seems like a lot of things, not just Blazor, are pushed to the .NET7 milestone. I have several shims in Blazor for the time being until .NET 7 is GA. I've just been working around it in the meantime.
My post above seems to be working great without needing to set the environment via javascript. Blazor reads the "blazor-environment" http header when loading blazor.boot.json. I'd recommend going that route for the time being as the static files response shim takes care of the 1 piece in the recommended pathway that is not currently working which is the blazor hosted environment should be setting the header value without manual intervention.
@CameronVetter I'm just a user of Blazor like you. It seems like a lot of things, not just Blazor, are pushed to the .NET7 milestone. I have several shims in Blazor for the time being until .NET 7 is GA. I've just been working around it in the meantime.
My post above seems to be working great without needing to set the environment via javascript. Blazor reads the "blazor-environment" http header when loading blazor.boot.json. I'd recommend going that route for the time being as the static files response shim takes care of the 1 piece in the recommended pathway that is not currently working which is the blazor hosted environment should be setting the header value without manual intervention.
There are numerous hacky workarounds in this thread that work. My question was for someone from Microsoft on this team that is deciding not to fix this to give us an answer on what the approach should be since what is documented doesn't work.
Why is this not fixed? The issue was reported 2 years ago.
ball dropped
Environment header in blazor.boot.json
response looks Good. Console write builder.HostEnvironment.Environment
shows the proper environment. but still, the appropriate appsettings json is not fetched from server
Looking at the source code
WebAssemblyHostEnvironment.Environmet
is set to dev
(as shown in console log). if that is the case, then why isn't apssettings.dev.json
is pulled from server
Looking at Blazor._internals.getConfig function, turns out, Blazor._internals.getConfig
function only pulls appsetting file If it is listed in blazor.boot.json
file.
Looking at blazor.boot.json
, files were listed in pascal case, so appsettings.Dev.json
, so i set the ASPNETCORE_ENVIRONMENT
env var to Dev
instead of dev
.
I'm guessing this is also affecting explicit calls to AddJsonFile
the same way right ?
I'm guessing this is also affecting explicit calls to
AddJsonFile
the same way right ?
I dont think there is a way to add json file manually in blazor. appsettings.json and appsettings.env.json seems pretty hard coded
You can still use this:
var env = "dev";
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json");
builder.AddJsonFile($"appsettings.{env}.json");
You just need to set env
from somewhere. I guess it depends on how you are hosting your app.
It doesn't seem to work, I get a FileNotFound
. I have verified that the file is in the wwwroot
folder. It seems to expect a physical path and doesn't try to fetch it using a relative path.
Jeep in mind that that executes on FE and configuration builder alone is not going to pull those files from BE
I used the information from @tchelidze, and changed my filename to appsettings.Dev.json
, and then changed my ASPNETCORE_ENVIRONMENT
to Dev
, then it started working correctly.
This seems very odd, and not at all aligned with how other .NET environments does it - so I totally agree with the other conclusions: This shouldn't be a minor issue.
Thanks for contacting us.
We're moving this issue to the .NET 8 Planning
milestone for future evaluation / consideration. Because it's not immediately obvious that this is a bug in our framework, we would like to keep this around to collect more feedback, which can later help us determine the impact of it. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Just to add how I´m doing this in case it helps someone down the line. It's probably not the best solution but I made it work for me.
I have a Release (this one is for my dev environment, and then I have another one for production that is 99% the same but with different variables)
where I do a JSON variable substitution on appsettings.Production.json (since that is always uesed)
so when there is a release the variables I have added are swapped out
Best would be if these things could be included in the project somehow and picked up from the AppService based on env or config. Little strange that this has been moved all the way to .NET 8 I have to say...
@sturlath, are you not serving the .gz or .br versions of the appsettings.env.json file or are you updating those as well?
Adding the appsettings.Development.json
(with an upper-case "D") to the \wwwroot
folder fixed this for me.
Our use case for this was to avoid tokenisation during deployment as that would fail integrity checks. We realised that WASM application can't read from Azure App Service app settings because its client side (probably why it got pushed for fixing, it is not very straight forward)
Its a shame that Azure App Service can't push that setting into the web.config httpProtocol.customHeaders section as the Blazor-Environment header automatically, though I don't think that wouldn't work for all scenarios anyway (another reason for the complexity)
Eventually we programmatically modified the web.config in a published artifact so that it would return the appropriate environment's header after deployment meaning we could add a file named like 'appsettings.qua.json' to our wwwroot folder.
DISCLAIMER: because all environments appsettings files need to be in wwwroot for this to work, this means the end user can access all files if they know the path. Naturally, you shouldn't be storing secrets here anyway because its client side - but you may also not want to do this if you don't want to expose your internal environment settings.
$environment = "qua"
$zipName = "drop"
#Extract the contents of archive for modification
Expand-Archive -Path "$zipName.zip" -Force
#Get existing XML file
[xml]$xml = Get-Content "$zipName\web.config"
$referenceNodeForInsertionPosition = $xml.configuration.'system.webServer'.staticContent
#Insert required node into XML at a specific position
$newNode = [xml]@"
<httpProtocol>
<customHeaders>
<add name="Blazor-Environment" value="$environment"/>
</customHeaders>
</httpProtocol>
"@
$newNode = $xml.ImportNode($newNode.httpProtocol, $true)
$xml.configuration.'system.webServer'.InsertBefore($newNode, $referenceNodeForInsertionPosition) | out-null
#Overwrite original XML
$path = Get-Location
$xml.Save($path.Path + "\$zipName\web.config")
#Archive folder and overwrite original zip
Compress-Archive -Path ($path.Path + "\$zipName\*") -DestinationPath "$zipName.zip" -CompressionLevel Optimal -Force
To learn more about what this message means, what to expect next, and how this issue will be handled you can read our Triage Process document. We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. Because it's not immediately obvious what is causing this behavior, we would like to keep this around to collect more feedback, which can later help us determine how to handle this. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact work.
The issue has been figured out and is an issue with case sensitivity. Saying its "not immediately obvious" is not a correct assessment. Please see @jasonshave comment above... This should be fixed ASAP, this has a huge impact and is a minor fix @mkArtakMSFT
It also looks like (maybe it's an intended behaviour, you'll tell me) Blazor WASM uses only appsettings.{...}.files
that are present at buildtime. If my environment is Staging
and I add a appsettings.Staging.json
file at runtime (using a docker-compose
volume
instruction, for example), it doesn't use or see it, and blazor.boot.json
only displays files that were present at buildtime appsettings: [appsettings.example.json", "../appsettings.json"]
... You would expect it to take them dynamically (as it does by taking into account appsettings.json
modifications at runtime)
Maybe that's related to Azure's issue, just dropping that information here
Describe the bug
When developing locally (Blazor WASM), I have the following files in /wwwroot:
My launchSettings.json specifies an ASPNETCORE_ENVIRONMENT of "LocalDevelopment".
When running locally, everything works as expected. appsettings.json and appsettings.LocalDevelopment.json are merged as expected.
I have just published the Blazor WASM app to Azure App Services, and appsettings.json merging fails. I have the ASPNETCORE_ENVIRONMENT set to "Development" in the App Service:
I have been able to confirm the failure by putting all of my settings in appsettings.json so that I don't need to rely on merging. The app runs as expected in the App Service.
To Reproduce
1: Create a new Blazor WASM ASP.NET Core Hosted application 2: Add appsettings.json, and appsettings.Development.json to /wwwroot 3: Add a configuration value to both files that requires merging. 4: Locally, set ASPNETCORE_ENVIRONMENT to "Development" 5: Confirm that the correct config value gets read 6: Deploy to Azure App Service 7: Set ASPNETCORE_ENVIRONMENT to "Development" for the App Service 8: BUG: Note that value is not read from appsettings.Development.json. It is read from appsettings.json.
Further technical details
dotnet --info