Current Limitations of Entity Framework Core

Introduction

Although EF Core seems to be the most popular ORM in the .NET world in these days – and I for sure won’t contradict it –, there are still some functionality missing, specially if we compare it with other ORMs that also exist, NHibernate coming obviously to my mind. This post is a reflection about that, it is in no way a comparison with other ORMs, in particular, NHibernate, it’s more a wish list for EF Core. I still follow and love NHibernate, and it’s still, in many ways, way ahead of EF Core, but that’s not what I’ll be writing about.

Primary Key Generation

EF Core currently only supports the following primary key generation strategies:

  • Identity/autoincrement (on databases that support it)
  • GUID/uniqueidentifier (on databases that support it)
  • Sequence-based (on databases that support it)
  • HiLo (SQL Server only)
  • Manually assigned

For GUIDs, EF Core automatically generates, on the client-side, a new value before inserting, which is nice.

HiLo is a great pattern for generating primary keys, but, unfortunately, the way Microsoft implemented it, resorting to database sequences, makes it database-specific – currently, SQL Server only. If it were implemented with just standard DML commands, it could be made database-agnostic, for the benefit of all.

I dare say that EF Core is slightly biased towards SQL Server and, even more, that most SQL Server folks are used to having IDENTITY as their default primary key generation strategy. While this is fine, it does prevent batch insertions, because it requires obtaining the generated primary key after each inser (SELECT SCOPE_IDENTITY()). If we have a client-generated primary key, batch insertion is possible, which can be a great benefit.

I’d like to have a truly extensible primary key generation mechanism on EF Core. Maybe something for the future.

Collection Types

Currently, EF Core only supports one type of collection. It can be lazy loaded, in which case, you need to declare it as ICollection<T> or IList<T>, or not, but that is it. You can’t have collections of primitive types without using a value converter. Plus, you don’t have semantic collections such as sets or bags, or indexed collections such as lists or maps.

Table Inheritance Patterns

There are three canonical table inheritance patterns:

Currently, TPH and TPT are already supported, but TPC is not. There are plans to introduce it in the future (https://github.com/dotnet/efcore/issues/3170)

Expression Columns

Currently there’s no way to map a column to a SQL expression, which could be very handly. True, we can have a whole entity coming as the result of a view, or a raw SQL, but this is a different thing. Of course, that property would not be persisted.

Expressions for CUD Operations

Another useful operation, the ability to use raw SQL – which could even be a stored procedure call – for Create, Update, and Delete (CUD) operations. This is also currently scheduled by the team for a future release (https://github.com/dotnet/efcore/issues/245).

Strongly Typed DML Operations

One thing that would be nice and already exists on other ORMs is the ability to batch perform DML operations from LINQ queries, for example, UPDATEs and DELETEs. Take this hypothetical strongly typed delete on top of a LINQ query, for example:

var deletedPosts = ctx.Posts.Where(p => p.Timestamp.Date < DateTime.Today.AddDays(-365)).Delete();

Much better than writing SQL as hardcoded strings, don’t you think? Yes, I do know that there are third-party extensions out there that already do this, but it would be nice to have this built-in. It’s being tracked for future implementation (https://github.com/dotnet/efcore/issues/795).

Lifecycle Events

Some lifecycle events – such as EF 6’s ObjectMaterialized and SavingChanges – are conspicuously missing. This can be useful, for example, to do something on an entity after it is loaded (hydrated) from the database. Fortunately, there are plans to introduce them (https://github.com/dotnet/efcore/issues/15911).

Conclusion

As a I said, these are just some thoughts on nice-haves for EF Core. Some of them are already on the EF Core team’s list, and some are not. There are many more, see the whole plan for v7.0 here and do submit your own suggestions here. As usual, I’d love to hear your thoughts on this, so let’s have them!

Changing Schema Dynamically in EF Core

Sometimes it may be necessary to change the schema for some entities based upon some criteria. This may be because of multitenancy or because you want to test something and don’t want to pollute the main schema. Here is a possible solution, going directly to the annotations that EF Core uses.

protected override void OnModelCreating(ModelBuilder modelBuilder) {

    base.OnModelCreating(modelBuilder);

//apply any IEntityTypeConfiguration<TEntity> configuration from this assembly

    modelBuilder.ApplyConfigurationsFromAssembly(typeof(DatabaseContext).Assembly);

    var model = modelBuilder.Model;

//possibly filter entities by some criteria?

    foreach (var entity in model.GetEntityTypes())

    {

        entity.RemoveAnnotation(“Relational:Schema”);

        entity.AddAnnotation(“Relational:Schema”, “FooBar”);

    } }

You need to override the OnModelCreating method, which is called by the infractructure when the model is being built by EF Core, and you let it do its job, and you then iterate through the found entities to add an annotation for “Relational:Schema”. And that’s it.

Posting AJAX Requests to ASP.NET Core MVC

Introduction

In the past, I’ve had trouble doing something that is apparently simple: invoking a simple action method in a controller using AJAX. Although it is indeed simple, when using jQuery, it may require some attention, hence this post.

In this example I will show how to do something simple: how to invoke an action that just adds two integers and returns the result using jQuery AJAX. This can be extended to any other kind of data, mind you, it is not tied to simple data types.

Prerequisites

We will be using .NET Core (or .NET 5/6, doesn’t really matter for the purpose of this sample) and jQuery 3.x, although it should work the same with 2.x. There is no special setup required other than adding controllers and views to dependency injection (or full MVC, if you prefer).

Controller Side

The controller part is simple, but we have two options:

  1. We can have multiple parameters
  2. Or we can have a single parameter of a data type that holds all of the data that we wish to send

Generally, option #2 is more extensible, for we can add more parameters easily, without changing the action method’s signature, but I will show here how it works with both options.

Multiple Parameters

Our action method will look like this:

[HttpPost]
public IActionResult Add(int a, int b)
{
    return Json(a + b);
}

And that’s it, pretty simple, the [HttpPost] attribute, as you probably know, is an action attribute that says that this action can only be called as a result of an HTTP POST.

Let’s see now what the single parameter version would look like.

Single Parameter

public record AddRequest(int A, int B);

[HttpPost]
public IActionResult Add([FromBody] AddRequest req)
{
    return Json(req.A + req.B);
}

Here we see a few more things:

  1. A record declaration for a type that contains two properties, A and B; I could have made it a regular class, but records are so much more fun! Winking smile You will notice that these two properties, although cased differently, are the same as the parameters on the previous example
  2. The parameter is decorated with a [FromBody] attribute. This one instructs ASP.NET Core MVC to provide the value for the parameter from the body of the request. Its usage could be skipped if we instead decorated the whole controller class with an [ApiController] attribute, but that is beyond the scope of this post

Client Side

On the client side, we also need to match the decision we made on the controller side, regarding how we defined the parameters.

Multiple Parameters

The JavaScript version goes like this:

function calculate() {     

const data = {  a: 1,         b: 2     };
$.ajax({      url: '/Home/Add',         type: 'POST',         data: data,         success: function(result, status, xhr) { /*hooray!*/ },         error: function(xhr, status, error) { /*houston, we have a problem!*/ }     }); 

}

Single Parameter

And the single one is just two small changes:

function calculate() {
     const data = {         a: 1,         b: 2     };
$.ajax({         url: '/Home/Add',         type: 'POST',         data: JSON.stringify(data),         contentType: 'application/json',         success: function(result, status, xhr) { /*hooray!*/ },         error: function(xhr, status, error) { /*houston, we have a problem!*/ }       }); }

As you can see, the difference is that here you need to explicitly serialize the data to JSON using the built-in JSON.stringify function and then also explicitly provide the content type application/json.

Pitfalls

There are a few possible pitfalls:

  1. You may get HTTP 400 Bad Request when you try to POST to your action method. This is likely because of Anti Cross Site Scripting Forgery (XSRF) protection, which is enabled by default in ASP.NET Core MVC. Please refer to my other post here, or, TL; DR, apply an [IgnoreAntiforgeryToken] to the action method
  2. When using the single parameter option, you may be getting a null value in the action method as the parameter value. This is likely the result of being unable to deserialize the contents that you are sending. Please ensure that you are allowing case-insensitive JSON serialization (the default) and that the parameters are well defined. See also here

Conclusion

AJAX has been around for quite a while and is a fun and safe option, but it has its tricks. Hope you find this post helpful!

ASP.NET Core Pitfalls – Areas

There are a few problems with using areas:

  1. The _ViewImport.cshtml and _ViewStart.cshtml files are not loaded by views inside an area, which means that, for example tag helpers registrations are lost and page layouts are not set. The solution is either to copy these files to a view folder inside the area, such as:
    Areas\Admin\Views\Home\_ViewImport.cshtml

    or to copy the files to the root of the application.

  2. You should register the area routes before the other routes:
    endpoints.MapControllerRoute("areas", "{area:exists}/{controller=Home}/{action=Index}/{id?}");
    

Modern Web Development with ASP.NET Core 3 Discount Code

Modern Web Development with ASP.NET Core 3 - Second Edition

If you are interested in my book, Modern Web Development with ASP.NET Core 3, from Packt Publishing, you can use this code for a 25% discount: 25MODERNWEB.

Get it from Amazon: https://www.amazon.com/gp/mpc/A37G5RAWO3DSQX or Packt: https://www.packtpub.com/product/modern-web-development-with-asp-net-core-3-second-edition/9781789619768.

Unit Testing the HttpContext in Controllers

Introduction

When it comes to unit testing, it is common to use mocking to replace “external” services, that is, those that are not part of the subject under test. Not everything can be mocked, and, sometimes, when we instantiate non-POCO classes, such as controllers (ControllerBase), there are lots of things that are not instantiated by the framework and are left for us do to. Just think, for example, if you want to access request or quest string data or know if the user is logged in?

In this post I will talk about two things: the user identity and the request data.

The HttpContext

Inside of a controller action method, it is common to get information which actually comes from the the context (the HttpContext property):

All of these properties get routed to the HttpContext property, which is read-only. It turns out that this property is itself routed to the ControllerContext’s property’s own HttpContext, but the ControllerContext can be set:

var controller = new HomeController();
controller.ControllerContext = new ControllerContext();

So, if we want to set a controller’s HttpContext property, all we have to do is set the ControllerContext’s HttpContext:

controller.ControllerContext.HttpContext = new DefaultHttpContext();

The DefaultHttpContext class is the default implementation of the abstract HttpContext class that is included in ASP.NET Core.

Features

All of the .NET and ASP.NET Core is very modular and designed for extensibility, so it should come as no surprise that all of the HttpContext features are provided as features and it’s easy to provide implementations for them.

Features are accessible through the Features collection and can be set using as key one interface, which is generally a core interface that identifies that feature:

context.Request.Set<IFormFeature>(new FormCollection(request));

The DefaultHttpContext takes in one of its constructors a collection of features, from which it can extract its functionality.

Request Data

When we talk about the request we can be talking about:

  • Form data (including files)
  • The query string

Each is implemented by its own feature. So, if we want to mock form data, we would do something like this, leveraging the IFormFeature:

var request = new Dictionary { { “email”, “rjperes@hotmail.com” }, { “name”, “Ricardo Peres” } }; var formCollection = new FormCollection(request); var form = new FormFeature(formCollection);

var features = new FeatureCollection(); features.Set<IFormFeature>(form); var context = new DefaultHttpContext(features);

This allows us to write code like this, from inside the :

var email = HttpContext.Request["email"];

As for the query string, we would do it like this, using IQueryFeature:

var request = new Dictionary { { “id”, “12345” } }; var queryCollection = new QueryCollection(request); var query = new QueryFeature(queryCollection);

var features = new FeatureCollection(); features.Set<IQueryFeature>(form); var context = new DefaultHttpContext(features);

This code gives us the ability to do this:

var id = HttpContext.Request.Query["id"];

Response

What about sending responses, HTTP status codes and cookies? I’ve got you covered too! The feature contract for the response is IHttpResponseFeature and we add it like this:

var response = new HttpResponseFeature();

var features = new FeatureCollection(); features.Set<IHttpResponseFeature>(response); var context = new DefaultHttpContext(features);

var responseCookies = new ResponseCookiesFeature(context.Features);

Notice that the ResponseCookiesFeature is a little awkward, as it takes the feature collection in its constructor.

With this on, you can set the response status or some cookies on the response of your action:

Response.StatusCode = 400;
Response.Cookies.Append("foo", "bar");

User Identity

As for the user identity, it’s much simpler, we just need to create a ClaimsPrincipal with any claims that we want:

var context = new DefaultHttpContext(features)

{ User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]

{

     new Claim(ClaimTypes.Name, “<username>”),

new Claim(ClaimTypes.Role, “<role>”)

    })) };

You can just pass any username and roles you want, and they will be made available to the controller’s User property.

Conclusion

As you can see, with a little bit of work, almost anything is possible in .NET Core, and, particularly, when it comes to unit tests! Stay tuned for more! Winking smile

Dynamic Routing in ASP.NET Core 3

ASP.NET Core 3 introduced a not so talked about feature which is dynamic routing. In a nutshell, it means that it is possible to decide at runtime the controller, action and route tokens that a request will be dispatched to. The idea is to map a route pattern to a dynamic route handler, like this:

app.UseEndpoints(endpoints =>
{
    endpoints.MapDynamicControllerRoute<SearchValueTransformer>("search/{**product}");
});

This maps a route of “/search/<anything>” to a class SearchValueTransformer, which is then responsible for supplying values for the controller and action.

This SeachValueTransformer class must inherit from DynamicRouteValueTransformer, this is the abstract base class for all dynamic route handling, and it only has one method to implement, TransformAsync. The example I am providing here is that of a service that receives some random query for a product on the URL and then decides to which controller it will be forwarded to. A sample implementation of this class would be:

class SearchValueTransformer : DynamicRouteValueTransformer { private readonly IProductLocator _productLocator; public SearchValueTransformer(IProductLocator productLocator) { this._productLocator = productLocator; } public override async ValueTask TransformAsync(

HttpContext httpContext, RouteValueDictionary values) { var productString = values[“product”] as string; var id = await this._productLocator.FindProduct(“product”, out var controller); values[“controller”] = controller; values[“action”] = “Get”; values[“id”] = id; return values; } }

As you can see, it takes an instance of an IProductLocator (I will get to that in a moment) in its constructor, which means that it supports dependency injection. The TransformAsync extracts a “product” parameter from the route – I am skipping validation because if we got here that’s because we matched the route – which it then uses to call the stored IProductLocator instance to retrieve the id and controller, which are then set as route parameters. The result route is then returned.

The SearchValueTransformer needs to be registered in the dependency injector too:

services.AddSingleton<SearchValueTransformer>();

The actual lifetime is irrelevant, here I am setting it as singleton because the SearchValueTransformer holds a single IProductLocator which is itself a singleton and nothing else.

As to the IProductLocator, here is it’s interface:

public interface IProductLocator
{
    Task<string> FindProduct(string product, out string controller);
}

The actual implementation, I leave it up to you, it must apply some logic to the product passed in the URL to decide which controller should be used for search it, and then return some reference and a controller responsible for returning information about it. This interface and its implementation must also be registered:

services.AddSingleton<IProductLocator, ProductLocator>();

And this is it. This may serve as a complement to static routing, other uses include translating route parts (controller, action) on the fly. As always, hope you find this useful!

Accessing the HttpContext from a DbContext

Sometimes it might be necessary to access the current HttpContext from inside a DbContext, namely, from inside the OnConfiguring or OnModelCreating methods. Why? Well, for once, because of multitenancy: we may want to be able to decide the connection string to use based on the requesting or the host’s domain, the current user or some other request parameter. Here the internal dependency injection (Instance) can’t help, because it cannot be used inside these methods.

The only option we have is to inject the IHttpContextAccessor class through our DbContext class’ constructor, and, from it, get hold of the HttpContext.

First we need to register the IHttpContextAccessor service in ConfigureServices:

services.AddHttpContextAccessor();

We also need to register our context for dependency injection:

services.AddDbContext<MyContext>();

A context registered this way needs to have a special constructor that has a parameter of type DbContextOptions (or DbContextOptions<MyContext>), in our case, we just need to add an extra parameter of type IHttpContextAccessor:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options)
    {
        this.HttpContextAccessor = httpContextAccessor;
    }

    protected IHttpContextAccessor HttpContextAccessor { get; }
}

Finally, when you need to access the HttpContext, you just need to retrieve it from the IHttpContextAccessor:

protected internal override void OnConfiguring(DbContextOptionsBuilder builder)
{
    var httpContext = this.HttpContextAccessor.HttpContext;
    var tenantService = httpContext.RequestServices.GetService<ITenantService>();
    var connectionString = tenantService.GetConnectionString(httpContext);

    builder.UseSqlServer(connectionString);

    base.OnConfiguring(builder);
}

Here the hypothetical ITenantService provides a method GetConnectionString that returns a connection string for the current HttpContext, and we use it with the SQL Server provider.

Hope you find this useful! Winking smile

C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development – Fourth Edition Review

C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development

This is a book written by Mark J. Price for Packt Publishing. I must say that I don’t know Mark, but I was asked by Pack to review this book, which I gladly did!

The topics covered in this book are vast, so it should be no surprise the size of it: more than 800 pages. It spawns across 21 chapters, each of them ends with some exercises. It talks about pretty much everything .NET, as you can see:

Chapter 1

Introduction to Visual Studio Code and Visual Studio 2019 for Windows and Mac. Presents some useful extensions for Visual Studio Code. Talks a bit about the .NET Framework and its branches and offspring, Xamarin, Mono and .NET Core. Also explains the intermediate language that .NET compiles to and how to produce native code from .NET. Also shows how to use Visual Studio Code to get code from GitHub and build console apps. Finally, it gives some pointers on how to get support from the Internet.

Chapter 2

Presents all the C# versions from 1 until 8, the last one to date. Shows how to enable a specific version on a .NET project. Gives a an overview of the unchanging C# language features, like variables, data types, reference and value types, and presents a simple example on how to get input from the user.

Chapter 3

Expands on the C# language started on the previous chapter introducing branching, conditions, pattern matching, assignment, operators, loops and casts.

Chapter 4

Introduces functions, how to debug and unit test them.

Chapter 5

Explains Object-Oriented Programming with C#. How references to assemblies and namespaces work. Field and property modifiers. How to use the return values of functions, including tuples. Method overloading, optional parameters. Partial classes. Properties with indexers and different levels of access.

Chapter 6

Talks about interfaces and type inheritance. Explains events and delegates. Generic types. Reference and value types. The dispose pattern. Member overriding and hiding. Preventing inheritance. Polymorphism. Casting. Extension methods.

Chapter 7

Packaging .NET components in assemblies and NuGet packages. The .NET Standard and .NET Core. Publishing applications. Decompiling assemblies. Publishing to NuGet. Porting to .NET Core.

Chapter 8

Common .NET types and operations: numbers, string, regular expressions, collections, spans, indexes, ranges, network resources, types, attributes. Internationalization.

Chapter 9

Files, file streams and serialization. Working with the filesystem. Text encoding. XML and JSON serialisation and compression.

Chapter 10

Data encryption and decryption. Data hashing and signing. Random number generation. User authentication and authorisation.

Chapter 11

Database programming with Entity Framework Core.

Chapter 12

Using LINQ. Custom LINQ methods. LINQ to XML. Parallel LINQ.

Chapter 13

Performance monitoring. Tasks. Synchronizing access to shared resources. async and await.

Chapter 14

ASP.NET Core web applications. SignalR. Blazor.

Chapter 15

ASP.NET Core Razor Pages. Using EF Core with ASP.NET Core. Razor Class Libraries.

Chapter 16

ASP.NET Core MVC.

Chapter 17

Using Content Management Systems (Piranha CMS).

Chapter 18

ASP.NET Core Web API. Swagger and Open API. Health checks. WCF and gRPC are mentioned briefly.

Chapter 19

Machine learning with ML.NET.

Chapter 20

Windows Forms apps. Windows Presentation Foundation apps with .NET Core and Windows Compatibility Pack. The XAML Standard. Modern Windows apps.

Chapter 21

Using Xamarin for building cross-platform mobile apps. Calling web services.

Conclusion

As you can see, this is a lot, and goes from the plain C# language to machine learning and Blazor. I’d say that some topics, such as Content Management Systems, could have been dropped, but other than that, pretty much everything that a developer longing to learn .NET could wish for is here. A great deal of ASP.NET Core, which is good, as it is for sure the strong part of .NET Core. So, if you’re one such developer, this is one book that you may want to get, you won’t feel disappointed! Definitely a good value for money!

Now Reading: C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development – Fourth Edition

Update: see the review here.

I am now reading C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development – Fourth Edition, by Mark J. Price, from Packt Publishing. Expect a review from it very soon.

C# 8.0 and .NET Core 3.0 - Modern Cross-Platform Development - Fourth Edition

@MarkJPrice @RavitJain @PacktPub