The code is not so much different from SkinnyControllers : Implement ISourceGenerator , putting the Generator attribute on the class
[Generator]
public partial class AutoActionsGenerator : ISourceGenerator
inspecting the classes if they have the common attribute , generating code with Scriban
The problem was : How can the AOPMethods can
- differentiate between the private function that must be made public
- generate the code for a similar public function, with same parameters (and maybe more) , but with different name ?
So I decide to go the route of convention: The programmer will declare the private function that he wants to autmatically make public ( and add templating code ) with a prefix or a suffix . This will be declared into the attribute of the class – and that will be all.
For example , I have this method
public string FullName()
{
return FirstName + ” ” + LastName;
}
That I want to monitor ( add logs, info and so on ) . I will make it private and start with pub
private string pubFullName()
{
return FirstName + ” ” + LastName;
}
Then , on the class , I will declare the pub prefix
[AutoMethods(template = TemplateMethod.CallerAtttributes, MethodPrefix =”pub”, MethodSuffix =”bup”)]
And the following will be generated
public string FullName(
[CallerMemberName] string memberName = “”,
[CallerFilePath] string sourceFilePath = “”,
[CallerLineNumber] int sourceLineNumber = 0)
{
try
{
Console.WriteLine(“–pubFullName start “);
Console.WriteLine(“called class :” + memberName);
Console.WriteLine(“called file :” + sourceFilePath);
Console.WriteLine(“called line :” + sourceLineNumber);
return
pubFullName();
}
catch (Exception ex)
{
Console.WriteLine(“error in pubFullName:” + ex.Message);
throw;
}
finally
{
Console.WriteLine(“——–pubFullName end”);
}
}
The caller attributes templates can be found at AOP_With_Roslyn\AOPMethods\AOPMethods\templates\CallerAtttributes.txt
//——————————————————————————
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//——————————————————————————
using System;
using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;
namespace {{NamespaceName}} {
/// <summary>
/// Generates code from {{ClassName}}
/// </summary>
[GeneratedCode(“AOPMethods”, “{{version}}”)]
[CompilerGenerated]
partial class {{ClassName}}{
/*
public int id(){
System.Diagnostics.Debugger.Break();
return 1;
}
*/
{{~ for mi in Methods ~}}
{{
separator = “”
if(mi.NrParameters > 0)
separator = “,”
end
strAwait = “”
strAsync =””
if mi.IsAsync == true
strAwait = ” await “
strAsync = ” async “
end
}}
public {{strAsync}} {{mi.ReturnType}} {{mi.NewName}} ({{mi.parametersDefinitionCSharp }} {{separator}}
[CallerMemberName] string memberName = “”,
[CallerFilePath] string sourceFilePath = “”,
[CallerLineNumber] int sourceLineNumber = 0){
try{
Console.WriteLine(“–{{mi.Name}} start “);
Console.WriteLine(“called class :”+memberName );
Console.WriteLine(“called file :”+sourceFilePath );
Console.WriteLine(“called line :”+sourceLineNumber );
{{
if mi.ReturnsVoid == false
}}
return
{{
end
}}
{{ strAwait }}
{{mi.Name}}({{ mi.parametersCallCSharp }});
}
catch(Exception ex){
Console.WriteLine(“error in {{mi.Name}}:” + ex.Message);
throw;
}
finally{
Console.WriteLine(“——–{{mi.Name}} end”);
}
}
{{~ end ~}}
}
}
You can add logging , security, anything else that is a vertical to the business