Tag Archives: .Net Framework

ReadOnly Entity Framework

Ever come across a situation where you want to use an Entity Framework data layer in a little tool or report, but ended up reverting to Ado.Net or a different ORM because EF is a little bit like a Heisenberg Framework (it changes things that it looks at)? You might have a seed method that tries to update data, or a migration that you don’t want to apply.

Apologies in advance if this seems like stating the bloody obvious; but it didn’t seem obvious to me at the time. If there’s a neater way to do this then please let me know.

Anyway, I recently had this issue, and came up with the idea of a ReadOnly DBContext. For example, your main DBContext might look like this:

    public class MyDbContext : DbContext, IMyDbContext
    {
        static MyDbContext()
        {            
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>());
        }
 
        public MyDbContext()
            : base("connection-string")
        {
            
            
        }
 
        public MyDbContext(string connectionString)
            : base(connectionString)
        {
 
 
        }
 
        public DbSet<Entity1> Entity1 { get; set; }
        public DbSet<Entity2> Entity2 { get; set; }
 
        void IMyDbContext.SaveChanges()
        {
            base.SaveChanges();
        }
 
        Task IMyDbContext.SaveChangesAsync()
        {
            return base.SaveChangesAsync();
        }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Entity1>()
                .HasOptional(a => a.Field2)
                .WithMany();            
  
            base.OnModelCreating(modelBuilder);
        }
    }

Making a ReadOnly version of this is pretty much removing the code; for example:

    public class MyReadOnlyDbContext : DbContext, IMyDbContext
    {
        static MyReadOnlyDbContext()
        {            
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyReadOnlyDbContext, Configuration>());
        }
 
        public MyReadOnlyDbContext()
            : base("connection-string")
        {
            
            
        }
 
        public MyReadOnlyDbContext(string connectionString)
            : base(connectionString)
        {
 
 
        }
 
        public DbSet<Entity1> Entity1 { get; set; }
        public DbSet<Entity2> Entity2 { get; set; }
 
        void IMyDbContext.SaveChanges()
        {

        }
 
        Task IMyDbContext.SaveChangesAsync()
        {
		  return Task.CompletedTask;

        }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Entity1>()
                .HasOptional(a => a.Field2)
                .WithMany();
  
            base.OnModelCreating(modelBuilder);
        }
    }

An easy way to return the read only version, rather than the main version is via a DbContextGenerator:

public class DbContextGenerator : IDbContextGenerator
{
    private readonly AppSettings appSettings;        
 
    public DbContextGenerator(AppSettings appSettings)
    {
        this.appSettings = appSettings;            
    }
 
    public IMyDbContext GenerateDbContext()
    {            
        if (appSettings.ReadOnly)
        {
            return new MyDbReadOnlyContext(appSettings.DatabaseConnectionString);
        }
        return new MyDbContext(appSettings.DatabaseConnectionString);                        
    }
}

This can be registered in the IoC and will return a DB Context based on a read only flag.

It’s worth noting that if your model doesn’t match, it will likely crash. It’s also worth noting that if you’re reading this article and trying to work out how you can use EF without having it manage the DB then it’s probably because something, somewhere, went wrong: this isn’t a suggestion for a new way to use EF, it’s a way to use EF in a temporary fashion.

Web API Routing – The Basics

Working with API projects, it’s easy to miss some key rules about the routing. This post is basically the result of some that I missed, and subsequent the investigation. It covers some very basic routing rules, and it certainly not intended to be an exhaustive guide.

.Net Framework

Starting with a .Net Framework Web API, let’s create a new web app:

And add a new controller:

Here’s the code for the controller; as you will see, it’s massively complex, but the good news is that you only need to pay attention to the name of the action, and the code inside it:

public class TestController : ApiController
{
    [HttpGet]
    public IHttpActionResult TestAction()
    {
        return Ok("TestAction Performed");
    }
}

Let’s run the project and navigate to the URL:

How did I know that was the URL? It’s magic, and you can buy some of that magic by sending a cheque for the low, low price of $25 to the address shown at the bottom of the screen.

Actually, it’s defined in WebApiConfig.cs:

Parameters

Where there is more than a single function, one surprising (to me) feature is that the parameters that it accepts is more important to the routing than the name of the controller. Here’s a second action with a parameter:

[HttpGet]
public IHttpActionResult TestAction2(string test)
{
    return Ok("TestAction2 Performed");
}

… and here’s it working:

However, should I not give it the parameter that it craves, it hides away, and instead, we get the first function that’s no too fussy about parameters:

It doesn’t even matter whether I just put some drivel as the controller name; the first criteria is the parameter:

This is because, according to this it follows these criteria:

The default implementation is provided by the ApiControllerActionSelector class. To select an action, it looks at the following:
• The HTTP method of the request.
• The “{action}” placeholder in the route template, if present.
• The parameters of the actions on the controller.

So, if we add the {action} placeholder, that ensures that it uses the correct method:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services
 
    // Web API routes
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        //routeTemplate: "api/{controller}/{id}",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

Otherwise, we get a best guess based on the parameters.

.Net Core Web API

The rules have changed since switching to .Net Core; WebApiConfig has gone and, in its place, it a localised routing system.

Here, you tell the class how to handle routing; for example, the following:

[Route("api/[controller]")]

Will result anything decorated with HttpGet being called when the controller is called. The parameters must be explicitly decorated; so passing no parameters would look like this:

[HttpGet]
public string OneTest()
{
    return "TestOne";
}

Whereas, a single parameter would look like this:

[HttpGet("{id}")]
public string aaa(int id)
{
    return "value aaa";
}

If you duplicate the signatures then they are not found. As with the framework version, you can simply tell it to look to the action name that you give it:

[Route("api/[controller]/[action]")]
public class TestController : Controller
{
    [HttpGet]
    public IEnumerable<string> TestActionOne()
    {
        return new string[] { "one value1", "value2" };
    }
 
    [HttpGet]
    public string TestActionTwo()
    {
        return "two value";
    }

But, again, it pays no attention to parameters until you decorate it correctly.

References

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing