Подтвердить что ты не робот

Получить ссылку на проект в шаблоне 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, используя его ссылку на проект?

4b9b3361

Ответ 1

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

Ответ 2

Этот ответ работает только из 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 Олегом Синчем.

Ответ 3

Основываясь на комментарии 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 и очень быстро поможет вам отладить, может ли ваш путь быть расположен или нет.

В качестве побочного примечания, в тех случаях, когда существовал относительный путь dir (например, ../App.config), который не мог быть найден, я обнаружил, что он помог разместить файл (например, test1.txt) на каждом уровне каталога, как я понял, что Host.ResolvePath не смог увидеть вне текущей сборки с моей настройкой. Это предостережение может запутаться очень быстро, так как ../../App.config может разрешить MySolution\App.config, но ../../MyDal/README.txt не будет разрешен (следовательно, файл не будет найден), даже если это правильный путь. Вышеприведенный код, кажется, отрицает эту проблему, насколько я могу судить.

Вышеупомянутое решение может также быть решением этой проблемы - Как использовать генератор объектов poco

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

Основываясь на ответе Мины и других, я придумал это решение. Он отображает текущий рабочий каталог, путь решения и использует трюк Мины для изменения активного рабочего каталога.

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