CallerMemberName: Your New Best Friend for Logging in C#

As I mentioned in my last post, I recently re-wrote the website and blog engine for my website. As part of that project and a different project of mine, I've been writing a lot of library code for CosmosDb and ASP.NET Core lately. One of the big things that I wanted was an easy way to log CosmosDb query details and ASP.NET Core MVC page request details.

I don't know about you but I've always found getting my logging code right to be kind of a tedious and messy process with a lot of hard-coded string values. Typically, those hard-coded strings are the "source" values for the log messages -- which class and which method is making the log call.

public class MyClass
{
  public void DoSomething() 
  {
    logger.WriteToLog("MyClass.DoSomething()", "did something");   
  }
}

You can make these calls a little more streamlined by using nameof but that only gets you so far. I wanted something a little more "automagical."

CallerMemberName Attribute
That "automagical" thing that I discovered is the CallerMemberName attribute. The method below is a utility method in CosmosRepository that creates a description for a query that runs against CosmosDb. Notice that the methodName parameter has a default value of empty string -- so if you call this method, you don't have to pass any value for methodName. But that parameter also has the CallerMemberName attribute attached to it, so when this method gets called, the compiler automatically drops in the name of the caller.

[Click on image for larger view.]

So lets say that you have the following code:

public class MyClass : CosmosRepository
{
  public void DoSomething() 
  {
    // calls GetQueryDescription()
 		logger.WriteToLog("MyClass.DoSomething()", GetQueryDescription());   
  }
}

When the logger.WriteToLog() line gets executed, it passes the value returned from GetQueryDescription() as the log message! I think that's unbelievably cool!

A Little Side-Note About CallerMemberName
As a disclaimer, I've been writing using C# for a long, long time. Decades. And when I discovered this attribute, I figured it was something new that had only recently been introduced.

Nope. Not new at all.

CallerMemberName was introduced as part of .NET Framework 4.5 in 2012. When .NET Core 1.0 dropped in 2016, it was there on the first day. I literally had never heard of this before and it blew my mind that I'd never known about it.

Getting Fancier (and Lazy-er) with Extension Methods
So using that attribute saved me from having to supply one parameter value. When I started adding logging to my website's content management system (CMS), I wanted to log things like page view, blog post views, and errors. Those calls were super repetitive and I wanted to see if I could get even more streamlined (read: lazy).

All of my controller classes extend from a common abstract base class named CmsControllerBase. One of the key features of CmsControllerBase is hanging on to a repository class for writing HTTP traffic information to CosmosDb, and that repository is exposed as protected ITrafficLogRepository TrafficLogRepository.

[Click on image for larger view.]

The upside of this is that I can create a C# extension method for the logging calls and those logging calls will have access to the controller. The extension method below is for logging HTTP 404 Not Found results. It takes the calling controller as an argument via this CmsControllerBase controller. It also takes the calling method name that uses CallerMemberName.

[Click on image for larger view.]

Then in my controller code, that means that logging an HTTP Not Found is just a matter of one empty method call (see below).

[Click on image for larger view.]

This wasn't the only extension method for logging. I also created utility extension methods for recording successful web traffic (HTTP 200), bad requests (HTTP 400), and errors (HTTP 500).

[Click on image for larger view.]

Once I had these, adding the logging calls was a simple matter of pasting in a bunch of single-line method calls without having to fiddle with any argument values.

Summary
If you're looking to simplify your logging calls, the CallerMemberName attribute is a powerful tool that can save you a lot of time and effort. By automatically inserting the name of the calling method, it eliminates the need for hard-coded strings and reduces the risk of errors. This attribute is especially useful for creating more maintainable and readable code, making your logging process more efficient and less prone to mistakes. Give it a try and see how it can streamline your logging practices.

About the Author

Benjamin Day is a consultant, trainer and author specializing in software development, project management and leadership.

Posted by Benjamin Day on 01/21/2025


Keep Up-to-Date with Visual Studio Live!

Email address*Country*