Sunday, March 19, 2023

Attach ACR in a Different Subscription to an Existing AKS

In this post, let's see how we can attach an Azure Container Registry (ACR) to an existing Azure Kubernetes Cluster (AKS), but here the ACR is in a different subscription.

Using Azure CLI, the command to attach an ACR to an existing AKS is,
# Attach using acr-name
az aks update -n <aks-name> -g <resource-group-name> --attach-acr <acr-name>

# Attach using acr-resource-id
az aks update -n <aks-name> -g <resource-group-name> --attach-acr <acr-resource-id>
Since the ACR is in a different subscription, we can't attach using acr-name. Instead, we need to attach using the acr-resource-id.

While you can get the ResourceId from the URL after navigating to your ACR from the Azure Portal, the best approach is to get it from Azure CLI.
# Switch to subscription where ACR resides in
az account set --subscription <SubscriptionId>

# List resource information of the ACR
az resource list --name <acr-name>
And this will list something like below.
az resource list --name <acr-name>
And now you can run the attach command with Resource Id.
# Attach using acr-resource-id
az aks update -n <aks-name> -g <resource-group-name> --attach-acr <acr-resource-id>
Hope this helps.

Happy Coding.

Regards,
Jaliya

Thursday, March 16, 2023

Visual Studio 2022: Web API Endpoint Explorer

In this post, let's have a look at this nice feature that is available in Visual Studio 2022 and that is Web API Endpoint Explorer. I am on Visual Studio 2022 version 17.6.0 Preview 2.0 and I am not really sure when this was introduced, but if you have the latest Visual Studio 2022 Preview, you should be able to try this out.

This feature is wrapped inside a feature flag which you need to enable by going to Tools -> Options -> Environment -> Preview Features and selecting Web API Endpoint Explorer.
Enable Web API Endpoint Explorer
Now you can find this window in View -> Other Windows -> Endpoints Explorer. And you can find this only while you are in a compatible project (API Project).
Endpoints Explorer
I have clicked on Endpoints Explorer on a simple Minimal API project.
Endpoints Explorer
And look at that. My endpoints are displayed nicely. From the window, I can directly open an endpoint in the code editor and I can even generate a request (using .http Files, read more: Visual Studio 2022: Sending HTTP Requests with .http Files)

That's pretty neat, isn't it.

Hope this helps.

Happy Coding.

Regards,
Jaliya

Wednesday, March 8, 2023

Entity Framework Core and Connection Resiliency

In this post, let's see some built-in features in EF Core that supports Connection Resiliency. For example, if the connection to the database dropped while executing a command, we might need to retry the operation. While we can write the code to do it ourselves, EF Core out of the box supports retry using execution strategies.

The execution strategy can be configured in the following ways.

When configuring the options for your context:

public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { getset; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer(
                @"Server=(localdb)\mssqllocaldb;Database=EfCore8;Trusted_Connection=True",
                providerOptions =>
                {
                    providerOptions.EnableRetryOnFailure();
                }
            );
    }
}

In the Program.cs or Startup.cs for an ASP.NET Core application:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MyDbContext>(options =>
{
    options.UseSqlServer(
        @"Server=(localdb)\mssqllocaldb;Database=EfCore8;Trusted_Connection=True",
        providerOptions =>
        {
            providerOptions.EnableRetryOnFailure();
        });
});

or

public void ConfigureServices(IServiceCollection services)
{
    // some code

    services.AddDbContext<MyDbContext>(options =>
    {
        options.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EfCore8;Trusted_Connection=True",
            providerOptions =>
            {
                providerOptions.EnableRetryOnFailure();
            });
    });
}

If you wish to change the defaults of the execution strategy, you can do that by implementing the abstract class ExecutionStrategy.

using Microsoft.EntityFrameworkCore.Storage;

internal class CustomExecutionStrategy : ExecutionStrategy
{
    public CustomExecutionStrategy(ExecutionStrategyDependencies dependenciesint maxRetryCount, TimeSpan maxRetryDelay)         : base(dependencies, maxRetryCount, maxRetryDelay) { }

    protected override bool ShouldRetryOn(Exception exception)
    {
        // your custom logic here

        return true;
    }
}

And register the CustomExecutionStrategy.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EfCore8;Trusted_Connection=True",
            providerOptions =>
            {
                var maxRetryCount = 5;
                var maxRetryDelay = TimeSpan.FromSeconds(10);

                providerOptions.ExecutionStrategy(dependencies => new CustomExecutionStrategy(dependencies, maxRetryCount, maxRetryDelay));
            }
        );
}

You can even register your own execution strategy by implementing IExecutionStrategy something like below.

using Microsoft.EntityFrameworkCore.Storage;

internal class CustomExecutionStrategy : IExecutionStrategy
{
    private readonly ExecutionStrategyDependencies _dependencies;

    public CustomExecutionStrategy(ExecutionStrategyDependencies dependencies)
    {
        _dependencies = dependencies;
    }

    // interface implementation
}

Hope this helps.

Read More,
   Connection Resiliency

Happy Coding.

Regards,
Jaliya

Wednesday, February 22, 2023

System.Text.Json: Configure Polymorphism using the Contract Model

In this post let's see how we can configure Polymorphism using the Contract Model in System.Text.Json. You can also configure Polymorphism using attributes (How to configure Polymorphism using attributes), but there can be scenarios it isn't possible to use attributes. 

In that case, you can achieve Polymorphism using the Contract Model and this is only available with .NET 7 onwards.

Consider the following classes.
public class Person
{
    public string Name { getset; }
}

public class Student : Person
{
    public int StudentId { getset; }
}

public class Employee : Person
{
    public int EmployeeId { getset; }
}
Now instead of using attributes, I can update the JsonSerializerOptions, by calling the DefaultJsonTypeInfoResolver() constructor to obtain the JsonSerializerOptions.TypeInfoResolver and adding custom actions to its Modifiers property to configure Polymorphism.
var jsonSerializerOptions = new JsonSerializerOptions
{
    WriteIndented = true,
    PropertyNameCaseInsensitive = true,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers =
        {
            static jsonTypeInfo =>
            {
                if (jsonTypeInfo.Type != typeof(Person))
                {
                    return;
                }

                jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
                {
                    TypeDiscriminatorPropertyName = "type",
                    IgnoreUnrecognizedTypeDiscriminators = true,
                    UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
                    DerivedTypes =
                    {
                        new JsonDerivedType(typeof(Student), "Student"),
                        new JsonDerivedType(typeof(Employee), "Employee"),
                    }
                };
            }
        }
    }
};
And now I can above JsonSerializerOptions to Serialize/Deserialize as follows.
Person student = new Student
{
    Name = "John Doe",
    StudentId = 1
};

// Serializing
string jsonString = JsonSerializer.Serialize(student, jsonSerializerOptions);
Console.WriteLine(jsonString);
//{
//  "type": "Student",
//  "studentId": 1,
//  "name": "John Doe"
//}

// Deserializing
Person parsedPerson = JsonSerializer.Deserialize<Person>(jsonString, jsonSerializerOptions);
Console.WriteLine(parsedPerson is Student);  //true
Hope this helps.

Happy Coding.

Regards,
Jaliya

Thursday, February 16, 2023

System.Text.Json: Enforce Required Properties for Deserialization

I had a requirement where I want to enforce some property values to be present before deserializing the JSON string. And with .NET 7, you can do that pretty easily (another reason to move to .NET 7).

In this post, let's see how we can enforce the required properties for deserialization. There are three ways,

Failing to provide a required property will throw a JsonException.

Let's have a look.

By adding the required modifier

Consider the following POCO class. Here I have applied required modifier to FirstName and LastName.

public record Person
{
    public required string FirstName { getset; }

    public string? MiddleName { getset; }

    public required string LastName { getset; }
}

And let's try to deserialize the following string.

string @string = """
    {
        "FirstName": "John",
        "LastName": "Doe"
    }
    """
;

try
{
    Person? person = JsonSerializer.Deserialize<Person>(@string);
}
catch (JsonException jsonException)
{
    Console.WriteLine(jsonException.Message);
}

The above code is successfully deserializing the string into a person. Because the string has required properties set.

Now let's try the below. I am removing the LastName from JSON string.

string @string = """
    {
        "FirstName": "John"
    }
    """
;

try
{
    Person? person = JsonSerializer.Deserialize<Person>(@string);
}
catch (JsonException jsonException)
{
    Console.WriteLine(jsonException.Message);
    // JSON deserialization for type 'Person' was missing required properties, including the following: LastName
}

This will fail because our string doesn't contain the LastName property.

By annotating it with JsonRequiredAttribute

We can achieve the same result as above by using JsonRequiredAttribute. So instead of adding required modifier, we can decorate the property with JsonRequiredAttribute.

public record Person
{
    [JsonRequired]
    public string FirstName { getset; }

    public string? MiddleName { getset; }

    [JsonRequired]
    public string LastName { getset; }
}

By modifying the JsonPropertyInfo.IsRequired property of the contract model

This is kind of a more advanced approach.

string @string = """
    {
        "FirstName": "John"
    }
    """
;

var jsonSerializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers =
        {
            static typeInfo =>
            {
                if (typeInfo.Kind != JsonTypeInfoKind.Object)
                {
                    return;
                }

                foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
                {
                    propertyInfo.IsRequired = propertyInfo.Name switch
                    {
                        nameof(Person.FirstName) or nameof(Person.LastName) => true,
                        _ => false
                    };
                }
            }
        }
    }
};

try
{
   // This time we are passing the jsonSerializerOptions
    Person? person = JsonSerializer.Deserialize<Person>(@string, jsonSerializerOptions);
}
catch (JsonException jsonException)
{
    Console.WriteLine(jsonException.Message);
    // JSON deserialization for type 'Person' was missing required properties, including the following: LastName
}

The above will also throw a JsonException with a message saying Required properties aren't set.

Hope this helps. 

Happy Coding.

Regards,
Jaliya

Monday, February 6, 2023

Azure Cosmos DB for MongoDB: Backup and Restore Databases using MongoDB Command Line Database Tools

In this post let's see how we can backup and restore databases in an Azure Cosmos DB for MongoDB account using MongoDB Command Line Database Tools.

I am using Windows and the first step is to download MongoDB Command Line Database Tools. As of today, the version is 100.6.1 and I have downloaded the zip version. You can even download the msi and install the tools.

Backup

You can run the mongodump.exe from the command prompt providing the connection string of your Azure Cosmos DB for MongoDB account, the database you want to backup and an output path to write the backup files to.

mongodump.exe --uri "<connectionString>" --db <databaseName> --out <backupDirectory> 

mongodump.exe

Restore

You can run the mongorestore.exe from the command prompt providing the connection string of your Azure Cosmos DB for MongoDB account, a target database name, and the directory containing the backup files of the database.

mongorestore.exe --uri "<connectionString>" --db <databaseName> --dir <backupDirectory\databaseName>

mongorestore.exe
I am yet to confirm whether this approach is recommended, but so far I haven't faced any issues with the restored database. Collections and their documents count look great.

If you want to copy a database from one Azure Cosmos DB for MongoDB account to other, you can try this out. I have tried, Copy data to or from Azure Cosmos DB for MongoDB using Azure Data Factory or Synapse Analytics, but unfortunately, it didn't work out well due to some issues, hence tried MongoDB Command Line Database Tools.
   Issue: Copy Activity: Copying data from and to Azure Cosmos DB for MongoDB: Failing due to incorrect Data Type 
   Issue: Copy Activity: Copying data from and to Azure Cosmos DB for MongoDB: "The retrieved type of data JObject is not supported yet"

Hope this helps. 

Please don't forget to leave a comment on whether this approach worked for you or not.

Happy Coding.

Regards,
Jaliya

____________________________________________________________________________________________________________________________

Update on 2023/02/08:

I have received some recommendations from Product Group: Azure Cosmos DB.
  • Native MongoDB tools would be recommended for smaller workloads
  • Azure Data Factory (ADF) for medium (<1TB)
  • Spark if it’s a large dataset (>1 TB)

Thursday, February 2, 2023

Azure DevOps Pipelines: Install npm Packages from an External Private Package Registry

In this post let's see how we can Install npm Packages from an external private package registry in an Azure DevOps Pipeline.

The first step is adding a Service Connection for Connection Type: npm. You can do it by going into your Project Settings -> Service Connections and then New service connection and choosing npm.

New npm service connection
Click on Next.
New npm service connection
Here you can put the details, give the Service Connection a name and save it (note down the name as we are going to need it in a future step). In my case, I want to consume npm packages from Form.io private package repository and I have only the Username and the Password. So I have filled those up.

Next, we need to add/update the .npmrc file and specify the private package registry URL.
# Some other Azure Artifact Packages
registry=https://pkgs.dev.azure.com/{some-organization}/{some-project}/_packaging/{some-feed}/npm/registry/

# Form.io Premium Packages
@formio:registry=https://pkg.form.io/


always-auth=true
And now we can modify the DevOps pipeline to install the private packages.
trigger:
  branches:
    include:
      - main
      - feature/*
      - version/*

pool:
  vmImage: 'ubuntu-latest'

name: $(Build.SourceBranchName).$(Build.BuildId)

steps:
  - task: npmAuthenticate@0
    displayName: "Authenticate for FormIo Premium Packages"
    inputs:
      workingFile: .npmrc
      customEndpoint: FormIo-Packages # Important: Name of the npm Service Connection created

  - task: NodeTool@0
    displayName: 'Install Node.js'
    inputs:
      versionSpec: '16.x'
      checkLatest: true

  - task: Npm@1
    displayName: 'Install Formio Premium Packages'
    inputs:
      command: custom
      workingDir: $(RootPath)
      verbose: false
      customCommand: 'install @formio/premium --registry https://pkg.form.io --force'
Here the important step is using npmAuthenticate@0 task to provide npm credentials to the .npmrc file for the scope of the build. So it will get used when we are doing the npm install.

And that should do.

Hope this helps.

Happy Coding.

Regards,
Jaliya

Monday, January 30, 2023

C# 11.0: Newlines in String Interpolation Expressions

In this post let's have a look at another feature that is available with C# 11.0. And that is support for Newlines in String Interpolation Expressions.

Consider the following example code written in C# 10.0.
int age = 60;
string ageCategory = age switch
{
< 1 => "Infant",
< 12 => "Child",
< 17 => "Adolescent",
< 65 => "Adult",
_ => "Older adult"
};
string message = $"Based on the Age of {age}, you are a(n) {ageCategory}.";
Here it would have been nice if I can include the logic to determine the age category within the interpolated string. But Newlines inside a non-verbatim interpolated string are not supported in C# 10.0.

With C# 11.0, we now have the support for Newlines in String Interpolation Expressions. So I can simplify the code as follows.
int age = 60;
string message = $"Based on the Age of {age}, you are a(n) {age switch
{
< 1 => "Infant",
< 12 => "Child",
< 17 => "Adolescent",
< 65 => "Adult",
_ => "Older adult"
}}.";
Isn't it nice? There is no pleasure like having readable simplified code.

Read more of C# features here.
   What's new in C# 11

Happy Coding.

Regards,
Jaliya

Wednesday, January 25, 2023

Visual Studio 2022: Sending HTTP Requests with .http Files

Do you know Visual Studio has this nice feature to send HTTP Requests using .http files. It's actually pretty neat.

We just have to create a file with .http extension.
.http Files in Action
We can do all the methods and the output is displaying nicely.

Disclaimer: I am not sure when this feature got added, I am on Microsoft Visual Studio Enterprise 2022 (64-bit) - Version 17.5.0 Preview 4.0 and I don't have a specific extension installed in order to enable this functionality.

Hope this helps!

Happy Coding.

Regards,
Jaliya

Wednesday, January 18, 2023

Visual Studio 2022 Version 17.5 Preview 2: Text Visualizer Improvements

In this post let's explore some nice improvements that got added to Text Visualizer in Visual Studio. This got shipped with Visual Studio 2022 Version 17.5 Preview 2

I actually found this accidentally and it's so handy!

Say I have a string variable that holds a JWT token and I want to decode it for some debugging purpose. Usually what I would do is copy-pasting the token into https://jwt.io or https://jwt.ms or some external JWT decoding tool. What if we can see the decoded token without leaving Visual Studio? And that's exactly what the new Text Visualizer brings to the table.

Say I want to see the decoded token of the following.
Debugging a string
I need to click on the View button. And then I am presented with the following.
Text Visualizer
I can just select JWT Decode and just like that I can see the decoded token. 

Along that, you can see there are more options to manipulate the string such as Base64 Encode & DecodeUrl Encode & Decode etc.

Isn't that great? I just love this. Remember, if you want to try this out, you need to install the latest Visual Studio 2022 Preview.

Hope this helps.

Happy Coding.

Regards,
Jaliya