.NET

JSON meets method interception in .NET

No way! Get out a here! Ohh sh*t…really???

Dear reader if this is sort of your reaction when I say you can do method interception in .NET with JSON, then keep reading this post as I will show you how.

There’s this new kid in town called CodeCop that can intercept or even rewire your app’s methods with just a simple JSON file. It’s a configuration based interceptor library for .NET that works entirely in-memory without the need of proxies or post-build assembly rewrites.

How is this possible, you might ask? Well as its creator I can tell you that CodeCop is mashup of several CLR complex interception techniques that make all this magic happen. This post isn’t about those techniques in detail but to show what you can do once we abstracted that complexity away into a simplistic, yet powerful API.

With CodeCop you build your interceptors as separate independent classes and apply them via JSON on the methods you desire. This means that at any time interceptors can be added or removed without code changes or redeploys, it’s unobtrusiveness at its best.

There’s even an online tool that one can use to reverse-engineer any .NET assembly, and automatically generate the JSON file needed for interception to happen, how cool is that?

I’m pretty sure you are all curious by now, so let’s cut the chase and see an example of how we can get started using this library (more in-depth info can be found on the project’s wiki).

CodeCop comes in three flavors, Free, Developer and Ultimate which you can compare here. For this example I will be using the Free version as the project we’re creating is a simple demo, but for more complex projects I truly recommend the Ultimate version as it even lets you intercept methods on external / 3rd party assemblies among other cool features.

This library supports .NET 4.0 and onwards, including the recent .NET 4.6 (although for x64 projects you need to disable RyuJIT for it to work).

Let’s start by creating a .NET 4.6 WebApplication project, using the MVC template.

mvc-template

Afterwards, head to the nuget package manager console and install the CodeCop nuget package.

nuget

Now that the CodeCop assembly is in place let’s build our first interceptor.

There are two kinds of interceptors you can build, one that intercepts the method “borders” that is to say before and after the method has executed, and other that lets you override the method execution completely. The override option though is only available to the Developer and Ultimate versions of the library, so as we’re using the Free version we will intercept only before and after execution.

Add a new class to the project and call it CustomHttpHeaderWriter. This interceptor will write the intercepted method’s name to a custom HTTP Header before and after it has executed.

interceptor

Make this class implement the ICopIntercept interface. This interface has two methods, OnBeforeExecute and OnAfterExecute. As its names clearly state OnBeforeExecute will be called before the intercepted method has executed and OnAfterExecute after.

implement

These methods receive an InterceptionContext object that among other useful information (like the parameters that were passed, generic arguments which was invoked, etc) contain the intercepted method itself that we can use to extract its name. You can read more about the InterceptionContext object here.

Add this code to the OnBeforeExecute method:
HttpContext.Current.Response.Headers.Add("Before", context.InterceptedMethod.Name);

And this code to the OnAfterExecute method:
HttpContext.Current.Response.Headers.Add("After", context.InterceptedMethod.Name);

This is how your interceptor should look like:

interceptor2

Let’s now bootstrap CodeCop by calling its Intercept method on the Global.asax file (you can also pipeline this into a Owin startup class but for the sake of simplicity lets add it to the Global.asax).

copintercept

The Intercept method has 2 overloads. One with no parameters that should be used when we want auto-discovery of interceptors (only for interceptors with public parameterless constructors) and other that receives your interceptors as arguments. As our interceptor has no dependencies on the constructor we will use the first one without arguments.

That’s all the code you need, to intercept ANY method inside your app. Nothing more.

Now let’s go to the online JSON generator tool to generate our configuration file. It’s through this file that we specify which methods we want to intercept and which interceptors will run once interception takes place.

This tool isn’t mandatory, we could have just written the JSON file by hand ourselves by following these instructions, but believe me it is much less error prone and saves you a lot of time.

Once the tool loads, we will see a popup asking if we want to see a tutorial on how to use it. Let’s skip the tutorial for now as I will show you how.

This is the main screen of the tool. All the action buttons are on the top right corner.

tool2

Click on the second button counting from the right to bring the upload screen.

tool1

Within this screen we have three options. Upload an existing JSON configuration file (for the cases you already have a configuration and want to make changes to it, upload a dll or an exe.

We are interested in uploading our app assembly that is a dll so we will click on the dll tab to do so.

upload2

Once the assembly is uploaded and its reverse engineer process ends, you will see all its types on the left of the screen. For our app the tool is informing us that there are 32 types inside our uploaded assembly.

types

We can scroll down to find the type(s) we want to intercept methods from or we can just use the filter. We want to intercept the HomeController’s methods, so let’s write Home on the filter. Immediately the filter will find our type, just click on arrow to select it.

type-select

Once the selection is done you will see a rectangle that on its bottom-left indicates how many methods the type has (in this case four) and on the bottom-right how many of that methods are intercepted (zero for now).

type-select2

Click the rectangle to bring the method selection options. In here we have also the option to filter for method names, but as we want to intercept all methods of the HomeController type, tick the Select All option.

interceptor-select

Now that we have selected the methods we want to intercept, we need to place our interceptor as the interceptor that it will run once the methods are captured. To do so click on the third button of the upper right menu.

interceptor-select3

The interceptor screen will appear, we need just to add the interceptor name (case sensitive) and press enter.

interceptor-name

Once the enter key is pressed you will see that the interceptor name is added on each of the methods of the type you have selected. You also see a Use As Global option, CodeCop enables an interceptor to be added to all methods of all types with this option. We will not select this option because this interceptor is only for the methods of the HomeController type.

Click anywhere outside the interceptor screen to return to the method selection options. We now have to activate our interceptor by ticking the checkbox below the method name to apply to it. We will select it for all methods of the type.

That’s all we need to configure, let’s view the JSON the tool generated for us by pressing the button with an eye icon.

view

Now press the download button and a file named copconfig.json (mandatory name, is case you want to generate this file by hand) is downloaded.

download

Next step is to add this file to our project with the “copy if newer” option on the copy to output directory project property.

add-json

Now launch the app by pressing CTRL + F5 and once the welcome screen appears, open the developer tools on your browser (I am using Chrome so it’s the F11 key) and navigate to the Network tab. Refresh the page for the browser to capture network traffic and click on the localhost entry.

network-tab

Once you click on localhost and select the Headers tab you will see that the interceptor we wrote has already kicked-in with the work we told him to do (write the method name to a custom HTTP Header). You will see that it has ran on the .ctor and on the Index methods before and after their execution for the HomeController type.

network-tab2

Next, navigate to the About and Contact pages with the network tab open and see our interceptor doing its work.

about

contact

Isn’t this cool? And the beauty of it is that once it is bootstrapped on an app, we can add or remove interceptors without having to change the app’s code. Just declare your interceptors on a different assembly, configure them in the copconfig.json file and you’re all set. This is great for instrumentation scenarios on production apps, can save you a lot of time and extra effort for huge applications.

CodeCop is not meant only for instrumentation, it can be used as a mocking/faking testing framework with its override method option. Can also be used to help you code faster by reducing boilerplate code, e.g. just create a global interceptor that checks if method arguments are null and never more you have to write code again to check that. Our imagination is king on what a powerful library like this can do for us.

It has no limitations in terms of the methods you can capture (public, private, abstract, virtual, static, generic, async, with out, ref parameters, etc), doesn’t force you to bloat your code with attributes or special objects, everything is JSON configured, also as interceptors can be declared in different assemblies, it doesn’t need you to redeploy your entire app when adding or removing interceptors.

Convinced? Alright! Now that you know how to intercept .NET methods with JSON whenever you see someone with the same reaction you had, show them this post or better still teach them how to use CodeCop 🙂 .

See you next time, where I will show you to do method surrogation with this powerful library.

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 *