4

I have some functions for which I want to log time consumed in them.

DBResult LongTask(DBCommand command)
{
   ...
}

Is there a way to attchieve this

[LogTimeUsed()]
DBResult LongTask(DBCommand command)
{
   ...
}

So that I can have class/function somewhere which gets called every time when this function is called and I can inject my own code, get access to command and DBResult and log time spent in function?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
0xDEAD BEEF
  • 2,074
  • 7
  • 31
  • 46

6 Answers6

4

There is no built in way to do this in .NET.

If your wish is not to use any 3rd party libraries (as you said in one of your comments), doing code weaving or dynamic proxy generation is a lot of work. In that case it's better to step away from using attributes and go with the decorator design pattern. Here's an example:

// Define an interface for the operation
public interface IMyLongRunningTask
{
    DBResult longTask(DBCommand command);
}

// Define an implementation for the operation:
public class MyLongRunningTask : IMyLongRunningTask
{
    public DBResult longTask(DBCommand command)
    {
        // code here
    }
}

And now you can write a decorator for the IMyLongRunningTask:

public class MyLongRunningTaskMonitor : IMyLongRunningTask
{
    private readonly IMyLongRunningTask wrappedService;
    private readonly ILogger logger;

    public MyLongRunningTaskMonitor(IMyLongRunningTask wrapped,
        ILogger logger)
    {
        this.wrappedService = wrapped;
        this.logger = logger;
    }

    public DBResult longTask(DBCommand command)
    {
        var watch = Stopwatch.CreateNew();

        var result = this.wrappedService.longTask(command);

        this.logger.Log("longTask executed in " + 
            watch.ElapsedMilliseconds + " ms.");

        return result;
    }
}

When you use dependency injection, you can easily configure an MyLongRunningTaskMonitor to be returned when an IMyLongRunningTask is requested. For instance:

container.Register<IMyLongRunningTask>(() =>
    new MyLongRunningTaskMonitor(
        container.GetInstance<MyLongRunningTask>(),
        container.GetInstance<ILogger>()
    )
);
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Oh. But this approach forces me to use "specific" syntax, when creating class instances. – 0xDEAD BEEF Mar 10 '11 at 12:35
  • 1
    Using the Dependency Injection pattern forces you in a specific direction (because that's what patterns do). DI/IoC frameworks each have their own 'language' for configuring this dependency wiring. When you use the DI pattern correctly, you can keep all your code (except the startup code) of your application free of this wiring. – Steven Mar 10 '11 at 13:20
2

You could use Castle DynamicProxy.

DynamicProxy generates proxies for your objects that you can use to transparently add or alter behavior to them, provide pre/post processing and many other things.

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • How do I do this myself? I don't want to use 3rd party classes/software. How do I create this decorator? Is this thing called proxy? How do I write my own proxy? – 0xDEAD BEEF Mar 09 '11 at 10:18
  • 3
    Why do you want to write it yourself? There's little point in reinventing the wheel. - You can always get the Castle source code and see how they've done it - it's open source. – Jakub Konecki Mar 09 '11 at 10:52
0

Just to add to the list of third party stuff out there is spring AOP (Spring is large and popular framework that has been ported to .net from Java)

http://www.springframework.net/doc-latest/reference/html/aop.html

andrew pate
  • 3,833
  • 36
  • 28
0

The question is looking for a way to create a decorator in c# by using c# attributes, to attempt to create the decorator syntax as seen in python (which is excellent... C# community take note)

Something similar could be acheived by embedding the 'attribute' in your method name (e.g. LongTask_LogTimeUsed) then have a small amount of (boilerplate) code INSIDE the LongTask method that reads its method name delegating the pre or post processing off to appropriate handlers:

How to get the name of the current method from code

How to get passed in parameters over to the pre or post processors would need thinking about though.

andrew pate
  • 3,833
  • 36
  • 28
  • For C# developer decorating method names is out of the question. Whole idea about decorations is to make it invisible to outside. C# developer would then create proxy class and wrap calls. But idea was to use attributes for that. It seems that there are no other options but to use code generators and dependency injection to accomplish this. – 0xDEAD BEEF Nov 28 '17 at 08:47
0

If you're not handling that particular type of attribute yourself, you should look into Aspect Orientated Programming, using something like PostSharp

Matthew Abbott
  • 60,571
  • 9
  • 104
  • 129
0

You can do this using PostSharp

Also check the answer to my question on SO - Aspect Oriented Logging with Unity\T4\anything else

Community
  • 1
  • 1
Unmesh Kondolikar
  • 9,256
  • 4
  • 38
  • 51