If you want to apply custom rewriting it is important to override the target files in the obj folder.
This is crucial as msbuild copies those files from here.
See my answer HERE
In my example i use PostSharp in addition to my rewriting task.
But this is no problem for your case:
<PropertyGroup>
<CompileDependsOn>
$(CompileDependsOn);
ApplyILRewriting
</CompileDependsOn>
<BuildDependsOn>
$(BuildDependsOn);
AfterILRewritingPostBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="ApplyILRewriting">
<ILTransformationTask IntermediateAssemblyPath="$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFileName)" />
</Target>
<!-- Override this target in another file. Build your nuget packages here for example. -->
<Target Name="AfterILRewritingPostBuild">
</Target>
The cool part about my solution is, that the code that transforms the assembly is loaded from the target assembly. So you can just implement a interface on a attribute and place the attribute on your target type. It will the run the method on the interface for every attribute applied on a target.
This enables you to have your rewriting instructions in your target assembly meaning that for every project you can easily add your own transformations.
As you can see i pass the path of the assembly in the obj folder.
My solution works like this(i do not want to release the full source at the moment, sorry):
- create pre transform folder in obj folder
- copy all files from obj/ to the folder
- create a post transform folder
- copy all files from obj/ to the folder
- inspect types using reflection:
- load referenced assemblies of your output assembly
- filter attribute types inheriting ITransformation interface
- find types that have those attribute types applied
- Load the matching assemblies and types using cecil from the post transform dir
- execute the Transform(reflectionDeclaringType, cecilDeclaringTypeDefinition) method on the attributes that you reflected on the types; This is the point where your custom cecil code applies the rewriting using the ITransformation interface
I also created another interface to apply a transformation not to a single type but rather to the whole assembly.
So i ended up having ITypeTransformation and IAssemblyTranformation. One scoped to the assembly and also only passing reflection and cecil assembly. The ITypeTransformation passes reflection, cecil assembly and reflection, cecil type
A example for a transformation could be:
public class TestTypeTransformation : Attribute, ITypeTransformationAttribute
{
public void ApplyTransformation(
Assembly preTransformationReflectionAssembly,
AssemblyDefinition postTransformationCecilAssembly,
Type reflectionType,
TypeDefinition cecilType)
{
// Your custom rewriting here
}
}