Can Of Code

Author Archives: Josh Browning

Blazor WebAssembly on a different host to the Server

If you open up the Blazor WebAssembly project template it is configured to run both the client and the server sharing the same host localhost:5001 for example. If you want to host your client separately from the server you have to change a few settings on both the client and server which wasn’t clear out the gate, I have created a walkthrough on how I achieved this and hopefully its some use to you too.

Who is this for?

  • Want to have the Blazor WebAssembly client hosted on a different URL say  client.myexample.com and your API on api.myexample.com
  • Those new to Blazor (like myself)

CORS

Because we are accessing the Server from a different host than the API we have to configure CORS to allow access. What is less than ideal is that you do have to set the CORS for IdentityServer and for ASP Core separately.

In the Server project I added the following to the ConfigureServices method in Startup.cs

var _loggerFactory = new LoggerFactory(); 
var cors = new DefaultCorsPolicyService(_loggerFactory.CreateLogger<DefaultCorsPolicyService>()) 
{ 
AllowedOrigins = { "https://client.myexample.com"} 
}; 
services.AddSingleton<ICorsPolicyService>(cors);

This adds our client host to the Allowed origins that is used by IdentityServer. We now need to also allow our client to the ASP Core Allowed Origins. There are multiple ways to do this but I had success using the following in the Configure Method in the servers Startup.cs.

app.UseCors(policy => { 
    policy.AllowAnyHeader(); 
    policy.AllowAnyMethod(); // This was added to stop blocking DELETE requests 
    policy.WithOrigins("https://client.myexample.com"); 
});

This should at least allow us to send requests from our client hosted at client.myexample.com to our server at api.myexample.com

Setting up the OIDC Client

OpenID Connect (OIDC) uses clients to keep track of things like redirect urls allowing you to have a different client for different frontends, say Mobile Apps or SPA. in the Blazor example, these are set in the appsettings.json and the default setup looks like this:

"IdentityServer": { 
"Clients": {
"WhatsForDinDins.Client": { "Profile": "IdentityServerSPA" } }
}

While this keep things nice and tidy for someone new, it does hide the configuration we need to set if we are not based on the same host. After a lot of trial and error I found the following configuration allowed us to authenticate with a client on a different host:

"IdentityServer": {
"Clients": {
"ProjectName.Client": {
"Profile": "SPA",
"RedirectUri": "https://client.myexample.com/authentication/login-callback/",
"LogoutUri": "https://client.myexample.com/authentication/logout-callback/",
"AllowedScopes": [ "ProjectName.ServerAPI", "openid", "profile" ]}
}
},

Here we are setting the clientId as “ProjectName.Client” and telling IdentityServer that it should callback to our client domain after it has authenticated. We also set the allowed scopes with “ProjectName.ServerAPI” being the API. Although I’m not sure this is required. The Profile value I’m still not sure but I found that setting SPA was what worked where as IdentityServerSPA did not. 

At this point our Server should be set to allow authentication and controller requests from our externally hosted client at client.myexample.com

Setting up the Blazor client

First we need to update our HttpClient to use our server host base address instead of the default which assumes the server is located on the same host as the client.

builder.Services.AddScoped<CustomAuthorizationMessageHandler>();

      
builder.Services.AddHttpClient("ProjectName.ServerAPI", client => client.BaseAddress = new Uri("https://api.myexample.com"))
                .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();

You may notice that we have a CustomAuthorizationMessageHandler. We have created a class that is used to ensure that the Authorization knows to look for our server instead of assuming its located on the same domain.

public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
        public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
            NavigationManager navigationManager)
            : base(provider, navigationManager)
        {
            ConfigureHandler( 
                authorizedUrls: new[] { "https://api.myexample.com" },
                scopes: new[] { "ProjectName.ServerAPI", "openid", "profile" });
        }
    }

Lastly in our Program.cs of the client we need to replace the default API Authentication and replace it with our own configuration values using AddOidcAuthentication:

builder.Services.AddOidcAuthentication(options =>
{
    options.ProviderOptions.MetadataUrl = "https://api.myexample.com/.well-known/openid-configuration";
    options.ProviderOptions.ClientId = "ProjectName.Client";
    options.ProviderOptions.Authority = "https://api.myexample.com/";
    options.ProviderOptions.ResponseType = "code";
    options.ProviderOptions.RedirectUri = "https://client.myexample.com/authentication/login-callback/";
    options.ProviderOptions.PostLogoutRedirectUri = "https://client.myexample.com/authentication/logout-callback/";
    options.UserOptions.ScopeClaim = "ProjectName.ServerAPI openid profile";
 });

And with that we should be set up to authenticate and call authorized controller actions from a client hosted on a separate host from its server.

It might not be the best way..

I came to this solution as a beginner to Blazor and with a rough understanding of OIDC so there maybe a better way to configure this without having to change so much configuration. Perhaps you only have to set the CORS in one location? Happy to hear if you have a different solution and of course I will update this post if I find out more. 

Posted in Blazor | Tagged , | Leave a comment

Podcasts Recommendations

One hour of my day is dedicated to walking my dog and something I find fits perfectly with this is slotting some headphones in and listening to a podcast. I thought I would share some podcasts recommendations that I enjoy and that you might not have heard of.

Planet Money

By NPR

A light introduction to topics relating to economics and business. The podcast has covered a fast range of topics from why some packs of M&Ms have an odd weight to buying their own barrel of oil to investigate the process.  The podcast never fails to give a light and entertaining overview of a topic that might never had crossed your mind.

Websitehttps://www.npr.org/sections/money/

Notable Episode: Fascinating take on the benefits of the US bankruptcy laws

How I built this

By NPR

How I built this follows the story of the people behind current and past business successes.  They have had a wide range of guests from Howard Schultz whom transformed Starbucks to what it is today, to say Rod Canion who co-founded Compaq (A story very familiar to those who have watched the first season of Halt and Catch Fire). Like Halt and Catch Fire, this podcast never fails to give an injection of inspiration.

Website: https://www.npr.org/podcasts/510313/how-i-built-this

Notable Episode: Compaq

The Documentary

By BBC World Service

The Documentary offers a short insightful podcasts about issue from around the world from a podcast discussing the Generation gap in China to an insight to the hackers of Siberia. I can find the news can tend to ignore international topics and therefore I find these documentaries a good source for understanding events occurring in the rest of the world.

Websitehttps://www.bbc.co.uk/programmes/p02nq0lx/episodes/downloads

Notable EpisodeThe CIA’s Secret War in Laos (From the son of one of the CIA Spies in Laos)

Bonus: What App?

It was the case for a long time that all the stock podcast apps were not up to the job in hard. For a couple of years I have used PocketCasts. It manages all the syncing of feeds and downloading of episodes for offline listening. I have not experienced any issues with it and it does seem that is regularly updated.

Websitehttps://www.shiftyjelly.com/pocketcasts/

That is some of the podcasts I listen to, got any recommendations?

Posted in Uncategorised | Leave a comment

ASP.NET Core – Can not find runtime target error

Just ran across a issue when creating a new ASP.NET Core project and upgrading to the 1.1.0 Nuget packages. When trying to build I would get this error:

Screenshot of Error List in Visual Studio

To resolve I opened the project.json and found in the dependencies:

“Microsoft.NETCore.App”: “1.1.0”,

and change to:

“Microsoft.NETCore.App”: { “version”:  “1.1.0”, “type”: “platform”}

Posted in Uncategorised | Leave a comment