Wednesday, August 24, 2022

Connecting to Azure Cosmos DB API for MongoDB using Azure Data Studio

Did you know that we can connect to an Azure Cosmos DB API for MongoDB using Azure Data Studio. There is an extension: Azure Cosmos DB API for MongoDB for Azure Data Studio, it's still in it's preview stage, but works great.

This extension in Azure Data Studio includes features such as,

  • Connection manager & query editor
  • Provisioning and scaling containers
  • Integrated terminal

Let's have a look at how easy it is to use this extension.

First, you need to download and install Azure Data Studio (if you haven't already). Then search for mongo under extensions. 
Install Azure Cosmos DB API for MongoDB extension
Select Azure Cosmos DB API for MongoDB, install it and then reload/restart the Azure Data Studio. Once that's done, click on New Connection and select Mongo account as the Connection Type.
Connect to MongoDB account
Now copy and paste the Connection string of your Azure Cosmos DB API for MongoDB account and click on Connect. Once you are connected. you will see all your databases.
Connected to Azure Cosmos DB API for MongoDB account
You can right-click on the connected account and select Manage to see more options. 
Manage Mongo account
Here I am opening an existing database and going to Open Mongo Shell to run a simple query on that database.
Executing queries on Mongo Shell
Do try it out, you are going to love it.

Happy Coding.

Regards,
Jaliya

Tuesday, August 16, 2022

Transitive Dependencies in Visual Studio 2022

Visual Studio 2022 17.3 and the latest preview of Visual Studio 2022 which is Visual Studio 2022 Version 17.4 Preview 1 were released last week.

I am seeing this fantastic feature in the latest preview, I can now see all the Transitive Dependencies of the installed packages from the NuGet Package Manager.
Transitive Dependencies in Visual Studio
This is very helpful in understanding the dependency tree of the packages. When I hovered over a Transitive Dependency, I can see which Top-level package brought that in.
Transitive Dependency in Visual Studio
And say one of the Transitive Dependencies has a vulnerability, and if we have an updated version of that, we can install it and promote it to a Top-level dependency.

According to the NuGet team, this feature was released as an experimental feature in Visual Studio 2022 17.3 and if you’re a part of the Visual Studio experiment group, you’ll be able to see your transitive dependencies whenever you’re managing your NuGet packages in Visual Studio. I am surprised I haven't seen this in a previous preview build, only started seeing this in Visual Studio 2022 Version 17.4 Preview 1. Can't check whether it's there in Visual Studio 2022 17.3, I am only using the latest preview always. Maybe this feature is available on Visual Studio 2022 Version 17.4 Preview 1 or I am part of the Visual Studio experiment group 😍.

Anyway, try to be on the latest Visual Studio Preview, you are going to love it.

Happy Coding.

Regards,
Jaliya

Monday, August 15, 2022

EF Core: OnDelete DeleteBehavior ClientSetNull Vs. SetNull in an Optional Relationship

In this post, let's have a look at the difference between DeleteBehavior.ClientSetNull and DeleteBehavior.SetNull when configuring OnDelete action in an Optional EF Core Relationship.  I am finding this important because sometimes it can confuse people including myself. 

Note: this post considers Microsoft SQL Server as the database provider.

So what's an Optional Relationship? Let's consider the following example.

public class Category
{
    public int Id { getset; }
 
    public string Name { getset; }
 
    public List<ToDo> ToDos { getset; }
}
 
public class ToDo
{
    public int Id { getset; }
 
    public string Title { getset; }
 
    public int? CategoryId { getset; }
 
    public Category Category { getset; }
}

Here I have a simple ToDo context, I have ToDos and a ToDo can optionally have a Category. And for a given Category, I can find all ToDos under that particular Category. Now our scenario is, what needs to happen if someone Deletes a Category? Here Category entity is the Principal/Parent and ToDo entity is the Dependent/Child.

We can configure the OnDelete behavior on Principal/Parent as follows.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Category>()
        .HasMany(x => x.ToDos)
        .WithOne(x => x.Category)
        .HasForeignKey(x => x.CategoryId)
        .OnDelete(/* DeleteBehavior */);
}

Here since the Relationship is optional, we have the option not to delete Dependents/Children while deleting a Principal/Parent or on severing the relationship from the Principal/Parent (we can severe the relationship by clearing out all the Dependents/Children from the Principal/Parent or by setting the Principal/Parent navigation property to null in each Dependent/Child).

The Default OnDelete behavior for Optional Relationships is DeleteBehavior.ClientSetNull.

First, let's see how the Dependent/Child table is created when we configure the OnDelete behavior with DeleteBehavior.ClientSetNull and DeleteBehavior.SetNull

DeleteBehavior.ClientSetNull

CREATE TABLE [ToDos] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [CategoryId] int NULL,
    CONSTRAINT [PK_ToDos] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_ToDos_Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [Categories] ([Id])
);

DeleteBehavior.SetNull

CREATE TABLE [ToDos] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [CategoryId] int NULL,
    CONSTRAINT [PK_ToDos] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_ToDos_Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [Categories] ([Id]) ON DELETE SET NULL
);

Here you can see, that there is an important difference when DeleteBehavior.SetNull is used, that is from the database side ON DELETE behavior is configured.

Now let's attempt to delete the Principal/Parent, in this context, it's a Category.

Category category = await context.Categories
    .FirstOrDefaultAsync();

context.Categories.Remove(category);
await context.SaveChangesAsync();

The query being generated is as follows.

--Executed DbCommand (6ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;

DELETE FROM [Categories]
OUTPUT 1
WHERE [Id] = @p0;

When DeleteBehavior.ClientSetNull:

Here we are going to get the SqlException which makes perfect sense. If you have a look at how the Dependent/Child table got created above. when DeleteBehavior.ClientSetNull, from the database side, there was no ON DELETE behavior configured on the Foreign Key. So from the database side, it's not happy, because there are Dependents/Children associated with the Principal/Parent getting deleted and the database doesn't know what to do with them.

When DeleteBehavior.SetNull:

Here, the Delete operation will proceed without any errors, because the Foreign Key in Dependent/Child table is configured with ON DELETE SET NULL and the database will take care of the associated Dependents/Children by setting the FK to null.

Now in order to have a successful Delete on Principal/Parent when DeleteBehavior.ClientSetNull, we need to explicitly load the Dependents/Children to the DbContext. 

Category category = await context.Categories
    .Include(x => x.ToDos)
    .FirstOrDefaultAsync();

context.Categories.Remove(category);
await context.SaveChangesAsync();

Now this will cause EF Core to issue the following query when deleting the Principal/Parent.

--Executed DbCommand (4ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32), @p2='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;

UPDATE [ToDos] SET [CategoryId] = @p0
OUTPUT 1
WHERE [Id] = @p1;

DELETE FROM [Categories]
OUTPUT 1
WHERE [Id] = @p2;

Now EF Core will first UPDATE Dependents/Children setting the Foreign Key to NULL and then DELETE the Principal/Parent. So now, the Delete operation will succeed.

Hope this helps.

More read:
   Cascade Delete

Happy Coding.

Regards,
Jaliya

Saturday, August 13, 2022

ASP.NET Core: Rate Limiting with .NET 7 Preview 6

With the upcoming .NET 7, there's a new NuGet package System.Threading.RateLimiting coming to manage the Rate Limiting. We can use rate limiting to protect a resource from getting overwhelmed. There is a very detailed post Announcing Rate Limiting for .NET that you definitely should read.

In this post, let's see how can we use Rate Limiting quite easily with an ASP.NET Core Application. You need to install Microsoft.AspNetCore.RateLimiting NuGet package that provides ASP.NET Core middleware for enforcing rate limiting in an application using System.Threading.RateLimiting.

Once that's installed, we need to start by defining RateLimiterOptions.
RateLimiterOptions rateLimiterOptions = new();
Here you can set up variety of things such as defining a GlobalLimiter, adding individual rate limiters and customizing the behavior when a request is rejected from a Rate Limiter.

Now let's start by adding ConcurrencyLimiter, one of the inbuilt rate limiters.
rateLimiterOptions.AddConcurrencyLimiter(policyName: "ConcurrencyLimit",
    new ConcurrencyLimiterOptions(permitLimit: 5,
        queueProcessingOrder: QueueProcessingOrder.OldestFirst,
        queueLimit: 3)); 
Next, we need to enable Rate Limiting middleware and use the RateLimiterOptions we just created.
app.UseRateLimiter(rateLimiterOptions);
Next, we can use rate limiters we have configured in our endpoints, something like below.
app.MapGet("/ToDos", () =>
{
    return TypedResults.Ok();
 
})
.RequireRateLimiting("ConcurrencyLimit");
Here note:  the global limiter will be executed first, followed by the endpoint-specific limiter, if one exists.

Now let's try to hit the rate limit on the above endpoint by making parallel requests (a lazy way of course).
HttpClient _httpClient = new HttpClient
{
    BaseAddress = new Uri("https://localhost:44378"),
};
 
List<Task<HttpResponseMessage>> tasks = new List<Task<HttpResponseMessage>>();
 
for (int i = 0; i < 10; i++)
{
    Task<HttpResponseMessage> task = _httpClient.GetAsync("/Todos");
    tasks.Add(task);
}
 
var results = new List<HttpResponseMessage>(await Task.WhenAll(tasks));
 
foreach (HttpResponseMessage item in results)
{
    Console.WriteLine(item.StatusCode);
}
And I can see an output like below.
ServiceUnavailable
If I want to change the Response Code when the Rate limit is hit (default is 503: ServiceUnavailable), I can do something like the below.
rateLimiterOptions.RejectionStatusCode = (int)HttpStatusCode.TooManyRequests;
TooManyRequests
Hope this helps.

Most importantly, a must-read.
Happy Coding.

Regards,
Jaliya