How to use T4 and Visual Studio to Extend a Partial Class - t4

I wanted to use T4 to generate properties for a partial class. I'm running into a configuration problem where my .TT file is in the same project as the class file I want to extend. So if I have to include the assembly in the .TT file it get's locked. I tried to do a command line in the pre-build but the problem there is that VS always wants to recompile the .TT file with the project.
The only solution I can think of is to rename the .tt files to say .t4 and then use a pre-build command with TextTransform -out to create the .cs file in the project directory.
Can anyone think of a cleaner way to do this?

Assuming that locking is caused by your template using Reflection to read metadata of the partial class you need to extend, you could solve the locking problem if you use CodeModel. This API is provided by Visual Studio and allows you to get the metadata directly from the source file, without the need to compile the partial class or load the compiled DLL. Here is an example of a T4 code generator that uses this approach: http://www.olegsych.com/2008/07/t4-template-for-generating-sql-view-from-csharp-enumeration

Related

Correct way to use multiple .IDL (MIDL) files within a single "Windows Runtime Component C++/WinRT" project

Visual Studio 2019. Windows Runtime Component C++/WinRT project.
How do I follow and implement the recommendation: "We recommend that you declare each runtime class in its own Interface Definition Language (IDL) (.idl) file, in order to optimize build performance when you edit an IDL file, and for logical correspondence of an IDL file to its generated source code files. Visual Studio merges all of the resulting .winmd files into a single file with the same name as the root namespace. That final .winmd file will be the one that the consumers of your component will reference."
https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/author-apis
Within the same project I can add a second (third and so on) .IDL file using Project->Add New Item->Midl File (.idl). This seems to work ok?! I then manually add associated .h and .cpp files for each .IDL file. Build to generate stub files then manually copy and "fill in" these files before a final build which is successful. In this way I have a single IDL file per runtime class with its associated headers and implementation files including any other files (c++ .h and .cpp files) needed for the implementation. As I need to add functionality to the interface I just edit the IDL file, rebuild and add functionality to the header and implementation C++ files.
Is this what was recommended?!?
When I add the .IDL file and then manually add an associated .h and .cpp they do not appear "under" the .IDL file as the original ones did when I created the new project. Is this just a visual nicety of Solution Explorer OR is this indicating that I have something wrong?!?
I plan to have multiple "C++/WinRT WRC" projects (one for each namespace, each consisting of multiple runtimeclass interfaces with separate .IDL/.h/.cpp files as described above. Then I reference all of the projects (project to project) in my single C#/UWP App.
I am actually trying to implement a user interface to allow me to utilise a large code base of math/engineering C++ classes that implement a very specific & proprietary type of electronic circuit simulation already existing and programmed in C++ and compiled as a console app. The user data in and out is relatively small compared to the processing that takes place to generate the output.
It looks like you are handling the idl files correctly and that behavior is the same as I experienced when just adding a new Midl file directly.
If you like the look of having the .h and .cpp files "under" the .idl file in the tree you can try adding a new View Model instead of a new Midl file. This will create the .idl/.h/.cpp files all with the same name and place the .h and .cpp files visually under the Midl file. The idl template you get this way is for a basic runtime class.
When creating a new Windows Runtime Component, the .idl and the .h are usually grouped under the .cpp, not the .idl, but whatever your preference. There isn't a template to add a Runtime Class, which is pretty dumb. One fix for this could be as follows:
This is not a perfect solution, but is the easiest. Create a new Windows Runtime Component. Open Project>Export Template. Select Export Item. Select the Runtime Class under the new component. Export with Automatic Import option checked. Save your project and exit VS. Open your project. You can now add a fully templated Windows Runtime Class by simply adding item>Runtime Class. However, there will still be no dependencies (there may be a tool for custom nesting, but not in community as far as I can see). To fix this, after adding the files, save the project. Edit the project file (use notepad++ or even unload project, edit) and add the property <DependentUpon>Runtime Class.idl</DependentUpon> between your .cpp and .h file delimiters. Save the project file and reload. Probably want to do this in batches.
The alternative is to write a .vsix to either add the files and edit the project file, or have a right click command that runs on a .cpp and edits the project file, adding the DependentUpon directive. I can't find a 2022 functional .vsix for this. I will post one if I make one.

How can we get the T4 template to generate code based on a .cs file that the user is editing?

I'm trying to create a T4 template that will save our developers from creating a lot of boilerplate code that's necessary in our framework. Let's say the developer creates an interface and marks it with our custom attribute. I would like it so that any interface marked with that custom attribute is enhanced by additional methods, which means my T4 template would have to generate partial classes on the fly. However, I would like it so that this automatic generation happens on the fly and seamlessly, preferably when the internal automatic compilation that's used for intellisense happens. You know how when you create a new class in Visual Studio and you switch to another source file and start using that class you didn't have to save or compile it, Intellisense was able to see the new class you created right away? I'd like the same automatic behavior with the code generated from my T4 template. Any thoughts?
You cannot do what you want to do easily, but here are some options ordered from easiest to most likely what you want (hardest).
Create code
snippets
Create a Visual Studio Item Template
Use Castle DynamicProxy to create the extra bits at run time.
Create a separate project to hold the T4 generated classes as described in my answer here
As a pre-step to your project build (modify .csproj file to do this), you can compile the source code from which you want to generated code and then reflect on that, generate the code and then add it to the project before the real compile step. This is what the MSR Orleans project does. You can read their source code here. This is really cool! :-)

How do I modify the template that reference.cs is generated from?

I've been searching on the web for this, and maybe I'm just using the wrong keywords or something? I could use some help.
My problem is simple - we have a bunch of reference.cs files in our solution, which were auto-generated by VS2010 when adding services. These files don't add XML comments by default, so when we build the project, I get 800 or so messages in the build list. This doesn't break anything, but it does make the build take (significantly) longer, and mucks up the output screen.
I "fixed" this by adding the appropriate #pragma statments to the beginning and end of each reference.cs file, but if those ever get regenerated, they will have to be re-added by hand. I'd like to streamline that process and just add them to whatever T4 template VS2010 is using in the first place. The problem is, I don't know where that is, or if VS2010 is using something else to build these files?
Can this be done? Is there a better solution? I don't necessarily want to turn off XML comments for the entire project.
Visual Studio does not use T4 templates to generate the service reference proxy classes (Reference.cs). Instead Visual Studio is most likely using the WsdlImporter and ServiceContractGenerator classes to generate this code.
There is a stackoverflow post on using either a custom wsdl exporter or WCFExtras to add xml comments to the generated code. Both of these assume you have access to the code for the services you are referencing.

t4 templates per template TransformOnBuild setting

I would like to automatically execute one of the .tt files when my project is built, but not the others. Is it possible to set the TransformOnBuild property on specific .tt files instead of project wide? Or another method to accomplish this?
I have decided to add a custom pre build step to generate the .tt files needed:
<Exec Command=""%PROGRAMFILES(x86)%\Common Files\microsoft shared\TextTemplating\10.0\TextTransform.exe" template.tt -out template.cs" />
This method also allowed me to easily pass parameters (defined in the project file) to the template with -a; another problem I was facing.
Answering as another method to accomplish this.
You could change your .tt as TextTemplatingFilePreprocessor
(descibed better here:
http://www.olegsych.com/2009/09/t4-preprocessed-text-templates/).
Create small command line tool that executes the preprocessor on pre-build event.
The first link includes this example, but it describes the use of preprocessed class:
http://blogs.clariusconsulting.net/pga/vs10-beta-1-t4-preprocessing-part-2/

Run a Visual Studio custom tool at build time

I have a script that will convert a text file into a resource file, so that I can have multiple language support by having text files for different languages converted into different resources. Once I run the script to get the resx file, I then have to run a custom build tool (as described here:Link to Code Project) in order to create the Designer.cs files to use the new files.
In keeping with the philosophy that I should be able to build the entire project with a single button click, how can I remove the step where I have to explicitly call the custom build tool in order to make the codebehind files?
I've tried automatically deleting the Designer.cs files as a pre-build step, since I would think that the custom build tool would automatically run if there were no Designer.cs files, but no dice.
So, I want my build script in Visual Studio/msbuild to do:
1) convert text to resx (done)
2) move resx files to appropriate directory (done)
3) create designer.cs files using a custom build tool (not done)
It's that last step...
Unfortunately I don't think there's an easy way of doing this. Custom Build Tools only run from within VS.NET - they don't run when you build your project using MSBuild from the command line.
In general, if you have the choice of writing a build tool as a Customer Build Tool or an MSBuild Task then choose the MSBuild Task every time as these Tasks will run in VS.NET and from the command line.
The designer.cs files for resources are there to support your coding. They give you the strongly typed access into the resource file. So, as long as you create your culture invariant resources in VS.NET (and let it create the .designer.cs files) then adding additional language support later (additional .resx files) should work fine.
If, however, your text files are your primary resource files, and you're adding new resource strings into these text files first, then you'll need to find another way of generating .cs files that allow you to code against those resources. If you HAD to, generating the .designer.cs file yourself (or somethign similar) wouldn't be that difficult. Using CodeDom or T4 you could create the helper class, using an existing .designer.cs file as a template.
There is a way to generate the *.Designer.cs for *.resx as part of the build process. There is a built-in MSBuild task GenerateResource, which basically a wrapper around the SDK tool resgen.exe. Here you can find an example how to use it.
Another thing you would find useful, if the generated *.Designer.cs version is not correct, basically, GenerateResource task is not calling the desired version of resgen.exe, setting property SdkToolsPath might help you.
Have you tried adding a Exec step in Before/AfterBuild step in your csproj? You have to manually edit the file for this, but that should solve your problem.
I'm not fully clear on if you want this done before or after the build. If you need it done sometime after Pass1/Pass2, you can hook into the targets directly. Try looking into Microsoft.Build.Common.Targets to get a feel for how to do this.

Resources