Polly and Blazor, Part 3 – Dependency Injection

Full source code available here.

This post continues to build on the two previous on using Polly with Blazor. The first was a simple example of using a Wait and Retry while updating the display as the policy retried, the second did the same but made use of the Polly Context. The Polly Context is something I have not made a lot of use of in the past, but I have a feeling that it will be very helpful with Blazor applications.

I’m keeping the examples similar, deliberately changing a single thing in each. In this post I will define the Wait and Retry Policy in the Startup, add it to the service collection and inject it into the Razor page.

One big difference to note is that I can no longer update the display from inside the OnRetry delegate of the Policy. Gone is the call to InvokeAsync(StateHasChanged) because this is dependent on the the ComponentBase.

In Startup.cs add the following, it defines the Wait and Retry policy, and its OnRetry delegate –

public void ConfigureServices(IServiceCollection services)
    {
    IAsyncPolicy<HttpResponseMessage> _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
    r => !r.IsSuccessStatusCode)
    .WaitAndRetryAsync(3,
        retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry: (response, retryDelay, retryCount, context) =>
        {
            context["message"] = context["message"] + $"\nReceived: {response.Result.StatusCode}, retryCount: {retryCount}, delaying: {retryDelay.Seconds} seconds";
        });

    services.AddSingleton<IAsyncPolicy<HttpResponseMessage>>(_httpRequestPolicy);
    // snip...

In the Razor section of the Index.razor page add this –

@inject IAsyncPolicy<HttpResponseMessage> _httpRequestPolicy

The policy will now be injected into the Razor page.

Using it is simple, see line 16 below –

@code {
   HttpClient httpClient = new HttpClient() {
        BaseAddress =  new Uri("http://localhost:5000")
    };

    private string status;
    private Context context = new Polly.Context("", new Dictionary<string, object>() {{"message",""}}); 
    private string responseCode;
    private string number;

    private async Task CallRemoteServiceAsync()
    {
        status = "Calling remote service...";
        string requestEndpoint = "faulty/";

        HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(ctx => httpClient.GetAsync(requestEndpoint), context);
        responseCode = httpResponse.StatusCode.ToString();
        number = await httpResponse.Content.ReadAsStringAsync();
        status = "Finished";
    }
}

Instead of injecting a Polly Policy you could inject a Polly Registry with more than one policy. I have written about the registry a few times on this blog.

Full source code available here.

Polly and Blazor, Part 2 – Using the Context

Full source code available here.

This post is a short follow up to the one where I used Polly Wait and Retry in Blazor. In that post I used variables defined in my C# method to pass information back to the calling code, to display on the screen. But here I’m going to show how the Polly Context can be used instead.

The setup and almost all the code is the same, so please take a look at that post.

Using the Context
The Razor section references the message in the Polly context rather than a defined variable for the message –

<p>Polly Summary : @context["message"]</p>

In the code block add a Polly Context and initialize the dictionary with a message, this is important because the Razor block references this message when the page loads.

@code {
    //snip...

    private Context context = new Polly.Context("", new Dictionary<string, object>() {{"message",""}});
    //snip... 

Then in the rest of the code block, update the message in the context with the information to display to the user.

private async Task CallRemoteServiceAsync()
{
    IAsyncPolicy<HttpResponseMessage> _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
        r => !r.IsSuccessStatusCode)
        .WaitAndRetryAsync(3,
            retryAttempt => TimeSpan.FromSeconds(retryAttempt * 2), onRetry: (response, retryDelay, retryCount, context) => {
                context["message"] = $"Recieved: {response.Result.StatusCode}, retryCount: {retryCount}, delaying: {retryDelay.Seconds} seconds\n";
                Console.WriteLine(context["message"]);
                InvokeAsync(StateHasChanged);
    });
    status = "Calling remote service...";
    string requestEndpoint = "faulty/";
    HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(ctx => httpClient.GetAsync(requestEndpoint), context);
    responseCode = httpResponse.StatusCode.ToString();
    number = await httpResponse.Content.ReadAsStringAsync();
    status = "Finished";
    context["message"] = "";
}

That’s it, another way to do the same thing.

In the next post I’ll show how to use a Polly Policy defined within the OnInitializedAsync block.

Full source code available here.

Blazor, Updating or Refreshing the Display During a Method Call

Full source code available BlazorUpdatingUIEverySecondWasm.

This is a quick post to show how to show how to refresh or update components on a Blazor page asynchronously, for example in response to a task or tasks completing.

In this example I have a button that calls a method, inside the method I have for loop, inside each iteration of the for loop, I increment the counter twice, delay twice, and update the display twice using a call to StateHasChanged().

Here is the code –

@page "/"

<h1>Updating the state of the page every second</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="StartCounterAsync">Start counter</button>

@code {
    private int currentCount = 0;
    private async Task StartCounterAsync()
    {
        for (int i = 1; i <= 10;)
        {
            await Task.Delay(1000);
            currentCount = i++;
            StateHasChanged();  
            await Task.Delay(1000);
            currentCount = i++;
            StateHasChanged();  
        }
    }
}

Once you know how to do it’s easy.

There is scenario where using StateHasChanged() won’t work and instead you’ll get an error like –

Exception has occurred: CLR/System.InvalidOperationException
An exception of type 'System.InvalidOperationException' occurred in Microsoft.AspNetCore.Components.dll but was not handled in user code: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'
   at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()

In this case use InvokeAsync(StateHasChanged); instead and it should work.

Full source code available BlazorUpdatingUIEverySecondWasm.

Polly and Blazor, Part 1 – Simple Wait and Retry

Full source code available here.

A few weeks ago I gave a talk on Polly at Dotnetconf (you can check it out here), at the end I got many questions about using Polly with Blazor, I had never tried it, but assumed it would work.

In this blog, part 1 of a few on Polly and Blazor, I’ll show you how to get a simple retry mechanism up and working in a Blazor Server App. I am not concerned with dependency injections, policy registries or anything other fancy things in this post, that will come later..

The setup
I have a .Net 5 Blazor Server app created with

dotnet new blazorserver

I stripped out the Blazor pages I didn’t need, and changed the code of the Index.razor file to make a HTTP call to a controller that generates errors 75% of time. I removed links to the other Blazor pages too.

Around the HTTP call I use the Polly Wait and Retry Policy to retry up three times, with a delay between each request. If you haven’t used Polly before, I have written a LOT about it, and have a Pluralsight course on it.

I made a few updates to the UI to show what the HttpClient and Polly are doing.

The Wait and Retry policy will retry after 2, 4 and 6 seconds. It prints out the to the console and updates the UI with the errors it gets from the remote system and details about the retry.

Because this is my first Blazor app, it took a little longer and may have some less than perfect approaches, but you should be able to take the retry idea and apply it to you application.

Before I show the code for retrying, let me show how I added a familiar Web API controller.

In Configure(..) method of Startup.cs I added endpoints.MapControllers(); to the below block so it looks like this –

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers(); // added this
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

Then I created a Controllers directory and added a new file FaultyController.cs.

Here is its code –

using Microsoft.AspNetCore.Mvc;

namespace WebApiDataDog.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class FaultyController : ControllerBase
    {
        private static int counter = 0;

        public FaultyController()
        {
        }

        [HttpGet]
        public ActionResult Get()
        {
            if (++counter % 4 == 0)
            {
                return Ok(counter);
            }
            else if(counter % 4 == 1)
            {
                return StatusCode(501);
            }
            else if(counter % 4 == 2)
            {
                return StatusCode(502);
            }
            else
            {
                return StatusCode(503);
            }
        }
    }
}

And here is my Razor page that uses the Polly Wait and Retry policy.

@page "/"
@using Polly

<h1>Polly Test</h1>
<p>This demo uses a HttpClient to call a controller that is setup to fail 75% of the time (first three request will fail, fourth will succeed). The Polly Retry policy will kick in a retry up to three time.</p>

<p>Status: @status</p>
<p>Polly Summary : @pollyMessage</p>

<p>Response Code : @responseCode</p>
<p>Response Body : @number</p>

<button class="btn btn-primary" @onclick="CallRemoteServiceAsync">Call remote service</button>

@code {
   HttpClient httpClient = new HttpClient() {
        BaseAddress =  new Uri("http://localhost:5000")
    };

    private string status;
    private string pollyMessage;
    private string responseCode;
    private string number;

    private async Task CallRemoteServiceAsync()
    {
        IAsyncPolicy<HttpResponseMessage> _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
            r => !r.IsSuccessStatusCode)
            .WaitAndRetryAsync(3,
                retryAttempt => TimeSpan.FromSeconds(retryAttempt * 2), onRetry: (response, retryDelay, retryCount, context) => {
                    pollyMessage = $"Recieved: {response.Result.StatusCode}, retryCount: {retryCount}, delaying: {retryDelay.Seconds} seconds\n";
                    Console.WriteLine(pollyMessage);
                    InvokeAsync(StateHasChanged);
        });

        status = "Calling remote service...";
        string requestEndpoint = "faulty/";

        HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));
        
        responseCode = httpResponse.StatusCode.ToString();
        number = await httpResponse.Content.ReadAsStringAsync();
        status = "Finished";
        pollyMessage = "";
    }
}

As I said above, I’m going to write a few more posts on Polly and Blazor to show some other scenarios, like using the Polly Context to pass data around and dependency injection (hopefully).

Full source code available here.