Monday, January 22, 2024

Monitoring Azure Durable Functions using Durable Functions Monitor

In this post let's have a look at a cool project that you might want to use if you are working on Azure Durable Functions. 

The project is DurableFunctionsMonitor, it provides a UI for monitoring, managing, and debugging orchestration instances in an Azure Durable Function App.
Durable Functions Monitor (DFM)
Durable Functions Monitor (DFM): Orchestration Sequence Diagram
I have been wanting to use this for several months now but only got to use this recently, and I like it.

This is basically an Azure Function App. The most important thing for Durable Functions Monitor (DFM) is, that it needs to know your Durable Function Apps' storage details, so it can pull the details and display them. So far I have only used it with Azure Storage, but it seems to support Netherite and Microsoft SQL Server.

 DFM can run in the following ways,
  • Injected mode: Install a NuGet package and expose the UI through your existing .NET Azure Functions project
  • Standalone: Since this is an Azure Function App, you can run it in the same ways as a typical Azure Function
    • Create a separate Azure Function App and install a NuGet package
    • Docker Container using the image scaletone/durablefunctionsmonitor
    • Deploy to your Kubernetes cluster
  • VS Code Extension
We can also customize things like Authentication for UI, its endpoints, etc.

Do give it a try:
   DurableFunctionsMonitor

Happy Coding.

Regards,
Jaliya

Wednesday, January 17, 2024

ASP.NET Core 8.0: Output Caching using Redis

With ASP.NET Core 8.0, now you can use Redis as your cache provider when cashing responses. The default is in-memory cache.

In this post, let's see how you can use Redis for output caching.

First, we need to install Microsoft.AspNetCore.OutputCaching.StackExchangeRedis NuGet package.

And then call AddStackExchangeRedisOutputCache to add Redis output caching services to the service collection.

// Add Redis output caching
builder.Services.AddStackExchangeRedisOutputCache(options =>
{
    options.Configuration =
        builder.Configuration.GetConnectionString("Redis");
});

And that's pretty much it.

The complete code looks like below.

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// Add Redis output caching services
builder.Services.AddStackExchangeRedisOutputCache(options =>
{
    options.Configuration =
        builder.Configuration.GetConnectionString("Redis");
});
// Add output caching services
builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder.Cache());
});

WebApplication app = builder.Build();

app.UseHttpsRedirection();

// Add output caching middleware to the request pipeline
app.UseOutputCache();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Mild", "Balmy", "Scorching"
};

app
    .MapGet("/weatherforecast", () =>
    {
        WeatherForecast[] forecast = Enumerable.Range(1, 5)
            .Select(index => new WeatherForecast
            (
                DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                Random.Shared.Next(-20, 55),
                summaries[Random.Shared.Next(summaries.Length)]
            ))
            .ToArray();
        return forecast;
    })
    .CacheOutput(); // enable output caching for this endpoint

app.Run();

internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

And you can see responses are getting cached.

Redis
More read:
   Output caching middleware in ASP.NET Core

Hope this helps.

Happy Coding.

Regards,
Jaliya

Sunday, January 14, 2024

HttpClient: Dynamically Add HttpMessageHandlers

In this post, let's have a look at how we can create a HttpClient with HttpMessageHandlers that gets created at run time.

I was hoping IHttpClientFactory would support that, but at least I couldn't find a way to get IHttpClientFactory to work with dynamic HttpMessageHandlers.

But luckily we have HttpClientFactory static class and there we have HttpClientFactory.Create(HttpMessageHandler, DelegatingHandler[])

The basic logic is we are supplying the innermost handler and other handlers, and internally it would get wired as a pipeline, something like below.

public static HttpMessageHandler CreatePipeline(HttpMessageHandler innerHandler, IEnumerable<DelegatingHandler> handlers)
{
HttpMessageHandler httpMessageHandler = innerHandler;
    foreach (DelegatingHandler item in handlers.Reverse())
    {
        item.InnerHandler = httpMessageHandler;
        httpMessageHandler = item;
    }

return httpMessageHandler;
}

And then it would create a HttpClient with the chained HttpMessageHandler as follows.

new HttpClient(CreatePipeline(innerHandler, handlers));

Hope this helps.

Happy Coding.

Regards,
Jaliya

Thursday, January 4, 2024

Reading Configuration using Different Options Patterns in ASP.NET Core

A few days ago I saw an interesting question where someone was asking what's the preferred way to read some configuration, something like below.
{
  "SomeSetting": {
    "Config""Value"
  }
}
Would you use, 

1. IConfiguration
app.MapGet("/config", (IConfiguration configuration) =>
{
    return configuration.GetValue<string>("SomeSetting:Config");
});
2. Options Pattern
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("SomeSetting"));

app.MapGet("/config", (IOptions<MyOptions> optionsAccessor) =>
{
    return optionsAccessor.Value.Config;
});

public record MyOptions
{
    public string Config { get; set; }
}
And that kind of prompted me to write this post.

As we all know, the more magic strings we maintain, the more trouble we ask for. But personally, if it's something that's hardly going to change, but still warrants being maintained as a configuration and does not use more than a couple of magic strings, I'd go for IConfiguration.

Saying that there are a lot of benefits to using Options Pattern. It uses strongly typed access and reduces the use of magic strings. We can also do Options Validation using Data Annotations, and we can even ask for early validation so that at the application start, we will know if something is missing or incorrectly configured rather than knowing it later when the app is. 

On top of those, there are different Options Interfaces that can be really handy.

  • It's a Singleton and CAN be injected into any service lifetime.
  • Supports Named Options.
  • Does not support reloadable changes. For new configuration values to be reflected, the app DOES need to be restarted.
  • Usage:
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("SomeSetting"));
..

app.MapGet("/config", (IOptions<MyOptions> optionsAccessor) =>
{
    return optionsAccessor.Value.Config;
});
  • It's Scoped and CAN NOT be injected into a Singleton service.
  • Supports Named Options.
  • Supports reloadable changes. For new configuration values to be reflected, the app DOES NOT need to be restarted. It's recomputed on every request and cached for the lifetime of the request.
  • Usage:
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("SomeSetting"));
..

app.MapGet("/config", (IOptionsSnapshot<MyOptions> snapshotOptionsAccessor) =>
{
    return snapshotOptionsAccessor.Value.Config;
});
  • It's a Singleton and CAN be injected into any service lifetime.
  • Supports Named Options.
  • Supports reloadable changes. For new configuration values to be reflected, the app DOES NOT need to be restarted. It's recomputed on every request and cached for the lifetime of the request.
  • Supports change notifications. That is if we want we can register a listener to be called whenever a named TOptions changes.
  • Usage:
builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("SomeSetting"));
...

app.MapGet("/config", (IOptionsMonitor<MyOptions> optionsDelegate) =>
{
    return optionsDelegate.CurrentValue.Config;
});
Hope this helps.

Happy Coding.

Regards,
Jaliya