Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get referenced project's path in T4 template?

I have a solution that has a few projects in it. I'd like to create some T4 templates in one of my test projects to generate tests based on code in another project. The test project has a Project Reference to the other project. The problem I have is that I don't know how to get a file path to the edmx file I need to generate code from.

Example (pretend this is an ASCII-based Solution Explorer):

MySolution.sln
-> MyTests.csproj (C:\a\b\c\)
----> GeneratedTests.tt (C:\a\b\c\GeneratedTests.tt)
-> MyDAL.csproj (C:\x\y\z\)
----> MyModel.edmx (C:\x\y\z\MyModel.edmx)

How would my GeneratedTests.tt be able to get a file path for MyModel.edmx utilizing its project reference to it?

like image 285
Jaxidian Avatar asked Aug 23 '10 13:08

Jaxidian


3 Answers

This answer only works from within Visual Studio.

Set the "hostspecific" property of the T4 template. This gives you access to the Host property. Type cast Host to IServiceProvider to call GetService(typeof(DTE)). This lets you traverse the contents of the solution.

<#@ template language="c#" hostspecific="true"  #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
These are the projects in this solution:
<#
var serviceProvider = this.Host as IServiceProvider;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
foreach (Project p in dte.Solution.Projects)
{
#>
    <#=p.Name#> at <#=p.FullName#>
<#
}
#>

Also see the example of the ITextTemplatingEngineHost interface on MSDN and T4 Architecture by Oleg Synch.

like image 121
Michael L Perry Avatar answered Oct 05 '22 22:10

Michael L Perry


Based off of James Close's comment, I was able to write the following template for debugging my file paths:

<#@ template language="C#" debug="true" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#><#@
 output extension=".txt"#><#

/////////Some standard-ish settings, continue reading on
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);

/////////Below are the relevant sections I used for debugging

    string solutionsPath = Host.ResolveAssemblyReference("$(SolutionDir)");//Gives you the location of MySolution.sln
    string edmxFile = solutionsPath + "MyDAL/MyDAL/MyModel.edmx"; //Note - VS projects usually have a subdir with the same name as the sln, hence the repetition for MyDAL
#>
Does this file exist?

<#
//
if (File.Exists(edmxFile))
{
    //Continue.
    #>
    Yes
    <#
}
else
{
    #>
    No
    <#
}
#>

This will generate a .txt file and will very quickly help you debug whether your path could be located or not.

As a side note, in cases where there was a relative dir path (e.g. ../App.config) that couldn't be located, I found that it helped to put a file (e.g. test1.txt) at each directory level, as I figured out that Host.ResolvePath wasn't able to see outside the current assembly with my setup. This caveat can get confusing very quickly since ../../App.config might resolve to MySolution\App.config, but ../../MyDal/README.txt won't resolve (hence the file won't be found), even if that is the correct path. The above code seems to negate this problem as far as I can see.

The above solution might also be a resolution to this issue - How to use the poco entity generator

like image 34
Aaron Newton Avatar answered Oct 06 '22 00:10

Aaron Newton


use these lines

string path = this.Host.ResolvePath("");
Directory.SetCurrentDirectory(path);

then use relative path to get your edmx file e.g, string inputFile = @"..\Modal.edmx";

like image 36
Mina W Alphonce Avatar answered Oct 05 '22 22:10

Mina W Alphonce