在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的文件路径?

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

此答案仅适用于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#> <# } #> 

另请参阅MSDN上的ITextTemplatingEngineHost接口和Oleg Synch的T4架构示例。

基于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将无法解析(因此该文件不会发现),即使这是正确的道路。 就我所见,上面的代码似乎否定了这个问题。

上述解决方案也可能是解决此问题的方法 – 如何使用poco实体生成器

使用这些线

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

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

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

根据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 #>