在T4模板中获取引用项目的路径?

时间:2010-08-23 13:31:42

标签: c# visual-studio-2010 t4

我的解决方案中包含一些项目。我想在我的一个测试项目中创建一些T4模板,以根据另一个项目中的代码生成测试。测试项目有一个项目参考另一个项目。我遇到的问题是我不知道如何获取我需要生成代码的edmx文件的文件路径。

示例(假装这是一个基于ASCII的解决方案资源管理器):

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)

我的GeneratedTests.tt如何利用其项目引用获取MyModel.edmx的文件路径?

6 个答案:

答案 0 :(得分:15)

此答案仅适用于Visual Studio中。

设置T4模板的“hostspecific”属性。这使您可以访问Host属性。键入cast Host to IServiceProvider以调用GetService(typeof(DTE))。这使您可以遍历解决方案的内容。

<#@ 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#>
<#
}
#>

另请参阅ITextTemplatingEngineHost interface on MSDNT4 Architecture by Oleg Synch的示例。

答案 1 :(得分:10)

基于James Close的评论,我能够编写以下模板来调试我的文件路径:

<#@ 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
    <#
}
#>

这将生成.txt文件,并且可以非常快速地帮助您调试是否可以找到您的路径。

作为旁注,如果存在无法找到的相对目录路径(例如../App.config),我发现它有助于将文件(例如test1.txt)放在每个目录级别,因为我发现Host.ResolvePath无法通过我的设置在当前程序集之外看到。由于../../App.config可能会解析为MySolution\App.config,但../../MyDal/README.txt将无法解析(因此无法找到该文件),即使这是正确的路径,此警告可能会很快造成混淆。就我所见,上面的代码似乎否定了这个问题。

上述解决方案也可能是解决此问题的方法 - How to use the poco entity generator

答案 2 :(得分:4)

这不起作用。您必须通过路径引用dll(您可以使用Host.ResolvePath找到它并使用工具箱中的VolatileAssembly标记以便能够重新编译它而无需重新启动VS)并使用反射来处理模型。

答案 3 :(得分:4)

使用这些行

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

然后使用相对路径获取您的edmx文件 例如,string inputFile = @“.. \ Modal.edmx”;

答案 4 :(得分:1)

您可以将宏用于特殊目录,例如模板中的$(ProjectDir)$(SolutionDir),也可以读取.sln或.csproj文件以提取其他项目的目录。

答案 5 :(得分:1)

根据Mina和其他人的回答,我提出了这个解决方案。它列出了当前的工作目录,解决方案路径,并使用Mina的技巧来更改活动的工作目录。

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#
 string cwd1 = System.IO.Directory.GetCurrentDirectory();
 string solutionPath = Host.ResolveAssemblyReference("$(SolutionDir)");
 Directory.SetCurrentDirectory(solutionPath);
 string cwd2 = System.IO.Directory.GetCurrentDirectory();
#>
// Solutionpath is:<#= solutionPath #>, old cwd: <#= cwd1 #>, new cwd: <#= cwd2 #>