Tag Archives: Read Only

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.

Adding and Removing an IIS Application in .NET

Following on from an earlier post about my discovery of an API to control IIS, I had cause to investigate creating a new web application in IIS. The code, again, is remarkably simple:

            ServerManager iisManager = new ServerManager();

            Console.WriteLine("Set-up new site...");

            var sites = iisManager.Sites;

            foreach (var s in sites)
            {
                Console.WriteLine($"Site {s.Name}");

                foreach (var a in s.Applications)
                {
                    Console.WriteLine($"Application {a.Path}");
                }
            }
            Console.WriteLine(" - - - ");

            var defaultSite = sites["Default Web Site"];
            defaultSite.Applications.Add("/Test", @"c:\inetpub\betapps\test");        
            iisManager.CommitChanges();

            Console.ReadLine();

This works fine and, as you can see, is really simple. If you remove the information lines at the top, it’s three lines of code.

Remove it again

To remove the application again, try this:

            var iisManager = new ServerManager();
            var sites = iisManager.Sites;
            var defaultSite = sites["Default Web Site"];
            var testapp = defaultSite.Applications["/Test"];

            if (testapp != null)
            {
                Console.WriteLine("Remove site");
                defaultSite.Applications.Remove(testapp);
                iisManager.CommitChanges();
            }

There is an important note here; simply adding, committing changes and then removing using the same instance of ServerManager will not work. It complains that once CommitChanges is called then the object is read only:

InvalidOperation

The configuration object is read only, because it has been committed by a call to ServerManager.CommitChanges(). If write access is required, use ServerManager to get a new reference.

Also, you can’t just get around this by calling something like:

iisManager = new ServerManager();

Although this does