Update:
Created an issue on Github ASP.NET Core project:
https://github.com/dotnet/aspnetcore/issues/32522
Original:
Created a new Blazor WebAssembly App with Microsoft Visual Studio 2019 Version 16.9.4 with Target Framework .NET 5.0 and ASP.NET Core Hosted.
The problem is that if I make an API call from the browser when the site is published to an Azure Web App I get an error response like this:
Sorry, there's nothing at this address.
If I make the request with "Empty cache and hard reload" everything works as expected.
The request always work on localhost
.
It is not limited to images loaded via API, same result for JSON response
.
How can I tell Blazor
to not use/ignore routing for URLs that contains /api/
?
I have read about ASP.NET Core Blazor routing
but not found anything there.
https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-5.0
The error message is from the App.razor
file:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
<MatPortalHost></MatPortalHost>
Same result if I use default value in App.razor
:
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if (!context.User.Identity.IsAuthenticated)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
ImagesController:
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ImagesController : ControllerBase
{
private readonly ApplicationDbContext _context;
public ImagesController(ApplicationDbContext context)
{
_context = context;
}
[HttpGet("{id}/file")]
[AllowAnonymous]
public async Task<ActionResult> GetImageDataFile(int id)
{
var image = await _context.Images.FindAsync(id);
if (image == null)
{
return NotFound();
}
return File(image.Data, image.ContentType);
}
Program.cs
for Blazor.Client
:
namespace Blazor.Client
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddHttpClient("Blazor.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddHttpClient<ImagesHttpClient>(client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddHttpClient<PostsAnonymousHttpClient>(client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("Blazor.ServerAPI"));
builder.Services.AddApiAuthorization();
builder.Services.AddMatBlazor();
await builder.Build().RunAsync();
}
}
}
Startup.cs
for Blazor.Server
, not modified at all:
namespace Blazor.Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
}
Publish config looks like this:
This was a real pain to debug but I eventually found the problem.
TLDR
Remove the line below from Blazor\Client\wwwroot\index.html
:
<script>navigator.serviceWorker.register('service-worker.js');</script>
Original:
To have some sort of start I had to reproduce the error locally. I did this by publishing my app to my local IIS instead of IIS Express. There were a few problems with certs and LocalDB
but I was able to reproduce the error locally after a while.
Blazor WebAssembly App with Individual Accounts and ASP.NET Core Hosted - IIS - SQLLocalDB 15.0 The specified resource language ID cannot be found
I then tried to create a new application to see if the error existed there. In a new application everything worked as expected. I then tried to step back in Git
to see when the error was introduced. I eventually ended up at the Initial commit
and the error was still there.
To find the actual error I first tried with WinMerge
to compare the folders but in order for that to work I would have to name the projects identically since every namespace
would show a diff otherwise.
Luckily there is Meld that can ignore specific words when comparing files and folders. I added two Text Filters under Meld Preferences that matched the namespaces I wanted to ignore and then compared the result.
https://stackoverflow.com/a/46162831/3850405
Now nearly everything was identical except from the Client\wwwroot\
folder. Looking at index.html
I noticed a big difference:
When creating the app I must have checked Progressive Web Application
due to the serviceWorker
above.
When I removed the line everything started working as expected.
<script>navigator.serviceWorker.register('service-worker.js');</script>
I then tried to create a new project with Progressive Web Application
set and deployed it to my local IIS with these settings:
After loading the site I could not reach https://localhost/_framework/blazor.boot.json
without seeing Sorry, there's nothing at this address.
.
If you would like to keep using Progressive Web Application
and Service worker
you can edit service-worker.published.js
and update shouldServeIndexHtml
to force urls to be server-rendered like this:
&& !event.request.url.includes('/api/')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With