0

What I need: a class with two parents, which are ContextBoundObject and another class.
Why: I need to access the ContextBoundOject to log the method calls.
Composition works? As of now, no (types are not recognized, among other things).
Are other ways to do this? Yes, but not so automatable and without third-party components (maybe a T4 could do, but I'm no expert).

A more detailed explanation.

I need to extend System classes (some of which have already MarshalByRefObject (which is the parent of ContextBoundObject) for parent, for example ServiceBase and FileSystemWatcher, and some not, for example Exception and Timer) to access some inner workings of the framework, so I can log method calls (for now; in future it may change).

If I use this way I only have to add a class name to the object I want to log, instead of adding the logging calls to every method, but obviously I can't do this:

public class MyService:ServiceBase,ContextBoundObject,IDisposable{
    public MyService(){}
    public Dispose(){}
}

so one could try the usual solution, interfaces, but then if I call Run as in:

ServiceBase.Run(new MyService());

using a hypotethical interface IServiceBase it wouldn't work, because the type ServiceBase is not castable to IServiceBase -- it doesn't inherit from any interface. The problem is even worse with exceptions: throw only accepts a type descending from Exception.
The reverse, producing a IContextBoundObject interface, doesn't seem to work either: the logging mechanism doesn't work by methods, so I don't need to implement any, just an attribute and some small internal classes (and inheriting from ContextBoundObject, not even from MarshalByRefObject, which the metadata present as practically the same).

From what I see, extending from ContextBoundObject puts the extended class in a Proxy (probably because in this way the method calls use SyncProcessMessage(IMessage) and so can be intercepted and logged), maybe there's a way to do it without inheritance, or maybe there could be pre or post compiling techniques available for surrounding methods with logging calls (like T4 Text Templates), I don't know.

If someone wants to give this a look, I used a customized version of MSTestExtentions in my program to do the logging (of the method calls). Any ideas are appreciated. There could be the need for more explanations, just ask.

Community
  • 1
  • 1
lunadir
  • 339
  • 3
  • 15

2 Answers2

0

Logging method calls is usually done using attributes to annotate classes or methods for which you want to have logging enabled. This is called Aspect Oriented Programming.

For this to work, you need a software that understands those attributes and post-processes your assembly by adding the necessary code to the methods / classes that have been annotated.

For C# there exists PostSharp. See here for an introduction.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Yes, I know a bit of AOP, and have used PostSharp, but as I've said I'd prefer not having third-party components. The logging I've done works, the problem is how to do it with classes that already have the single inheritance "occupied". – lunadir Feb 20 '13 at 11:53
  • @lunadir: Well, you don't. Multiple inheritance simply isn't supported. You will have to find another way. – Daniel Hilgarth Feb 20 '13 at 11:57
  • In fact I would interested in the possiblity of other ways to do what I'm already doing. – lunadir Feb 20 '13 at 12:04
  • Whether this is AOP or not is not important. The point is how do I intercept method calls where now I can't. – lunadir Feb 20 '13 at 13:08
  • @lunadir: You will have to use *something* that rewrites the assemblies after they have been compiled. That's not a problem for your own assemblies but I don't think it will work for assemblies in the .NET framework. – Daniel Hilgarth Feb 20 '13 at 13:12
  • Well actually you can create a dynamic assembly with the new type, but C# doesn't provide the facilities to edit the IL. I saw one or two products that do, but still it would be external components. By the way I don't need something so sophisticated, 'just' programmatically editing the source in a pre-compiling phase would do, but I am not sure there is something like that. Macros could also shorten the work, but those too are not supported. – lunadir Feb 20 '13 at 13:30
  • @lunadir: How would all of this help you in intercepting calls to `ServiceBase.Run`? – Daniel Hilgarth Feb 20 '13 at 13:31
  • It depends on the implementation. If the ServiceBase called with Run is a proxy, then the OnStart method should be logged because it should be wrapped by [A]SyncProcessMessage. In the case of code transformation I would accept even a static way to tell that that is a method call (in the end I would have to do it for a limited number of objects), but it needs to be separated from the source code, or else it would be a mess. – lunadir Feb 20 '13 at 13:37
  • @lunadir: So you don't actually want to intercept `ServiceBase.Run` itself? You only want to intercept `OnStart` etc in your own class? – Daniel Hilgarth Feb 20 '13 at 13:42
  • If I could intercept `ServiceBase.Run` I would, I mean, I log all that I can, but in the specific case of the TransparentProxy by ContextBoundObject way I doubt it's easily feasible. I'm starting to understand why classes like ServiceBase have not the "possibility" to be proxied, and I'm happy of what I've achieved until now, but it would be more useful to me to log the calls to that class too. – lunadir Feb 20 '13 at 14:09
0

Experimenting with proxies I found a way that apparently logs explicit calls.
Essentially I create a RealProxy like in example in the msdn, then obtain the TransparentProxy and use that as the normal object.
The logging is done in the Invoke method overridden in the customized RealProxy class.

static void Main(){
...
    var ServiceClassProxy=new ServiceRealProxy(typeof(AServiceBaseClass),new object[]{/*args*/});
    aServiceInstance=(AServiceBaseClass)ServiceClassProxy.GetTransparentProxy();
    ServiceBase.Run(aServiceInstance);
...
}

In the proxy class the Invoke will be done like this:

class ServiceRealProxy:RealProxy{
...
    [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
    public override IMessage Invoke(IMessage myIMessage){
        // remember to set the "__Uri" property you get in the constructor
    ...
        /* logging before */
        myReturnMessage = ChannelServices.SyncDispatchMessage(myIMessage);
        /* logging after */
    ...
        return myReturnMessage;

        // it could be useful making a switch for all the derived types from IMessage; I see 18 of them, from
        // System.Runtime.Remoting.Messaging.ConstructionCall
        // ... to
        // System.Runtime.Remoting.Messaging.TransitionCall
    }
...
}

I have still to investigate extensively, but the logging happened. This isn't an answer to my original problem because I have still to test this on classes that don't inherit from MarshalByRefObject.

lunadir
  • 339
  • 3
  • 15