what is and where can I find MvcTextTemplateHost - t4

I would like to know what this is MvcTextTemplateHost. I have this in my create.tt but I cant find it in my bin folder (searching with object viewer). I read up and found out it's in my
VisualStudio.Extensions.web.dll but I cant find this dll
I've read this
T4 References for 'MvcTextTemplateHost' and 'VisualStudio'.
I would just like to know what properties and methods this class has. I would love a t4 text editor. I installed a few but nothing gives me intellisense for this class thank you.

MvcTextTemplateHost is "Host" of MVC 3.0 (Add>View and Add>Controller) Dialog and maintain user interactions:
so it is not available outside of the tool. When you provide "Scaffolding" template (a .tt file) a manager passes these user inputs to host so host will have those properties.
The class is packaged in:
($VSDIR)\Common7\IDE\Microsoft.VisualStudio.Web.Mvc.3.01.dll
Hope it helps.

In my case the solution was. add these line en controllerWithContext.tt
<## assembly name="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Microsoft.VisualStudio.Web.Mvc.3.01.dll" #>
next to:
<## import namespace="System.Reflection" #>
before:
<## import namespace="Microsoft.VisualStudio.Web.Mvc.Scaffolding.BuiltIn" #>
good luck

You can find all .tt files in VS installation direction, for example to get MVC4 .tt files, go to: ($VSDir)\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\CodeTemplates
To get the list of the properties of MvcTextTemplateHost, as they are dynamic, you can add the following code to your .tt file:
<#
Type myType = mvcHost.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
#>
<#= prop.Name #>
<#
}
#>
I ran it as I create a List View in MVC4, and some of the properties that came up are:
ViewName
IsPartialView
IsContentPage
ReferenceScriptLibraries
AutoEventWireup
MasterPageFile
...

I had the same problem after installing the T4 templates for modifying Visual Studio's auto generated CRUD pages described in this question: How do I create my own Scaffold Template in ASP.NET MVC 3?
The solution for me was just to just close Visual Studio 2012 and say Yes to saving the solution. When I reopened it everything compiled fine again, magically. The comments on this answer suggest this has worked for similar situations: https://stackoverflow.com/a/13816299/176877

Related

Add template file without custom tool to project programmatically

We add a structure of T4 template files (tt and ttinclude ones) in a project in Visual Studio.
For these templates we are using our custom transformation and processing and we do NOT want the Custom Tool setting of the tt files which by default is set to TextTemplatingFileGenerator.
In order to achieve that we are using the following code:
... // logic for the files creation
ProjectItem addedItem = this.project.ProjectItems.AddFromFile(fileFullPath);
addedItem.Properties.Item("CustomTool").Value = string.Empty;
The problem is that when the files are added to the project a code generation is caused by the default custom tool and even after we remove it from the properties of the tt files the errors caused by the transformation are still in the Errors List (its something like visual glitch).
They disappear as soon as you save a file, navigate to other file or build the project but we do not want our users to see these errors and make any additional actions to get rid of them.
We tried to access the errors collection using the DTE and DTE2 classes like
DTE2 dte2 = (DTE2)this.project.DTE;
dte2.ToolWindows.TaskList;
or getting them from the ErrorListProvider provider as
var provider = new ErrorListProvider(this.ServiceProvider);
var tasks = provider.Tasks;
but the TaskList is not containing these errors - may be the reason is that they are transformation errors not a compile ones.
Even more strange is that the DTE.Events.TaskListEvents.TaskAdded event is firing for each of the transformation errors but they cannot be found in the TaskList. Also calling the Delete() method of the errors got from the TaskAdded event is not removing them from the errors list.
We also tried to programmatically navigate through the files or save the tamplates but it is not refreshing the errors list like when doing it manually.
How can we refresh the ErrorList or tell Visual Studio not to add a Custom Tool setting when we add the templates to the Project?
P.S. We do not want to force a build of the project of the clients (it is removing the errors but it is not applicable for us).
We found a dirty workaround to get rid of the errors.
We generate the template files with their basic template content (the one below) which is valid for the default TextTemplatingFileGenerator and the initial code generation is not causing any errors.
<## template debug="true" hostSpecific="true" #>
<## output extension=".cs" #>
<## Assembly Name="System.Core" #>
<## Assembly Name="System.Windows.Forms" #>
<## import namespace="System" #>
<#
// This is a temporary content valid for the TextTemplatingFileGenerator.
#>
Then after removing the custom tool setting we replace the content with the real one and everything is working as expected because the files are already in the Project and there are not any other transformations without a custom tool.
Not the best solution but we were not able to find better. I hope this helps.

Finding T4 text template class code

T4 text templates can be used to generate not only code but also any kind of text with visual studio.
I've read blogs and tutorials about T4 and as far as I can understand, visual studio dynamically builds a class in the background, compiles and runs the code in that class to build the text output.
Is it possible to see the source code of that class?
Yes, the easiest way is to change the Custom Tool in the properties window when the template file is selected in Solution Explorer.
By default, it will be 'TextTemplatingFileGenerator'.
If you change the custom tool to 'TextTemplatingFilePreprocessor' you'll get the underlying template class instead of the template output generated into your project.
To be precise, this code won't be exactly the same as that which is run under the covers, but it will be very close.
If you need the absolute exact code, you should leave the custom tool alone, but set the debug="true" flag on your <## template #> directive. This will then leave the generated code sitting around in a random named '.cs' or 'vb' file in your %TEMP% directory. Just sort the directory by time and it should be up at the top.

T4 Template Get Attributes

I am trying to customise the T4 templates used in MVCScaffolding.
I would like to filter out properties which are have the NotMapped attribute.
My problem is that the attribute collection seems to be empty. I have tried printing out the attributes like below:
List<ModelProperty> properties = GetModelProperties(Model.ViewDataType, true);
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && !property.IsForeignKey) {
#>
<th>
#Html.LabelFor(x => x.First().<#= property.Name #>)
<!--
<#foreach(var attribute in property.Type.CodeType.Attributes)
{#>
Attribute: <#=attribute.GetType().Name#>
<#}#>
-->
</th>
<#
}
}
#>
I cannot find any information about this which actually works and so far it is a very slow case of trial and error. What is the correct way to get the attributes or to get the template to ignore unmapped attributes?
It's not an exact answer to your question but it will provide more information about the problem. I have experienced exactly the same. There are some strange things about this issue:
It worked before. I run the same code (it’s from source control so I’m sure) as 2 months ago and today it’s failing.
The same code when run from outside of T4 engine (e.g. MVC application) works perfectly fine.
I have altered my code so it can be run from outside of Visual Studio:
string assemblyPath = Host.ResolveAssemblyReference("$(ProjectDir)$(OutDir)T4Mvc.dll");
was changed to:
string assemblyPath = #"D:\AbsolutePath\bin\T4Mvc.dll";
Then I used TextTransform.exe instead of RMB > Run Custom Tool
use
TextTransform.exe AjaxServices.tt -out AjaxServices.js
(You can find TextTransform.exe in: "C:\Program Files (x86)\Common Files\microsoft shared\TextTemplating\10.0" ).
Also I have disabled hostspecific flag.
The same template when executed from TextTransform.exe instead of VS worked perfectly. It seems that it’s some kind of problem with VS.
Please try using TextTransform. exe and tell if it works.

Custom Visual Studio Context Menus

I want to use T4 templates to automatically create some code but I want to add a user input box (to ask for a name, for example) similar to the MVC3 "Add View" / "Add Controller" dialog when you right click on a specific folder. Is this possible with pure T4 templates or is it going to result in a writing a VS plugin DLL? If it involves writing a DLL can I just plop that into the projects reference and use it per-project or does it have to be registered individually on each machine?
Managed to figure it out. I probably should of tried this first. Just add the required imports to your T4 template:
<## assembly name="System.Windows.Forms.dll" #>
<## assembly name="System.Drawing.dll" #>
<## import namespace="System.Windows.Forms" #>
<## import namespace="System.Drawing" #>
and then create a form programmatically with a label, input box and button. On DialogResult.OK (for example) just read the input value and do what you need with it. Works perfectly :-)

Determine solution configuration (debug/release) when running a T4 template

I have a T4 template that can output either optimized content or standard content based on a flag. Currently I'm manually changing the flag based on my needs.
What I'd love to do is set the flag based on the Configuration of the Solution in Visual Studio. If set to build in Debug mode, I would output standard content. If set to build in Release mode, I would optimize the content instead. I found another T4 question that looks promising: T4 Text Template - Is it possible to get compilation symbols from host?
However, in my case I would want to do something like the following:
<## template language="C#" hostspecific="True"
compilerOptions="/d:$(ConfigurationName)" #>
Since I can use $(SolutionDir) in an assembly directive:
<## assembly name="$(SolutionDir)\myreference.dll" #>
I would think the /d:$(ConfigurationName) would get me where I needed to go, and then I could do the following to set my flag:
<#
#if Debug
optimize = false;
#else
optimize = true;
#endif
#>
Alas, this doesn't seem to work. I've also attempted using:
Host.ResolveParameterValue("-", "-", "ConfigurationName");
Also to no avail. Any ideas?
No sooner do I ask but I find a snippet at the bottom of this MSDN article that gets me where I need to be. The answer here is to use the IServiceProvider interface to get the Visual Studio DTE. Here's code that is getting it done (apologies in advance for the hard-coded "Debug"):
var serviceProvider = Host as IServiceProvider;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
var configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
optimize = (configName != "Debug");
UPDATE
This code will check to see if the active project's current configuration has optimizations turned on. It still has a hard-coded property name, but one that's much less likely to change. Also, using the project's optimization flag makes a lot of sense for my scenario (trying to decide if I should turn on optimizations in my own code):
var serviceProvider = Host as IServiceProvider;
var dte = serviceProvider.GetService(typeof(EnvDTE.DTE)) as DTE;
config = dte.Solution
.FindProjectItem(Host.TemplateFile)
.ContainingProject
.ConfigurationManager
.ActiveConfiguration;
foreach(Property prop in config.Properties)
{
if (prop.Name == "Optimize")
{
optimize = (bool)prop.Value;
break;
}
}
For people trying to get this work at design-time (file save) as well as at build-time (F5/F6), two methods are necessary.
Emil describes the design-time method. For build-time, you first have to specify a T4 parameter in your project file:
<ItemGroup>
<T4ParameterValues Include="BuildConfiguration">
<Value>$(Configuration)</Value>
<Visible>false</Visible>
</T4ParameterValues>
</ItemGroup>
Then you have to reference it at the top of your .tt:
<## parameter type="System.String" name="BuildConfiguration" #>
And then look for whichever of them happens to be provided:
string configurationName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
if (string.IsNullOrWhiteSpace(configurationName))
{
var serviceProvider = (IServiceProvider)Host;
var dte = (DTE)serviceProvider.GetService(typeof(DTE));
configurationName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
}
It is necessary to include the logic for both if you want your template to work in both scenarios. The design-time method does not work at build-time (the DTE Host is not around to provide the Solution), and the build-time method does not work at design-time (MSBuild is not around to provide the parameter).
If trying to do this in a VS2017 ASP.Net Core project then following is a solution that worked for me with highlights from my post here.
This MSDN blog by Jeremy Kuhne and this blog by Thomas Levesque and several other links such as this MSDN doc helped get it working in VS2017.
I did not have to add anything to the beginning of the .csproj file since VS2017 has the files already included by default.
In Visual Studio 2017, the Text Template Transformation component is
automatically installed as part of the Visual Studio extension
devlopment workload. You can also install it from the Individual
components tab of Visual Studio Installer, under the Code tools
category. Install the Modeling SDK component from the Individual
components tab.
I ended up with the following .csproj changes at the end of the file:
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<!-- Run the Transform task at the start of every build -->
<TransformOnBuild>true</TransformOnBuild>
<!-- -->
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
<!-- Transform every template every time -->
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
<!-- add AFTER import for $(MSBuildToolsPath)\Microsoft.CSharp.targets -->
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
<ItemGroup>
<T4ParameterValues Include="BuildConfiguration">
<Value>$(Configuration)</Value>
<Visible>False</Visible>
</T4ParameterValues>
</ItemGroup>
<Target Name="CreateT4ItemListsForMSBuildCustomTool" BeforeTargets="CreateT4ItemLists" AfterTargets="SelectItemsForTransform">
<ItemGroup>
<T4Transform Include="#(CreateT4ItemListsInputs)" Condition="'%(CreateT4ItemListsInputs.Generator)' == 'MSBuild:TransformAll'" />
</ItemGroup>
</Target>
This in the T4 Template:
<## template hostspecific="true" language="C#" #>
<## output extension=".txt" #>
<## assembly name="EnvDTE" #>
<#
//Build time
string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
if (string.IsNullOrWhiteSpace(configName))
{
try
{
//Design time.
var serviceProvider = (IServiceProvider)Host;
EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
}
catch(Exception ex)
{
configName = ex.Message;
}
}
#>
<#=configName#>
The following property settings on the .tt file:
Build Action: None
Copy to Output Directory: Do Not Copy
Custom Tool: MSBuild:TransformAll

Resources