.NET CodeCop EntityFramework

Bypassing EntityFramework. Because I can.

Howdy folks, if you recall from my last post, CodeCop is a new library I developed which uses JSON to configure method interceptors for .NET apps.

It works entirely in memory, without proxies, post-build rewrites or special objects and besides letting you intercept before and after a method has executed it also enables a complete bypass of a method’s behavior.

Method surrogation is one of the most powerful features of CodeCop, in fact its so powerful that it even lets you intercept methods you didn’t write and reside on 3rd party assemblies.

Today I will give you a simple example of just that. Lets put our bad boy hat and be nasty to…Entity Framework library itself! (sorry EF, I love you nothing personal there).

I want to be able, at runtime, whenever the Remove method of the DbSet object is called to swap it for a call to the Add method instead. Also whenever we call the SaveChanges method from DbContext we will ignore that and output to the console the sentence “No way Jose!”. Sounds evil? I feel a bad-ass right now. 😈

Let’s start by creating two separate projects in Visual Studio, a Console Application and a Class Library. I will be using Framework 4.6, but you can chose any other from 4.0 onwards. I will be calling EFInterception to the first and Interceptors to the latter.

new-project2

new-project

Now we add our dependencies via nuget to both projects, Entity Framework 6.0 and CodeCop:
install-package entityframework -version 6.0
install-package codecop

We will now create two interceptors on the Class Library project. Add two classes to the project call them DbContextInterceptor and DbSetInterceptor respectively.

interceptor1

interceptor2

Make your code on the DbSetInterceptor look like this (refer to the CodeCop wiki for the API details):

 public class DbSetInterceptor : ICopIntercept, ICopOverride
    {

        public void OnBeforeExecute(InterceptionContext context)
        {
            Console.WriteLine("Before Remove Method");
        }

        public void OnAfterExecute(InterceptionContext context)
        {
            Console.WriteLine("After Remove Method");
        }

        public object OnOverride(InterceptionContext context)
        {
            dynamic dbset = context.Sender;

            if (dbset != null && context.Parameters.FirstOrDefault() != null)
            {
                dbset.Add(context.Parameters.First().Value as dynamic);
            }

            return null;
        }
    }

The above code is very easy to understand, before and after the method executed we will output a message to the console. Also, instead of running the original method behavior we will override it with a call to the Add method from the DbSet class passing in the entity that was handled to the Remove method as argument when it was originally called.

Now head to the DbContextInterceptor and paste this code in:

  public class DbContextInterceptor : ICopIntercept, ICopOverride
    {
        public void OnBeforeExecute(InterceptionContext context)
        {
            Console.WriteLine("Before SaveChanges()");
        }

        public void OnAfterExecute(InterceptionContext context)
        {
            Console.WriteLine("After SaveChanges()");
        }

        public object OnOverride(InterceptionContext context)
        {
            Console.WriteLine("No way Jose!");
            return 1;
        }
    }

The code is self-explanatory, same output on the before and after method execution and then on override instead of calling the method we will output “No way Jose!” to the console.

That’s all you need to do on the Class Library project, compile it and copy its dll to the bin folder of the Console Application project.

On the Console Application side, I have created a DemoDBContext with a single DBSet of Person which is a simple class with three properties, FirstName, LastName and Age (I will omit the source here for the sake of brevity).

Now sign the Console Application assembly with any key (this step is mandatory because EF is a strong-named assembly):
sign

Afterwards, on the Program class add this code:

 class Program
    {
        private static readonly DemoDbContext _context = new DemoDbContext();
        static void Main(string[] args)
        {
            // Bootstrap CodeCop
            Cop.Intercept();

            // Calling remove will Add
            _context.Persons.Remove(new Person
            {
                Age = 38,
                FirstName = "Ricardo",
                LastName = "Barbosa"
            });

            //Saving changes will tell us no way Jose!
            _context.SaveChanges();
        }
    }

Add a JSON file to your project, call it copconfig.json and select on the Copy to Output Directory property, copy if newer, make the file look like this:

{
  "Types": [
    {
      "TypeName": "System.Data.Entity.DbSet`1, EntityFramework",
      "Methods": [
        {
          "MethodSignature": "Remove(TEntity)",
          "Interceptors": [
            "DbSetInterceptor"
          ]
        }
      ],
      "GenericArgumentTypes": [ "EFInterception.Person" ]
    },
       {
      "TypeName": "System.Data.Entity.DbContext, EntityFramework",
      "Methods": [
        {
          "MethodSignature": "SaveChanges()",
          "Interceptors": [
            "DbContextInterceptor"
          ]
        }
      ],
      "GenericArgumentTypes": []
    }
  ],
  "GlobalInterceptors": [ ],
  "Key": "Paste your product license key here if you have one (the Free product mode is limited to intercepting 25 methods)"
}

Running the the app and setting a breakpoint after a call to Remove we see that it actually added the entity instead of removing it.

result2

And this is the console output:

result

As you see, in a snap, we completely bypassed these two methods on a 3rd party signed assembly. And we did it unobtrusively, your Console Application code knows nothing about your interceptors (you just dropped the dll’s on the bin remember?). Via JSON we placed them and that’s about all the effort there is to have full control over a type and its methods, no matter where it resides (inside or outside your main app assembly).

Now, what’s the usefulness of all this, you might ask? Well dear reader, your imagination is king there. One good use that immediately comes to mind is for mocking/faking frameworks. Today these frameworks need object wrappers, which implies the developer to create interfaces or abstract classes with virtual methods to override. CodeCop needs any of those because it works with the original objects themselves. It’s a quick and direct object interception process at the distance of a JSON file. Impressed? Alright! 🙂

That’s all I have for today, next week I will showcase Pipelined Interception which is the possibility to intercept methods directly on interfaces and automatically on all types that implement them. Coolness at its highest!

Stay tuned, see you next week!

Free Email Updates
Get the latest content first.
100% Privacy. No spam.

Liked it? Please Share.

Leave a Reply

Your email address will not be published. Required fields are marked *