Wednesday, October 14, 2020

C# 9.0: Records

C# 9.0 is almost around the corner, we are just less than a month away from .NET Conf 2020, where C# 9.0 along with .NET 5.0 and Visual Studio 16.8.0 will be officially released. 

One of the biggest features coming with C# 9.0 is Records. I think it's high time we have a look at what Records are.

You can try out this feature even now with the latest Preview of Visual Studio 2019 (Version 16.8.0 Preview 4 as of today) and .NET 5.0 RC (SDK 5.0.100-rc.2 as of today).

In this post, let's have an overview of what Records are. But before diving in, let's consider the following example using C# 8.

Consider, you have a Person class with just 2 properties, FirstName and LastName.

var person = new Person("John""Doe");

So to be able to do this, I need to create a Person class with 2 properties and then set values to them through the constructor, something like below.

public class Person
{
    public string FirstName { getset; }
    public string LastName { getset; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}

Next, say, I am creating another Person with the same FirstName, LastName.

var otherPerson = new Person("John""Joe");

There are often times, I need to compare whether it's the same person. I don't care about the references, I am only concerned about its values. Basically something like this,

bool isTheSamePerson = person == otherPerson;

And for us to be able to something like this, we need to modify Person class to implement IEquatable<T> and override operators.

public class Person : IEquatable<Person>
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public bool Equals(Person other) => other is object && FirstName == other.FirstName && LastName == other.LastName;

    public static bool operator ==(Person left, Person right) => left is object ? left.Equals(right) : left is null;

    public static bool operator !=(Person left, Person right) => !(left == right);

    public override bool Equals(object obj) => Equals(obj as Person);

    public override int GetHashCode() => HashCode.Combine(FirstName, LastName);
}

Now say, you want to deconstruct the Person (part of C# 7.0), that's something like this,

(string firstName, string lastName) = person;

To be able to do this, you need to add a Deconstruct method to Person class.

public void Deconstruct(out string firstName, out string lastName)
{
    firstName = FirstName;
    lastName = LastName;
}

And finally, say we want to override Person.ToString() to return $"{FirstName} {LastName}". Yes, that means another method.

public override string ToString() => $"{FirstName} {LastName}";

Suddenly you can see our small class has grown and these functionalities are pretty much we are going need in most of the cases. So our C# 8.0 class is going to look like below with all the above functionality.

public class Person : IEquatable<Person>
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public void Deconstruct(out string firstName, out string lastName)
    {
        firstName = FirstName;
        lastName = LastName;
    }

    public bool Equals(Person other) => other is object && FirstName == other.FirstName && LastName == other.LastName;

    public static bool operator ==(Person left, Person right) => left is object ? left.Equals(right) : left is null;

    public static bool operator !=(Person left, Person right) => !(left == right);

    public override bool Equals(object obj) => Equals(obj as Person);

    public override int GetHashCode() => HashCode.Combine(FirstName, LastName);

    public override string ToString() => $"{FirstName} {LastName}";
}

What if we can simplify all this code. Enter Records.

Records

With C# 9.0, you can have all the above functionality available by default by creating a Record of Person instead of a Class of Person.

public record Person(string FirstName, string LastName);

You should see something strange here, we can specify parameters at the record definition level. This form is called positional records. You can still use the traditional syntax, which is defining separate properties and a constructor, etc.

So basically, I can do something like this and I will get a below output.

using System;

var person = new Person("John""Doe");
var otherPerson = new Person("John""Doe");

// Value Comparision
Console.WriteLine($"Value Comparison: {person == otherPerson}");

// Reference Comparision
Console.WriteLine($"Reference Comparison: {ReferenceEquals(personotherPerson)}");

// Deconstruction
(string firstNamestring lastName) = person;
Console.WriteLine($"Deconstuct: {firstName} {lastName}");

// ToString()
Console.WriteLine($"ToString(): {person}");

public record Person(string FirstNamestring LastName);

Output:

Value Comparison: True
Reference Comparison: False
Deconstuct: John Doe
ToString(): Person { FirstName = John, LastName = Doe }

So what is this new type, Record? 

Records are reference types and are immutable by default. There is a nice read here What's new in C# 9.0: Record types, I highly recommend you to read that for a more detailed explanation of records and its internal implementation.

Another nice thing with Records is, records support with-expressions. It's something like this,

var someOtherPerson = person with { FirstName = "Jane" };

So this will create a new object someOtherPerson, and all the properties of person will be shallow copied, but the specified properties will be changed.  I can verify that by printing someOtherPerson,

Console.WriteLine(someOtherPerson);
// Person { FirstName = Jane, LastName = Doe }

If you try to set values to FirstName/LastName properties without using the object initializer, we can see something interesting here.

init accessor
Here we can see a new accessor called init. It's another feature coming with C# 9.0. Properties that have init accessor can be set only in the object initializer or in the instance constructor. So when a record is defined using positional record syntax, all its arguments will have init accessor.

Let's modify the person record a bit by adding another property.

public record Person(string FirstNamestring LastName)
{
    public int Age { getset; }
}

So if we try to set property values,

someOtherPerson.LastName = "Smith"// this is NOT ALLOWED, because it has init accessor
someOtherPerson.Age = 20; // this is allowed

Hope that's enough to get you started on exploring more on records.

If you haven't saved the date of .NET Conf 2020, just spend like a minute and do save the date right now.

Happy Coding.

Regards,
Jaliya

Thursday, October 1, 2020

Azure Functions: Consuming Configuration Data from Azure App Configuration and Azure Key Vault

Azure App Configuration is a managed service to centrally manage application and feature settings. One of the nicest things about AAC is, it can consume secrets from AKV. In this post, let's see how we can consume Configuration Data from Azure App Configuration (AAC) and Azure Key Vault (AKV).

Before starting off, I am assuming that you have an understanding of how to set up AAC and AKV (here is a post I wrote a couple of months back about creating AAC: ASP.NET Core Application Reading Configuration from Azure App Configuration). And I am assuming you know how to set up dependency injection using FunctionsStartup in an Azure Function App (If you want to refresh your memories, may be this can help Dependency Injection in Azure Functions).

So consider that we have an AAC configured with AKV secrets (Here I have only 1 AKV Reference).

Azure App Configuration with AKV References
So consider I have an Azure Function App with DI setup.

Like 10 days back, Microsoft.Azure.Functions.Extensions version: 1.1.0 was released and with that, one of the new features that got available is Configuration source customization. Basically, that is, in the Startup class, now you can override the ConfigureAppConfiguration.

public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
    FunctionsHostBuilderContext context = builder.GetContext();

    builder.ConfigurationBuilder
        .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
        .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
        .AddEnvironmentVariables();

    var aacEndpoint = Environment.GetEnvironmentVariable("AzureAppConfiguration_BaseUrl");
    if (!string.IsNullOrEmpty(aacEndpoint))
    {
        builder.ConfigurationBuilder
            .AddAzureAppConfiguration(options =>
            {
                var tokenCredential = new Azure.Identity.DefaultAzureCredential();
                options
                    .Connect(new Uri(aacEndpoint), tokenCredential)
                    .Select(KeyFilter.Any, LabelFilter.Null)
                    .Select(KeyFilter.Any, Environment.GetEnvironmentVariable("AzureAppConfiguration_Label"))
                    .ConfigureKeyVault(kv =>
                    {
                        kv.SetCredential(tokenCredential);
                    });
            });
    }
}

So in the above the code example, I have added appsettings.json, appsettings.{environment}.json as configuration sources (yes, you can do that). And if I have an AAC endpoint (something like https://something.azconfig.io), I have added AAC as a configuration source. You can notice that, instead of using AAC connection string, I have used the Connect overload that uses AAC endpoint Uri and TokenCredential. For TokenCredential, I have used DefaultAzureCredentialDefaultAzureCredential provides a default TokenCredential authentication flow for applications that will be deployed to Azure and it will be trying different credential types on a specific order (please go through the above link to find about the order).

Now let's have a look at how things are going to work on Local Development Environment using Visual Studio and when deployed to Azure (I am only covering running in Azure scenario here in this post).

Local Development Environment using Visual Studio

So in the local development environment using Visual Studio, for you to consume AAC configured with an AKV, you need to do the following steps.

  • Make sure, you have the latest Azure CLI installed
  • Correct account is set from Visual Studio: Tools -> Options -> Azure Service Authentication
    • This account needs to be given App Configuration Data Reader role in AAC (through Access control (IAM) in AAC)
    • In AKV, an access policy is defined for this Account
Tools -> Options -> Azure Service Authentication
AAC - IAM - App Configuration Data Reader role
AKV - Access Policies
Note: In AKV, here in my case, I have all the permissions. You might need to give only Get like I have given for Manage Identities above me.
  • For the Azure CLI logged in account, if you have access to multiple subscriptions in your tenant or in different tenants, make sure the subscription where your AAC lives, is selected as the default subscription.
// show the default subscription
az account show 

// list all the subscriptions
az account list;

//set default subscription
az account set --subscription [subscription-id]

With the above steps, you should be able to consume AAC with AKV when your Function App is running locally in Visual Studio. 

Note: It's better not to consume AAC when running locally, usually what I do is wrap adding AAC configuration in a #if condition or environment check condition and use AAC only in production. For the local development environment, we can have the configuration inside appsettings.Development.json or something like that.

Deployed to Azure

When the Azure Function app is deployed to Azure, you can use either System Assigned Managed Identity or User Assigned Managed Identity

System Assigned Managed Identity

For System Assigned Managed Identity, you can have a look at this post Consume Secrets in an Azure Key Vault from an Azure Function App on how you can setup System Assigned Managed Identity in Azure Function App. Then in addition to those steps in that post, you need to give your Managed Identity, App Configuration Data Reader role in your AAC (like we did for Visual Studio Account).

User Assigned Managed Identity

For User Assigned Managed Identity, you need to create an User Assigned Managed Identity in Azure which is another managed service.

Create User Assigned Managed Identity
Then inside your Function App, you need to assign that managed identity to the function app. You can do this by, going to Identity -> User Assigned -> Add.


Then again like previous scenarios, you need to give that identity App Configuration Data Reader role in your AAC and define an access policy in AKV.

And in the Configuration add an app setting, AZURE_CLIENT_ID with the value of ClientId in the created Managed Identity.

So that's it.

Hope this helps.

Happy Coding.

Regards,
Jaliya

Wednesday, September 30, 2020

RetryOptions in Azure Durable Functions

In this post, let's see how we can handle Retries on Activity Functions or Orchestration Functions in the Durable Functions Framework.

When you are calling an Activity Functions or another Orchestration Function from IDurableOrchestrationContext, there 2 methods to use CallActivityWithRetryAsync and CallSubOrchestratorWithRetryAsync which you can use that accepts a parameter of type RetryOptions.

So basically when you are calling an Activity Function or another Orchestration Function you can do something like below.

var retryOptions = new RetryOptions(TimeSpan.FromSeconds(10), 3)
{
    Handle = exception => exception.InnerException is MyException myException
};
var someReturn = await context.CallActivityWithRetryAsync<SomeReturn>("MyActivity", retryOptions, someInput);

So here, if MyActvity throws an exception of type MyException, we will be retrying again in 10 seconds and maxNumberOfAttempts will be 3. One of the important things to note for the Handle delegate is, you need access exceptions' InnerException if you want to get the actual exception. The exception would always be FunctionFailedException.

There is another interesting property that you can use in RetryOptions which is BackoffCoefficientBackoffCoefficient lets you increment the waiting time in subsequent retries. Default is 1, for an example if you do something like below,

var retryOptions = new RetryOptions(TimeSpan.FromSeconds(10), 3)
{
    BackoffCoefficient = 2,
    Handle = exception => exception.InnerException is MyException myException
};
var someReturnValue= await context.CallActivityWithRetryAsync<SomeReturn>("MyActivity", retryOptions, someInput);

The first retry will be in 10 seconds, the second retry will be in 20 seconds (after the first retry fail) and the final retry will be in 30 seconds (after the second retry fail). 

These are the different options available in RetryOptions that you can use to get the best retry experience.

  • BackoffCoefficient: Gets or sets the backoff coefficient.
  • FirstRetryInterval: Gets or sets the first retry interval.
  • Handle: Gets or sets a delegate to call on an exception to determine if retries should proceed.
  • MaxNumberOfAttempts: Gets or sets the max number of attempts.
  • MaxRetryInterval: Gets or sets the max retry interval.
  • RetryTimeout: Gets or sets the timeout for retries.

So hope this helps.

Happy Coding.

Regards,
Jaliya

Wednesday, September 23, 2020

Azure Durable Functions for Monitoring

In this post, let's see how Azure Durable Functions can be used to Monitor a long-running task. It's actually pretty easy. But there are some important things to Note.

Consider the below code. This is a basic implementation of such a monitoring functionality using an Orchestration Function. Here basically we are triggering an Activity function that will invoke a long-running task (here it is returning the taskId so we can poll for status using that). And then we are polling every 15 seconds for 60 seconds by triggering another Activity Function. If we are able to get a successful result within that time frame, we are returning that, else we throw a TimeoutException or you can do whatever you want.

[FunctionName("MonitorTask")]
public static async Task<TaskResult> Run([OrchestrationTriggerIDurableOrchestrationContext context)
{
    TaskInput taskInput = context.GetInput<TaskInput>();

    ProcessingResult processingResult = await context.CallActivityAsync<ProcessingResult>("InvokeLongRunningTask", taskInput);

    var pollingIntervalInSeconds = 15;
    DateTime expiryTime = context.CurrentUtcDateTime.AddSeconds(60);

    while (context.CurrentUtcDateTime < expiryTime)
    {
        TaskResult taskResult = await context.CallActivityAsync<TaskResult>("GetTaskResult", processingResult.TaskId);

        if (taskResult.Status == "Success")
        {
            return taskResult;
        }

        // Orchestration sleeps until this time.
        DateTime nextCheck = context.CurrentUtcDateTime.AddSeconds(pollingIntervalInSeconds);
        await context.CreateTimer(nextCheck, CancellationToken.None);
    }

    throw new TimeoutException("Timeout Occurred");
}

The most important thing here is, we are getting CurrentUtcDateTime from the IDurableOrchestrationContext. The reason for that is, Durable Functions should be deterministic. It should be deterministic because Durable Functions use Event Sourcing pattern to determine it's current state (and that is rather than keeping the current state, it tracks how/what events made the function to get into the current state). If we use DateTime.UtcDateTime, for every time it replays the message, the DateTime will be different and will end up with a infinite wait. CurrentUtcDateTime will be the same for every replay of this specific instance.

So hope this helps!

Happy Coding.

Regards,
Jaliya

Thursday, September 3, 2020

Consume Secrets in an Azure Key Vault from an Azure Function App

In a development environment, you most likely will be using plain text values in App Settings, but in higher environments, you might not have the luxury to do that. Instead, you might have to read secrets from an Azure Key Vault. In this post, let's see how we can consume a secret in an Azure Key Vault from an Azure Function App. It's actually pretty easy. I am assuming you already have an Azure Function App and an Azure Key Vault created.

First, go to your Function App, click on the Identity tab, and then turn it on.

Identity On

Then, go to your Azure Key Vault where you have your secrets, Click on Access Policies.

Access Policies

And from there click on + Add Access Policy. So here since I am only giving access to read Secrets, I am selecting only Get from Secret permissions multi select dropdown. And then click on Select principal and search for your function application name, select and Add. 

Add access policy

Now from the Key Vault, go to the secret where you want to expose and copy it's Secret Identifier.

Secret Identifier

Now go back to the Function App configuration settings, set the value for your key like below.

@Microsoft.KeyVault(SecretUri=https://copied-secret-identifier)

And you can see it's getting resolved.

Add/Edit application setting

So that's it and no code changes required.

Happy Coding.

Regards,
Jaliya