I think it was mentioned in a recent stream with Mads Torgerson that there is a proposal to add a [CallerMemberInfo] attribute which would work the same as [CallerMemberName], but would allow you to recieve a MemberInfo instead of a string. Personally I think that would make the entire "caller" family complete, and would also act as a more reasonable alternative to the proposed infoof expression.
I've used all except CallerArgumentExpression. One of the more useful things I did was inject the Caller, File, and Line number into the logger scope at the start of methods, making debugging from logs much easier, especially if you're looking at logs that don't have stack trace.
CallerMemberName is useful if you are making an INotifyPropertyChanged implementation that handles multiple properties. You can have your property setters call a private helper method that has a CallerMemberName and use this to access the property name that was modified easily, so you can add it to the EventArgs.
Why not simply use an MVVM framework, caliburn prism or whatever and the PropertyChanged nuget. Completely remove them from code and implement them via some form of precompilation on classes that implement INotifyPropertyChanged. INotifyPropertyChanged and much of the WPFish stuff is just boilerplate you don't want to deal with. Use auto properties and if you need to do something override the created methods.
Great video. I’ve been a fan of the caller member attributes for enhancing error log details for some time. I didn’t know about that feature to capture the input arguments. Very cool and thank you for sharing.
Thank you for the video. It was very helpful. These features look really handy if you're implementing deeper diagnostic logging for your code. For example, I needed to do this for a shared library I was working on. I needed to log information about what modules and classes called it, as well as the arguments it was called with, so that I could log parameters and results and have an idea about how people were using the library. This way, we could have a statistics report at the end of the day. I had to use a lot of reflection and do a lot of string parsing of the Current StackTrace, but it still wasn't enough. I had to add extra parameters to my methods so developers could pass more information. If these features were available back then, it would have been a lot of use to me.
I can see a good use for the last two. Sometimes you cannot attach a debugger (maybe it's running at a customer's location) and to debug where something is happening, you sprinkle a lot of logging in the code. This would allow you to write a static LogDebug message that automatically knows the filename and line of where it's called and include that in the log message.
We usually like to enrich logging with custom fields and they way we are doing it with ILogger - I believe these attributes are not as useful because there will be a number of methods in stack trace between ilogger call and actual logging handler
I use CallerMemberName, CallerFilePath and CallerLineNumber in a generic logging helper class that I reuse in projects which basically just contains wrappers for the Serilog Information, Warn, Error etc functions, which prepends the file/member/line number at the beginning of the message, so I can see where in the code the log was created from. For the file path, I'm using Path.GetFileNameWithoutExtension() so as to just keep the filename so logs arent cluttered with the full path. I did not know about the new Argument one, it's interesting but not sure when I'd use it.
I’m curious what happens if you mix and match languages with the argument one - like you call from VB, passing in a lambda to a C# method. I guess that’s something to try later.
These attributes are a great addition but still very situational. For example, they can not work with params constructs, and this really breaks their usage in most logging methods, unless you are using string interpolation in your message.
Very fascinating stuff! Question: is there an attribute that can get all of the caller values for all of the arguments when there is more than one without having to individually add a argument for each new one?
If you will call Example() methods from several another methods, each compilation result will call Example() with it name. Test1() => Example("Test1") Test2() => Example("Test2")
Hi,great video. can you do a session on model validation performance in webapi world? Always curious if fluent validation is faster or slower than the default validation attributes?
I use CallerMemberName the most, its really handy for implementing IPropertyChanged. CallerFileName and line number can be really useful for error logging.
Hi nick thanks a lot for yours courses and videos ... Can you please make a course for mongoDB and dynamic DTO to validate dynamic forms or dynamic JSON
I feel like this feature could be used to exploit vulnerabilities in calling code when implemented in a library. The library uses this feature to find the names of methods in code that calls it, and uses this to seek out exploits by brute force calling those methods using reflection...
Oh wow, the expression one is even worse. A library could extract all sorts of sensitive data that whoever wrote the calling code thought the library wouldn't have access to because it's being evaluated before being passed in! Yikes!
@@EdKolis putting your salt in... right as a string there... anyone could get that out of your source with reflector, dotPeek, ilDasm. And really... that goes for all of your code. It really is a non-issue at that point.
Installing a malicious nuget package can already do much worse things than getting some potentially hardcoded string. Like hell, even the dumbest thing - it could literally scan the entire executable on runtime and send all the strings it finds to the attacker. If you're worried about it the actual issue is that you're using a fishy library in the first place, not the feature. It's kind of like worrying that your bathroom lock is too weak to stop a thief. Worry about your front door first.
I think it was mentioned in a recent stream with Mads Torgerson that there is a proposal to add a [CallerMemberInfo] attribute which would work the same as [CallerMemberName], but would allow you to recieve a MemberInfo instead of a string. Personally I think that would make the entire "caller" family complete, and would also act as a more reasonable alternative to the proposed infoof expression.
That would be a great addition.
I've used all except CallerArgumentExpression. One of the more useful things I did was inject the Caller, File, and Line number into the logger scope at the start of methods, making debugging from logs much easier, especially if you're looking at logs that don't have stack trace.
hi! do you have a sample on how to do that? was looking for it myself :-)
@@jptouron3080
public static class LoggingExtensions
{
public static IDisposable? AddCallerScope(this ILogger logger, string memberName = "", string filePath = "",
long lineNumber = 0, [CallerMemberName] string methodName = "", [CallerLineNumber] long logScopeLineNumber = 0)
{
return logger.BeginScope("{callerMember}, {callerPath}:{callerLine} -> {method}:{lineNumber}",
memberName, filePath, lineNumber, methodName, logScopeLineNumber);
}
}
then simply use like this:
public void SomeMethod(int methodArgument, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] long lineNumber = 0)
{
using var logScope = _logger.AddCallerScope(memberName, filePath, lineNumber);
.........
Merry Christmas, Nick! You’re doing awesome work with this channel!
CallerMemberName is useful if you are making an INotifyPropertyChanged implementation that handles multiple properties. You can have your property setters call a private helper method that has a CallerMemberName and use this to access the property name that was modified easily, so you can add it to the EventArgs.
Why not simply use an MVVM framework, caliburn prism or whatever and the PropertyChanged nuget. Completely remove them from code and implement them via some form of precompilation on classes that implement INotifyPropertyChanged. INotifyPropertyChanged and much of the WPFish stuff is just boilerplate you don't want to deal with. Use auto properties and if you need to do something override the created methods.
I love the caller attributes, i use them whenever i can. But argument expressions was new for me, so thanks for sharing.
One of the important things is getting the type of the returned value of the expression
Great video. I’ve been a fan of the caller member attributes for enhancing error log details for some time. I didn’t know about that feature to capture the input arguments. Very cool and thank you for sharing.
6:16 I was going to call you out on the use of nameof for number, but of course you had it!
Thank you for the video. It was very helpful. These features look really handy if you're implementing deeper diagnostic logging for your code. For example, I needed to do this for a shared library I was working on. I needed to log information about what modules and classes called it, as well as the arguments it was called with, so that I could log parameters and results and have an idea about how people were using the library. This way, we could have a statistics report at the end of the day. I had to use a lot of reflection and do a lot of string parsing of the Current StackTrace, but it still wasn't enough. I had to add extra parameters to my methods so developers could pass more information. If these features were available back then, it would have been a lot of use to me.
I can see a good use for the last two. Sometimes you cannot attach a debugger (maybe it's running at a customer's location) and to debug where something is happening, you sprinkle a lot of logging in the code. This would allow you to write a static LogDebug message that automatically knows the filename and line of where it's called and include that in the log message.
Hello. Could anybody help me - what is extention are used on 7:10 as IL viewer but with higth level c#?
We usually like to enrich logging with custom fields and they way we are doing it with ILogger - I believe these attributes are not as useful because there will be a number of methods in stack trace between ilogger call and actual logging handler
Is there an c# IL viewer extension for visual studio(not code)? 😤
Have a look at "IL Spy 2022"
And check ILDasm.
This is last example is actually similar to the C++ macro __FILE__ and __LINE__, which can be useful in UTests.
CallerMemberName is used extensively in WPF
Fits perfectly with INotifyProperyChanged.
I use CallerMemberName, CallerFilePath and CallerLineNumber in a generic logging helper class that I reuse in projects which basically just contains wrappers for the Serilog Information, Warn, Error etc functions, which prepends the file/member/line number at the beginning of the message, so I can see where in the code the log was created from. For the file path, I'm using Path.GetFileNameWithoutExtension() so as to just keep the filename so logs arent cluttered with the full path. I did not know about the new Argument one, it's interesting but not sure when I'd use it.
Definitely gonna implement the line number caller in the exception libraries
I’m curious what happens if you mix and match languages with the argument one - like you call from VB, passing in a lambda to a C# method. I guess that’s something to try later.
These attributes are a great addition but still very situational. For example, they can not work with params constructs, and this really breaks their usage in most logging methods, unless you are using string interpolation in your message.
Exactly, which is the problem I'm now running into when setting up Serilog the correct way
Very fascinating stuff! Question: is there an attribute that can get all of the caller values for all of the arguments when there is more than one without having to individually add a argument for each new one?
If you will call Example() methods from several another methods, each compilation result will call Example() with it name.
Test1() => Example("Test1")
Test2() => Example("Test2")
Hi,great video. can you do a session on model validation performance in webapi world? Always curious if fluent validation is faster or slower than the default validation attributes?
this works in unity?
I use CallerMemberName the most, its really handy for implementing IPropertyChanged.
CallerFileName and line number can be really useful for error logging.
Can you get the class name?
Wonderful, it's more on build time rather than compile time.
Would be interesting to get the CallerArgumentExpression as an actual Expression
Thanks
Wish the added new keyword pathof(exp) which would do the same job as nameof but returning full path eg. Foo.Bar.PropName instead of just PropName
AN’T WORK?
Hi nick thanks a lot for yours courses and videos ... Can you please make a course for mongoDB and dynamic DTO to validate dynamic forms or dynamic JSON
I feel like this feature could be used to exploit vulnerabilities in calling code when implemented in a library. The library uses this feature to find the names of methods in code that calls it, and uses this to seek out exploits by brute force calling those methods using reflection...
Oh wow, the expression one is even worse. A library could extract all sorts of sensitive data that whoever wrote the calling code thought the library wouldn't have access to because it's being evaluated before being passed in! Yikes!
e.g. CallLibrary(HashPassword(pword, "secretsalt")); exposes the salt
@@EdKolis putting your salt in... right as a string there... anyone could get that out of your source with reflector, dotPeek, ilDasm. And really... that goes for all of your code. It really is a non-issue at that point.
Unless you put secrets in your version control, This isn't an issue at all.
Installing a malicious nuget package can already do much worse things than getting some potentially hardcoded string.
Like hell, even the dumbest thing - it could literally scan the entire executable on runtime and send all the strings it finds to the attacker.
If you're worried about it the actual issue is that you're using a fishy library in the first place, not the feature.
It's kind of like worrying that your bathroom lock is too weak to stop a thief. Worry about your front door first.
First
First