I'm interested in measuring the time it takes to execute particular methods.
I was thinking it would be really convenient to do this using a Custom Attribute instead of littering methods with code to start/stop stopwatch and sending to logger. If I could decorate the method in question using an attribute, that'd be really convenient!
I was able to create a Custom Attribute following this article: https://docs.microsoft.com/en-us/dotnet/standard/attributes/writing-custom-attributes
Like so:
public class MonitorExecutionTime : Attribute
{
private Stopwatch measureExecution;
// Start measuring on instantiation
public MonitorExecutionTime()
{
measureExecution = new Stopwatch();
measureExecution.Start();
}
// how do I hook into end invoke?
public MethodHasEnded()
{
measureExecution.Stop();
TimeSpan timeSpan = measureExecution.Elapsed;
Console.WriteLine("Time: {0}h {1}m {2}s {3}ms", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds);
}
}
But I'm not sure how to "capture" the being invoke and end invoke points of execution in order to Start the stopwatch and Stop the stopwatch (to measure the time and log it).
Has anyone took this approach in a .net core app? Thanks in advance for any pointers!
We can calculate the execution time of the code using StartNew() and Stop() methods. StartNew() method comes under the Stopwatch class and it basically used to initialize a new Stopwatch instance. Internally it marks the elapsed time property equal to zero and then it starts measuring the elapsed time.
If milliseconds then in Visual Studio 2019 you can see the time between two breakpoints under Diagnostic Tools -> Events -> Duration (opens automatically in Debug mode, or use Ctrl + Alt + F2 ).
Attributes aren't called in runtime. But you can use library like Fody for assembly weaving - to add code automatically after your assembly is compiled into method marked with your custom attribute.
In fact, there is already an implementation like what you want to achieve - Method Timer
Here is how it works (copy/paste from documentation). Your code:
public class MyClass
{
[Time]
public void MyMethod()
{
//Some code u are curious how long it takes
Console.WriteLine("Hello");
}
}
What is actually compiled into final assembly
public class MyClass
{
public void MyMethod()
{
var stopwatch = Stopwatch.StartNew();
try
{
//Some code u are curious how long it takes
Console.WriteLine("Hello");
}
finally
{
stopwatch.Stop();
Trace.WriteLine("MyClass.MyMethod " + stopwatch.ElapsedMilliseconds + "ms");
}
}
}
You can write your custom interceptor code to avoid using Trace.WriteLine and do logging the way you want it.
Attributes in .NET are not wrappers, so you can't use them in that way. You must use a method call wrapper, for example:
public class Service : IService
{
public void Exec() {
Wrap("Method Exec", () => {
// do something usefull
});
}
private void Wrap(string message, Action action)
{
var watch = Stopwatch.StartNew();
try
{
action();
}
finally
{
watch.Stop();
Console.WriteLine($"{message} executed in {watch.ElapsedMilliseconds} ms");
}
}
}
If you want to wrap all methods of class or interface, you should look at aspect-oriented programming, for example in this article: https://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/
@Igore-goyda - your post sent me along the path to what I needed. In summary for others - there are two ways to intercept methods and run some custom processing. Either via a proxy or using an IL rewriter.
I found this article excellent at explaining: http://jeffbelback.me/posts/2015/06/01/principles-of-aop/
I decided the Proxy method would work best for me (didn't like the notion of my code being modified after compilation), and was able to implement a suitable solution using Autofac following this article: https://nearsoft.com/blog/aspect-oriented-programming-aop-in-net-core-and-c-using-autofac-and-dynamicproxy/
The Autofac documentation also helped me out: https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html?highlight=proxy
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With