flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Verifying calling objects

Monday, February 12, 2007 2:59 PM

I've been spending a lot of time recently thinking about how you could enforce calling restrictions on certain methods in your objects.  Say, for example, you have a particular method on a particular class that essentially is in place only as a kluge; something that should only be called in very certain circumstances and only by a certain caller.

Let me give you a example.  Recently I was asked to make a certain method asynchronous, a method which previously had been invoked completely synchronously.  I decided to just follow the standard .NET Asynchronous Programming Model and essentially wrap the method in a modified BackgroundWorker (the solution actually ended up being a bit more involved than that but that was essentially the gist of it).

The BackgroundWorker, like most of the APM, works on delegates.  Essentially, you find the method that does most of your work and designate that as the handler for your BackgroundWorker.DoWork event.  Then you find your clean up method which should be called at the end (this is basically your callback) and designate that as the handler for your BackgroundWorker.RunWorkerCompleted event.  Once you get your head around it it's actually a pretty slick little system.

Let's say that your original methods are DoIntensiveOperation() and CleanUpIntensiveOperation(), like below:

        private void DoIntensiveOperation()
        {
            // Perform a lot of intensive work
        }
 
        private void CleanUpIntensiveOperation()
        {
            // Clean up our intensive operation
        }

and it's called in code synchronously like this:

         Console.WriteLine("Starting our intensive operation...");
         DoIntensiveOperation();
         CleanUpIntensiveOperation();
         Console.WriteLine("Finished with our intensive operation!");

If you want to make the method asynchronous, you simply have to register it as appropriate with the BackgroundWorker and call the BackgroundWorker in its place.  (OK, I oversimplified it a little bit, you also have to alter your original method signatures to match the expected signatures the handlers in BackgroundWorker expect).

         BackgroundWorker myBackgroundWorker = new BackgroundWorker();
         myBackgroundWorker.DoWork += 
             new DoWorkEventHandler(DoIntensiveOperation);
         myBackgroundWorker.RunWorkerCompleted += 
             new RunWorkerCompletedEventHandler(CleanUpIntensiveOperation);
 
         Console.WriteLine("Starting our intensive operation...");
         myBackgroundWorker.RunWorkerAsync();
         Console.WriteLine("Finished with our intensive operation!");

Simple enough, right?  Well, almost.

Think about this:  Now you have new versions of those methods out there which are really only invoked by the background worker.  Granted in the example above, their private but there's no reason why they couldn't be public.  And besides, just because they're private doesn't necessarily make them safe.  In my case, I was working in a shared class file.  There was nothing to keep the next developer from coming along 5 minutes later and deciding to just randomly start calling my precious methods directly; scary signatures not withstanding.

What we need is a way to verify that those new methods we created are only being called by who we intended, in our case, the BackgroundWorker.  Luckily, the signature provides just such a way.

You'll notice that the signature of our methods bear a strong resemblance to signature of the EventHandler delegate, as well they should since they're in essence handlers in they're own right.  One of the interesting things about the EventHandler delegate is that they're first parameter is and object called 'sender'.  What is this 'sender'?  Well, if you've ever needed to inspect it while handling an event, you know that the runtime implicitly places a references to the calling object in this sender parameter meaning that you can always reference the calling object (or at least its public members) when you're handling the event.  Luckily, that works out to be just exactly what we need to verify who's actually calling our method.  We can check this parameter as soon as we're invoked and decide if who called us is someone that we want to be allowed to call us.

        private void DoIntensiveOperation(object sender, DoWorkEventArgs e)
        {
            Debug.Assert(sender is BackgroundWorker,
                "DoIntensiveOperation may only be called by an instance of BackgroundWorker");
 
            // Perform a lot of intensive work
        }
 
        private void CleanUpIntensiveOperation(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.Assert(sender is BackgroundWorker,
                "CleanUpIntensiveOperation may only be called by an instance of BackgroundWorker");
 
            // Clean up our intensive operation
        }

Works great, right?  Well, almost.  One of the gotchas with this is that it only makes sense for methods which either can be invoked publicly by an outside object, or asynchronously by use of a delegate.  It really just doesn't make to much sense for your standard synchronous private method.  The other gotcha is that this methodology relies heavily on the honor system, meaning, that it's very easy to spoof:

        Console.WriteLine("Starting our intensive operation...");
        DoIntensiveOperation(new BackgroundWorker(), DoWorkEventArgs.Empty);
        CleanUpIntensiveOperation(new BackgroundWorker(), RunWorkerCompletedEventArgs.Empty);
        Console.WriteLine("Finished with our intensive operation!");

So its a possible solution, but definitely not an end all.  It's definitely not a solution I would recommend for a commercially developed API or any API with a high security standard but it may work OK to enforce proper use inside of your own little development team.    Anyone have any thoughts?

kick it on DotNetKicks.com

Feedback

# re: Verifying calling objects

I have had this same problem when writing internal methods that are only supposed to be called by unit test code.

I considered demanding one of the identity permissions (eg. StrongNameIdentityPermission) but none of them were specific enough. And besides, it probably only makes sense to verify the caller in a DEBUG build, not RELEASE.

My solution ended up being a helper method that creates a StackTrace instance and verifies the caller in the correct frame of that stack trace. 2/18/2007 6:52 PM | Kent Boogaart

 re: Verifying calling objects

why use the BackgroundThreadInvoker? Its a nice easy way to get multi-threading in an app if u don't know how to use multi-threading, but how about using delegates/asyncallbacks and the begin/end mechanism.

In best practice multi-threading, you should let the client decide which kind of call to make (sync or async). Having methods that are some hybid/kluge isn't right. 2/18/2007 9:06 PM | Bart C

# re: Verifying calling objects

Kent, why go through all of that trouble when you can just use the InternalsVisiableToAttribute? Ent Lib uses this paradigm for exactly the reasons you wrote about. 2/19/2007 4:10 AM | jayson knight

# re: Verifying calling objects

The stack trace is a great idea, i've been meaning to look into that, I know there is some sort of a StackFrame in the BCL but hadn't gotten around to it yet. Thanks for the idea!

Also, Jayson, you're completely right about the InternalsVisibleToAttribute. However, as I found out when I tried to use it for unit testing some helper methods, none of our assemblies our strong named yet. Unfortunately the attribute requires this. I'm hoping to convince my lead to let us start strong naming in our upcoming post mortem.

Also, Bart, thanks for the note about the delegates. You are entirely correct they are the most elegant way to handle this. The reason we decided to go with the BackgroundWorker was that we were trying to create a general use worker thread with a progress bar that we could apply to several intensive operations. In hindsight this was a pretty bad decision and really didn't buy us anything since we generally had to mutilate the legacy code so much to get it to work with our model (i.e., the method signatures, altering the flow to fit our callback, etc). I intended it as a temporary solution (of course we all know how temporary solutions have a habit of becoming permanent ;) with hopes that I'll be able to gut the code entirely in upcoming weeks. We'll see what happens... 2/19/2007 9:37 AM | Jeremy Jarrell

# re: Verifying calling objects

Jayson, that's exactly what I used. But that doesn't stop non unit test code from calling the unit test only members. That's the point. 2/19/2007 5:34 PM | Kent Boogaart

# re: Verifying calling objects

Well, if those methods are called only in that situation why not make them anonymous? So that they officially don't exist outside of your calls. 5/7/2007 1:54 PM | Simone Busoli

# re: Verifying calling objects

Hmm, I actually hadn't thought about that. That's definitely a nice, very clean, solution as well.

Good idea, Simone! 5/7/2007 2:06 PM | Jeremy

Post a comment





 

Please add 7 and 2 and type the answer here: