Return to site

Visual Studio For Mac T4 Template

broken image


Visual Studio for Mac.NET. T4 Template in VS2017 using FxCop.Sdk namespace does not work. Visual studio visual studio 2017 version 15.9 windows 10.0. Alberto Salinas reported Jun 25, 2019 at 07:38 AM. Show comments 5. The EnvDTE assembly is only available to T4 templates on Windows with Visual Studio since it provides access to the Visual Studio object model. In Xamarin Studio a T4 template will generate a single file. It is not possible to run a T4 template and make arbitrary changes to the project.

Several years ago I published a series of articles on how to use T4 to generate code. As part of that series I showed how you can, at build time, get Visual Studio to run environmental transforms on any project. To get this to work we relied on a custom .targets file being installed. The .targets file was installed as part of a Visual Studio extension that also installed the T4 templates. As newer versions of Visual Studio have been released the extension has been updated through Visual Studio 2017.

  • Xamarin Studio will automatically compile and execute the T4 file whenever it's saved, as long as the 'Custom tool' property is set to 'TextTemplatingFileGenerator'. This property is set automatically if you create the file with File - New File - Text Templating - T4 Template. See this blog post. There's also support for preprocessed T4.
  • Process your T4 files right from Visual Studio Code. We had been missing this feature of parsing T4 template to easily generate code from VS Code. T4 template parser is a text transformation utility created by Microsoft and has been available in Visual Studio since 2008.

This process still works but as you start moving to build servers in the cloud or that don't have Visual Studio installed you cannot rely on extensions being available. This article will discuss the process of moving the transform process to a NuGet package that can be used in any build system. This is consistent with how popular packages are now injecting .targets files into the build process as well and reduces the dependencies needed to build a solution.

Who This Isn't For

If you are using Azure or another cloud provider then please note that they generally provide a cloud-specific approach to storing per-environment settings. You may not need to use config transforms anymore. There are plusses and minuses to transforms. On the plus side you can ensure at build time that everything is transforming correctly. On the negative side you are exposing your settings to all your developers.

If you are building .NET Core applications then realize that XML-based configs are out and JSON files (options) are in. The configuration system in .NET Core allows you to have per-environment settings files that override specific settings in the base file. You don't need environmental transforms in these environments anymore.

What Is Changing

Visual Studio For Mac T4 Template

The base change that will be made is that the .targets file that is shipped as part of the VS extension needs to move to a NuGet package. The need for a VS extension at build time has to be eliminated. The original solution has several components: item template, config transform files and .targets file. The config transform files containing the transformation rules remain unchanged. You can continue to use them as is.

The item template needs to be adjusted to handle the move from an extension-specific .targets file to a NuGet package. This is a minor change.

The .targets file needs to be moved from the extension to a NuGet package. At the same time we can update the file to rely on a pre-build assembly that contains the transformation logic. This helps resolve issues with trying to get MSBuild to load an assembly from an inline task like we had in previous versions of the extension.

Creating the NuGet Package

To get started we need to create a new class library to hold the transformation task the .targets file will call.

  1. Create a new class library (e.g. P3Net.BuildExtensions.TransformConfigs) targeting .NET 4.6.1.
  2. Copy the TransformXmlFiles.cs file from the old build extension project into the new project.
  3. Fix up the namespace name.
  4. Add NuGet packages for the required MSBuild packages.
  5. Microsoft.Build.Framework
  6. Microsoft.Build.Utilities.Core
  7. Microsoft.Web.Xdt

In the sample implementation I'm using the SDK project format to make things easier. Edit the project file or update it via the UI.

  1. Set the title, description and package tags appropriately.
  2. Set the version of the package. Note: I'm using a directory.build.props to share the versioning across projects.
  3. Set the GeneratePackageOnBuild to true.
  4. Optionally configure the package and publish information.
  5. Set the NuspecFile attribute to the path to the .nuspec file below.

XDT Package Changes

The original version of the code used the Microsoft.Web.Publishing.Tasks.TransformXml task from Microsoft.Web.Publishing.Tasks. But this assembly is not shipped in NuGet so we have switched to Microsoft.Web.Xdt. This required some changes to the TransformXmlFiles task to use the new type. Here are the highlights, the code has the full version.

Defining the NuSpec File

The SDK project format supports generating packages without a .nuspec file. However I was unable to get it to place the .props and .targets files into the correct locations so we are going to use an external file for now.

Packing the Right Files

The .props files are put into the build folder which will cause them to be injected into the build file. The .targets file in the tools folder is part of the tools that will be referenced by the build. To be found at build time the generated DLL needs to be copied to the tools folder. Normally we would do this using a post-build event. The problem is that we're relying on the built in packaging feature of the project system and that runs before post build events. Hence when the package is created the binaries haven't been copied yet. To resolve this we need to copy the files before packing occurs.

As of Visual Studio 2017 15.9 I am unable to get the binary files to appear in the package file. The pack target determines what files to include before the build runs. Because the binaries haven't been built yet it won't recognize them as inputs to Nuspec no matter what I've tried to do. Here's some of the things I've tried.

Copy Binaries During Buld

Currently the PackDependsOn target can be used to run a task before packaging occurs. We just need to add a target that runs before this.

However the pack target determines the files to include before the build step so it won't see these files even if they are there.

Update Package Files Item Group

The pack target uses _PackageFiles to identify the files to include. In theory updating this item group to include the binaries should include them. But I was unable to get the item group to recognize the new files.

Use a wildcard in Nuspec

Nuspec supports wildcards so you can do something like bin***.dll to include binary files. The problem is that the folder structure is rebuilt under the target folder. The binaries have to be at the root for the .targets file to work so the structure would need to be flattened. Unfortunately this isn't supported in the Nuspec file outside content files.

You could also simply hard code the path to the output. For example the following would copy the files correctly.

The downside to this approach is the hard coded configuration and platform information. This is the approach I have gone with.

Use Manual Packaging

The last option is to not use the automated system at all but instead either do it via a post build event or manually.

Studio

The base change that will be made is that the .targets file that is shipped as part of the VS extension needs to move to a NuGet package. The need for a VS extension at build time has to be eliminated. The original solution has several components: item template, config transform files and .targets file. The config transform files containing the transformation rules remain unchanged. You can continue to use them as is.

The item template needs to be adjusted to handle the move from an extension-specific .targets file to a NuGet package. This is a minor change.

The .targets file needs to be moved from the extension to a NuGet package. At the same time we can update the file to rely on a pre-build assembly that contains the transformation logic. This helps resolve issues with trying to get MSBuild to load an assembly from an inline task like we had in previous versions of the extension.

Creating the NuGet Package

To get started we need to create a new class library to hold the transformation task the .targets file will call.

  1. Create a new class library (e.g. P3Net.BuildExtensions.TransformConfigs) targeting .NET 4.6.1.
  2. Copy the TransformXmlFiles.cs file from the old build extension project into the new project.
  3. Fix up the namespace name.
  4. Add NuGet packages for the required MSBuild packages.
  5. Microsoft.Build.Framework
  6. Microsoft.Build.Utilities.Core
  7. Microsoft.Web.Xdt

In the sample implementation I'm using the SDK project format to make things easier. Edit the project file or update it via the UI.

  1. Set the title, description and package tags appropriately.
  2. Set the version of the package. Note: I'm using a directory.build.props to share the versioning across projects.
  3. Set the GeneratePackageOnBuild to true.
  4. Optionally configure the package and publish information.
  5. Set the NuspecFile attribute to the path to the .nuspec file below.

XDT Package Changes

The original version of the code used the Microsoft.Web.Publishing.Tasks.TransformXml task from Microsoft.Web.Publishing.Tasks. But this assembly is not shipped in NuGet so we have switched to Microsoft.Web.Xdt. This required some changes to the TransformXmlFiles task to use the new type. Here are the highlights, the code has the full version.

Defining the NuSpec File

The SDK project format supports generating packages without a .nuspec file. However I was unable to get it to place the .props and .targets files into the correct locations so we are going to use an external file for now.

Packing the Right Files

The .props files are put into the build folder which will cause them to be injected into the build file. The .targets file in the tools folder is part of the tools that will be referenced by the build. To be found at build time the generated DLL needs to be copied to the tools folder. Normally we would do this using a post-build event. The problem is that we're relying on the built in packaging feature of the project system and that runs before post build events. Hence when the package is created the binaries haven't been copied yet. To resolve this we need to copy the files before packing occurs.

As of Visual Studio 2017 15.9 I am unable to get the binary files to appear in the package file. The pack target determines what files to include before the build runs. Because the binaries haven't been built yet it won't recognize them as inputs to Nuspec no matter what I've tried to do. Here's some of the things I've tried.

Copy Binaries During Buld

Currently the PackDependsOn target can be used to run a task before packaging occurs. We just need to add a target that runs before this.

However the pack target determines the files to include before the build step so it won't see these files even if they are there.

Update Package Files Item Group

The pack target uses _PackageFiles to identify the files to include. In theory updating this item group to include the binaries should include them. But I was unable to get the item group to recognize the new files.

Use a wildcard in Nuspec

Nuspec supports wildcards so you can do something like bin***.dll to include binary files. The problem is that the folder structure is rebuilt under the target folder. The binaries have to be at the root for the .targets file to work so the structure would need to be flattened. Unfortunately this isn't supported in the Nuspec file outside content files.

You could also simply hard code the path to the output. For example the following would copy the files correctly.

The downside to this approach is the hard coded configuration and platform information. This is the approach I have gone with.

Use Manual Packaging

The last option is to not use the automated system at all but instead either do it via a post build event or manually.

Updating the Targets File

With the build task complete and wrapped in a package we just need to get it called during a build. That is where the .targets Allegorithmic substance painter 2019 3 3 download free. file comes in. In the previous version the file was copied to a location under MSBuild but it is now going to be part of the package. Artpaper: new daily wallpapers 3 0 5. Counter strike source offline.

Visual Studio For Mac T4 Template Free

  1. Create a new Tools folder in the package project.
  2. Copy the .targets file into the new folder and rename to P3Net.BuildExtensions.TransformConfigs.targets.

The .targets file needs a couple of adjustments to play nice with the rest of the build system and use the new assembly where the custom task is defined.

We need to make sure the .targets file gets copied to the output directory so right-click the file in Solution Explorer and set its Build Action to Content.

Handling Binding Redirects

One change from the original version is around looking for the app.config file. For newer projects using the SDK format the build system can auto-generate binding redirects. This reduces the amount of configuration that goes into the config file and helps ensure the application will use the correct versions. However this transformation occurs at build time and the modified file is stored directly in the output.

To account for this the .targets file has been modified to use the generated config file instead of the version in source. This will ensure the transforms include any generated binding redirects.

Adding the Props File

The final step is to add a .props file that will get added to the project file when the package is installed. The property file will import the .targets file into the build. Create the P3Net.BuildExtensions.TransformConfigs.props file in the package project. Then paste the following code.

Like the .targets file it needs to be copied to the output at build time.

Updating the Item Template

The environment config item template (actually the template wizard) currently looks for an import of the targets file so that it can report a warning if a project is using the template but hasn't installed the extension yet. Instead we will look for the NuGet package. Instead of trying to handle both approaaches to package references we'll just look for the props file that the package installs.

Testing the Changes

Go ahead and build the solution. Then find the generated .nupkg file and open it. If everything is correct then the .props file will be under the build folder and the .targets file under the tools folder. When the package is installed the .props file will get added to the project file. Since it references the .targets file that file will get loaded at build time which will trigger the generation of the config transforms.

Now copy the package file to your local NuGet store so you can add it to a project with a set of config transforms. We'll use a simple web app as a test.

Visual Studio For Mac Download

  1. Create a new ASP.NET Web Application in Visual Studio.
  2. Using Package Manager add the new package to the project.
  3. Rebuild.
  4. The existing web config transforms should run during the build and, as in the original article, you should have the transformed files ready for use.

Visual Studio 2019 Support

As a final touch we will update the extension to support VS 2019. This just requires a couple of changes to the vsixmanifest file as discussed here.

  1. Update the InstallationTarget to [15.0,17.0)].
  2. Update any Prerequisite elements from Visual Studio to [15.0,].
  3. Update the extension version information.
  4. Rebuild

Note: The templates require T4 Toolbox which has not been updated to VS 2019 as of yet.

Cleaning Up the Code

The build extension project (P3Net.BuildExtensions) and VSIX (P3Net.BuildExtensions.Setup) are no longer needed and can be removed.

The installation script and original .targets files can be removed as they are no longer needed.

The text template VSIX (T4TemplatesSetup) may have a dependency on the build extension project. This can be removed from the manifest editor now that it is gone.

The code is available on GitHub.

Posts

  • The EnvDTE assembly is only available to T4 templates on Windows with Visual Studio since it provides access to the Visual Studio object model.

    In Xamarin Studio a T4 template will generate a single file. It is not possible to run a T4 template and make arbitrary changes to the project. You could probably do this with a custom T4 template host that provides access to the Xamarin Studio object model. However the T4 template could not be used for Visual Studio.

  • @mattward What would be the best approach to add code-gen (doesn't need to be T4) to Xamarin Studio? Picking up files that where changed, creating new .cs files for compilation to the project. E.g. using AddIns or custom T4 host, what would be the high level steps to do / APIs to use. Thanks

  • @DomCS - It depends on your requirements. You can look at using the built-in code generation support, such as T4, and see if that fits your requirements. If not then you will probably need a custom addin. Without knowing your requirements it is not that easy for me to suggest an approach.

    A T4 file will generate a new file when the T4 file is saved. So it is a manual process. If you need something more than that, such as generating new files before every build then you will need to create an addin. The TypeScript addin is one example that generates code before the build. Another approach would possibly be to do this all with MSBuild instead of creating an addin.

  • 0




broken image