Получить путь к указанному проекту в шаблоне T4? - PullRequest
14 голосов
/ 23 августа 2010

У меня есть решение, в котором есть несколько проектов. Я хотел бы создать несколько шаблонов 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 ]

15 голосов
/ 29 августа 2010

Этот ответ работает только из Visual Studio.

Установите свойство hostspecific для шаблона T4. Это дает вам доступ к свойству Host. Введите приведение Host к 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 на MSDN и T4 Архитектура от Олега Синча .

10 голосов
/ 13 января 2013

Исходя из комментариев Джеймса Клоуса, я смог написать следующий шаблон для отладки путей к моим файлам:

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

4 голосов
/ 06 ноября 2010

используйте эти строки

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

затем используйте относительный путь, чтобы получить файл edmx например, строка inputFile = @ ".. \ Modal.edmx";

4 голосов
/ 23 августа 2010

Это не работает таким образом.Вам нужно будет ссылаться на dll по пути (вы можете узнать это с помощью Host.ResolvePath и использовать тег VolatileAssembly на панели инструментов, чтобы иметь возможность перекомпилировать его без перезапуска VS) и использовать отражение для работы с моделью.

1 голос
/ 02 июня 2017

Основываясь на ответе Мины и других, я придумал это решение. Он перечисляет текущий рабочий каталог, путь решения и использует хитрость 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 #>
1 голос
/ 23 августа 2010

Вы можете использовать макросы для специальных каталогов, таких как $(ProjectDir), $(SolutionDir) из шаблона, и, возможно, прочитать файл .sln или .csproj, чтобы извлечь каталог для другого проекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...