Category Archives: Blazor

Blazor and the GetFromJsonAsync exception TypeError: Failed to Fetch

I have an Azure hosted web api. I also have a simple Blazor standalone application that’s meant to call the API to get a list of categories to display. i.e. the Blazor app is meant to call the Azure web api, fetch the data and display it – should be easy enough, right ?

The web api can easily accessed via a web browser or a console app using the .NET HttpClient, but the Blazor code using the following simply kept throwing exception with the cryptic message “TypeError: Failed to Fetch”

@inject HttpClient Http

// Blazor and other code

protected override async Task OnInitializedAsync()
{
   try
   {
      _categories = await Http.GetFromJsonAsync<string[]>("categories");
   }
   catch (Exception e)
   {
      Debug.WriteLine(e);
   }
}

What was happening is I was actually getting a CORS error, sadly not really reported via the exception so no exactly obvious.

If you get this error interacting with your web api via Blazor then go to the Azure dashboard. I’m running my web api as a container app, type CORS into the left search bar of the resource (in my case a Container App). you should see the Settings section CORS subsection.

Add * to the Allowed Origins and click apply.

Now your Blazor app should be able to interact with the Azure web api app.

Blazor and the JavaScript interop.

In the post Logging in Blazor we saw how we can use the IJSRuntime to call out to the JavaScript runtime.

Ofcourse we can interop with any JavaScript code within our application, so for example let’s make some simple changes to the index.html from that post and add a script block, such as this

<script>
   function displayMessage(msg) {
      alert(msg);
   }
</script>

Nothing very special here, but we just want something visual to more easily see our interop calls.

Next, in our .razor file let’s simple add a button and associated code block

<button @onclick="DisplayMessage">Alert</button>

@code {
   private void DisplayMessage()
   {
      JsRuntime.InvokeVoidAsync("displayMessage", "Hello JavaScript World");
   }
}

The IJSRuntime interface has the following methods

public interface IJSRuntime
{
   ValueTask<TValue> InvokeAsync<TValue>(string identifier, 
      object[] args);
   ValueTask<TValue> InvokeAsync<TValue>(string identifier, 
      CancellationToken cancellationToken, object[] args);
}

As you can see, both return a ValueTask, hence are awaitable, but neither matches our InvokeVoidAsync method. This is because there are a bunch of extension methods within JSRuntimeExtensions. These extension methods check that the supplied IJSRuntime is not null and then calls the interface methods.

In the example above, we are not interested in the return value, so let’s now return some value from our JavaScript…

Change the script to

<script>
   function displayMessage(msg) {
      return prompt(msg);
   }
</script>

and now change the C# code in our code block to

private async void DisplayMessage()
{
   Debug.WriteLine(
      await JsRuntime.InvokeAsync<string>(
         "displayMessage", "Hello JavaScript World"
      )
   );
}

At this point, we’re receiving the return from our JavaScript function and (in the case of a WebAssembly application) outputting to the browser console.

Ofcourse we can now write JavaScript code and call this from Blazor as well.

Blazor/ASP.NET core on docker

I wanted to get a Blazor server application up and running on Ubuntu within a docker container (I’m running the whole thing on a Raspberry Pi 4 with Ubuntu Server).

The first stage for this post will simply be about creating a Dockerfile and creating a Blazor server application via the dotnet template.

We’re going to want the latest version of dotnet core, so let’s start by creating a very bare bones Dockerfile which will create an image based upon
mcr.microsoft.com/dotnet/core/sdk:3.1, it will also expose the standard HTTP port used in the Blazor server template, i.e. port 5000

Here’s the Dockerfile

FROM mcr.microsoft.com/dotnet/core/sdk:3.1
ENV APP_HOME /home
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
EXPOSE 5000
CMD [ "bash" ]

To build this image run the following

docker rmi dotnet-env --force
docker build -t dotnet-env .

The first line is solely there to remove any existing image (which will be especially useful whilst developing the image). The second line will build the Dockerfile and name it dotnet-env.

Once built, let’s run the image to see all is good with it. So simply run

docker run -it --rm -p 5000:5000 -v /home/share:/home/share dotnet-env

In this example we’ll run docker in interactive mode and map ports using -p to map the host port 5000 to the exposed port in the image. We’ll also also created a volume link from the container to the host.

Once we’ve run the image up we should be placed into a BASH command prompt, now we can simply run

dotnet new blazorserver -o MyServer

To create the project MyServer, once created cd into the MyServer folder. Now run

dotnet run

A kestrel server should start up, and you might be able to access the server using http://server-ip-address. I say might, because you may well see an error at startup, saying something like

Unable to bind to http://localhost:5000 on the IPv6 loopback interface: ‘Cannot assign requested address’.

What you need to do is go into the Properties folder and open launchSettings.json, change the line

"applicationUrl": "https://localhost:5001;http://localhost:5000",

to

"applicationUrl": "http://0.0.0.0:5001;http://0.0.0.0:5000",

Next Step

This obvious next step to our docker build is to create a Docker image which contains our application and runs it when the container is started. We’re going to build and publish the using dotnet publish -c Release -o publish and then include the published files in our docker container, alternatively you might prefer to have the Dockerfile build and publish the project as part of its build process.

For now let’s just build our Blazor server application, then publish it to a folder.

We’re going to host the application in Kestrel, so before we go any further open the appsetting.json file from the publish folder and add the following

"Kestrel": {
  "EndPoints": {
    "Http": {
      "Url": "http://0.0.0.0:5000"
    }   
  }
},

Now we’ll make the changes to the Dockerfile to copy the published folder to the image and start up the Kestrel server when the image is run, here’s the Dockerfile

FROM mcr.microsoft.com/dotnet/core/sdk:3.1

ENV APP_HOME /home
RUN mkdir -p $APP_HOME

WORKDIR $APP_HOME

COPY ./BlazorServer/BlazorServer/publish ${APP_HOME}

EXPOSE 5000

CMD [ "dotnet", "BlazorServer.dll" ]

Now you should be able to access your server using http://your_server_name:5000.

Blazor Components

We can create Blazor components within our Blazor application by simply right mouse clicking on a folder or project in Visual Studio and select Add | Razor Component.

A component derives from Microsoft.AspNetCore.Components.ComponentBase, whether implicitly, such as within a .razor file or explicitly, such as in a C# code file.

Razor component

If we create a .razor file we are already implementing a ComponentBase, but usually without an explicit inherit such as the following

@inherits ComponentBase

With or without this @inherit, we will get a generated file (written to obj\Debug\netstandard2.1\Razor) that is a class which implements the ComponentBase.

We can add code to our .razor file in a @code block, thus combining markup and code within the same file, as per this example

@namespace BlazorApp

<h3>@Text</h3>

@code {
    [Parameter]
    public string Text { get; set; }
}

Separate code and razor files

As alternative to a single .razor file with both markup and code, we can create a .cs file for our code. For example if our .razor file is MyComponent.razor we could create a MyComponent.cs and put our code into a C# class. The class should derive from ComponentBase and also be partial

Hence now we have a MyComponent.razor file that looks like this

@namespace BlazorApp

<h3>@Text</h3>

and a C# file, MyComponent.cs that looks like this

using Microsoft.AspNetCore.Components;

namespace BlazorApp
{
    public partial class MyComponent : ComponentBase
    {
        [Parameter]
        public string Text { get; set; }
    }
}

Ofcourse the use of the partial keyword is the key to this working. If we name the file MyComponent.cs all will be fine, but if we name the file MyComponent.razor.cs the file will appear like a code-behind file in other C# scenarios.

Code only component

We could also write a code only component, so let’s assume we have only a MyComponent.cs file

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

namespace BlazorApp
{
    public class MyComponent : ComponentBase
    {
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.OpenElement(1, "h3");
            builder.AddContent(2, Text);
            builder.CloseElement();
        }

        [Parameter]
        public string Text { get; set; }
    }
}

Obviously we have to put a little bit of effort into constructing the elements in the BuildRenderTree method, but this might suit some scenarios.

Pages and Layouts

Pages and Layouts are just components, just like those discussed above.

The only difference of between a Page and component is that our class is annotated with a PageAttribute for Page. Obviously in a .razor file this happens automatically when we add a page declaration as below

@page "/"

As for the layout, we inherit from LayoutComponentBase, in a .razor file this looks like this

@inherits LayoutComponentBase

Dependency Injection and Blazor

In a previous post Blazor routing and Navigation we injected the NavigationManager into out page using the following

@inject NavigationManager NavManager

So when we use @inject followed by the type we want injected, ASP.NET/Blazor will automatically supply the NavigationManager (assuming one exists).

Adding services

Ofcourse we can also add our own types/services to the DI container.

On a Blazor WebAssembly application, we can add types to the Program.cs, Main method, for example

public static async Task Main(string[] args)
{
   var builder = WebAssemblyHostBuilder.CreateDefault(args);
   // template generated code here

   // my custom DataService
   builder.Services.AddSingleton<IDataService, DataService>();

   await builder.Build().RunAsync();
}

In Blazor Server, we add our types to the Startup.cs, ConfigureServices method, for example

public void ConfigureServices(IServiceCollection services)
{
   // template generated code here

   // my custom DataService
   services.AddSingleton<IDataService, DataService>();
}

Service lifetime

In the examples in the previous section we added the service as a singleton.

  • Scoped – this is means the service is scoped to the connection. This is the preferred way to handle per user services – there is no concept of scope services in WebAssembly as obviously it’s a client technology at this point and already per user scoped
  • Singleton – As you’d expect, this is a single instance for the lifetime of the application
  • Transient – each request for a transient service will receive a new instance of the service
  • If you need access to service is a Component class, i.e. you’re creating your own IComponent you have mark a property with the InjectAttribute

    public class MyService
    {
       [Inject]
       IDataService DataService { get; set; }
    }
    

    Ofcourse constructor injection (my preferred way to do things) is also available, so we just write code such as this, assuming that MyService is created using the service container

    public class MyService
    {
    public MyService(IDataService dataService)
    {
    // do something with dataService
    }
    }

    Configuration and Blazor

    In a previous post we looked at dependency injection within Blazor. One of the services available by default is an implementation of IConfiguration, hence to inject the configuration object we do the following

    @inject IConfiguration Configuration
    

    and we can interact with the configuration using a key, i.e.

    @Configuration["SomeKey"]
    

    For Blazor on the server we can simply add the key/value to the appsettings.json file, like this

    "SomeKey":  "Hello World" 
    

    By default Blazor WebAssembly does not come with an appsettings.json, so you’ll need to add one yourself. This file will need to be in the wwwroot folder as these files will be deployed at part of your client.

    You can put sensitive data in the server appsettings.json because it’s hosted on the server, do not put sensitive information in the appsettings.json for a WebAssembly/client otherwise this will be downloaded to the user’s machine.

    If you want to store more complicated data in the appsettings.json, for example a JSON object, you’ll need to create a class that looks like the data, for example if your appsettings.json had the following

    "Person": {
      "FirstName": "Scooby",
      "LastName": "Doo"
    } 
    

    So now we’ll need a class to match the structure of the data. The name of the class is not important, the structure is, so here we have

    public class MyPerson
    {
       public string FirstName { get; set; }
       public string LastName { get; set; }
    }
    

    Now to access this we need to use

    Configuration.GetSection("Person").Get<MyPerson>();
    

    References

    Carl Franklin’s Blazor Train: Configuration and Dependency Injection

    Logging in Blazor

    It’s not unusual for us to need to output log message to file, console etc. Obviously there’s going to be a different in capabilities for logging from WASM (essentially on the client browser) and on a server.

    Blazor supplies the logging framework

    Blazor supplies loggin via the ILogger, ILogger, ILoggerFactory and ILoggerProvider interfaces. In most cases you’ll use the ILogger and ILogger.

    Logging capabilities are supplied via the WebAssemblyHostBuilder on WebAssembly and Host on the server (see Program.cs in both project types).

    We can therefore use these interfaces/implementation via injection like this

    @inject ILogger Logger;
    // OR
    @inject ILogger<MyPage> Logger;
    

    Alternatively we might use the ILogFactory like this

    @inject ILoggerFactory LoggerFactory
    
    // with the following
    var logger = LoggerFactory.CreateLogger<MyPage>();
    

    Logging in WebAssembly

    With WebAssembly on the client, we’d obviously expect to be logging to the Browser devtools. Whilst we can actually just use

    Console.WriteLine("Message 1");
    Debug.WriteLine("Message 2");
    

    the Logging framework offers some extra functionality, such as categorisation of logs etc. To use the ILogger or ILogger, we simply use

    Logger.LogWarning("Log a warning");
    

    (we have the ability to log debug, warning, info etc.)

    Logging to Server

    For Blazor Server, the output from the logging will be visible in the console window if running as a standalone application or the output window of Visual Studio.

    However if you want your Blazor server application to output to the browser, then you need to use the IJSRuntime, which we can inject like this

    @inject IJSRuntime JsRuntime
    

    and then use the runtime like this

    JsRuntime.InvokeAsync<string>("console.log", "Browser Message");
    

    as you can see, the runtime allows us access to the JavaScript runtime hosting our pages and we can call the console.log JavaScript method, passing the parameters for the method call. In our case it’s just a string “Browser Message”.

    Adding custom logger

    To add a custom logger we can use something like this, where the DebugProvider is our implementation of an ILoggingProvider

    builder.Logging.AddProvider(new DebugProvider());
    

    Configuration

    Configuration is placed in the appsettings.json file (remember if you’re using appsettings.json on WebAssembly client then this should be placed in the wwwroot folder otherwise it’s not set to the browser). For server the appsettings.json can be in the project folder.

    Here’s the template generated appsettings section for logging

    "Logging": {
      "LogLevel": {
        "Default": "Trace",
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    

    Creating Blazor fragments

    At some point you may need to dynamically create elements of mark-up in a Blazor application. For example, you might create a reusable class library for returning components, icons or the likes depending upon the user.

    Ofcourse we can do this from the @code block within a page or we might prefer to simply return mark-up from a function.

    Let’s look at a simple example method which, depending upon the id sent to it returns a different icon, here’s an abridge snippet of the code

    public static RenderFragment GetIconForId(int id)
    {
       var iconType = typeof(ListIcon);
       switch (id)
       {
          case 0:
             iconType = typeof(HomeIcon);
             break;
          case 1:
             iconType = typeof(NotificationImportantIcon);
             break;
          // etc.
       }
       
       return builder =>
       {
          builder.OpenComponent(0, iconType);
          builder.CloseComponent();
       };
    }
    

    As you can see we return a RenderFragment which is actually just a delegate which takes a RenderTreeBuilder argument. From this builder we create/append a child component, the first value is a sequence (a position of the instructions in the source code) followed by the type of the child component to add.

    If the case above, the HomeIcon is an Icon from Skclusive.Material, which is ultimately an Microsoft.AspNetCore.Components.IComponent.

    So anything that takes a RenderFragment will now display the icon that’s returned via the method in our example.

    We can also use AddAttribute to our component, see RenderTreeBuilder for more information.

    Basically it’s not dissimilar (as you’ve expect) to create XML documents using the XmlDocument classes etc.

    Blazor routing and Navigation

    Routing

    If you take a look at the generated pages for a Blazor application, you’ll see the following

    @page "/counter"
    

    this denotes a route to our page, i.e. http://localhost:44319/counter.

    Note: When you compile your application a file is generated (see Counter.g.cs in compiled folder) and this page declaration is converted to a RouteAttribute.

    You can have multiple routes pointing to the same page, in this example all these routes will navigate to the same Counter.razor page

    @page "/counter"
    @page "/mycounter"
    @page "/something"
    

    Probably more useful is the ability to add parameters to our routes, for example

    @page "/counter"
    @page "/counter/{InitialValue}"
    

    By default InitialValue is of type string, but we can change this by using a constraint, for example

    @page "/counter"
    @page "/counter/{InitialValue:int}"
    

    Now we simply create a property in our code with the ParameterAttribute applied to it, like this

    [Parameter]
    public int? InitialValue { get; set; }
    

    We use a nullable int in case the value is missing. We can also have routes handling different type contraints (for example a string or on int) to mean two different things

    @page "/counter"
    @page "/counter/{InitialValue:int}"
    @page "/counter/{SomeString}"
    

    In our OnInitialized() method (part of the component life cycle) we might then set the currentCount to InitialValue.

    The routes are declared in our pages but the routing component itself can be found in App.razor. In this case the Router will locate the routes from the supplied AppAssembly

    <Router AppAssembly="@typeof(Program).Assembly">
    

    We can also includes routes within AdditionalAssemblies, for example maybe you’ve got some reusable components with routing supplied, hence we write

    <Router AppAssembly="@typeof(Program).Assembly" 
       AdditionalAssemblies="new[] { typeof(MyComponents).Assembly }>
    

    Navigation

    If you want to navigate to other pages, we need to use the NavigationManager. This needs to be injected into our page, using

    @inject NavigationManager NavManager
    

    Now to navigate, for example when a button is click, we use the following

    NavManager.NavigateTo("counter/2");
    

    In the instance we’ll navigate to the relative URL/page with “counter/someData”.

    This works fine when navigating to other pages but if we want to navigate within a page and we’re using the component’s OnInitialized method to initialize data?

    Because OnInitialized is called when the page is initial loaded and because we’re already in the page, this method will not normally be called again if we navigate within the page, so we simply need to supply an extra parameter to our NavigateTo code to force the page to reload, i.e.

    NavManager.NavigateTo("counter/2", true);
    

    Note: An alternative solution ofcourse is to override the other life cycle method OnParameterSet and instead move initialization code to that method.

    Adding imports to your Blazor app.

    The default template’s supplied for Blazor Server and WebAssembly applications, gives you lots upfront. However, ofcourse you’re likely to want to import further functionality via the @using directive.

    For example, let’s say we want to add the following to the Counter.razor IncrementCount method (from the default template generated files)

    Debug.WriteLine("Increment");
    

    We can simply add the following to the top of the Counter.razor file

    @using System.Diagnostics
    

    Alternatively and especially useful for using code across multiple pages/components, you can put the above code into the _Imports.razor file. Think of this as a global set of using reference, but only for @code sections, for standard C# classes we ofcourse use the using directive as usual.

    Note: I’ve found my current version of Visual Studio doesn’t seem to immediately recognise the updated _Imports.razor file, a build fixes that.