Obtenir le chemin du projet référencé dans le modèle T4?

J’ai une solution qui contient quelques projets. J’aimerais créer des modèles T4 dans l’un de mes projets de test pour générer des tests basés sur du code dans un autre projet. Le projet de test a une référence de projet à l’autre projet. Le problème que j’ai, c’est que je ne sais pas comment obtenir un chemin d’access au fichier edmx à partir duquel je dois générer du code.

Exemple (supposez qu’il s’agit d’un explorateur de solutions basé sur 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) 

Comment mon GeneratedTests.tt pourrait-il obtenir un chemin de fichier pour MyModel.edmx en utilisant sa référence de projet?

Cela ne marche pas comme ça. Vous devrez référencer la DLL par chemin (vous pouvez le trouver avec Host.ResolvePath et utiliser la balise VolatileAssembly de la boîte à outils pour pouvoir le recomstackr sans redémarrer VS) et utiliser la reflection pour travailler sur le modèle.

Cette réponse ne fonctionne que depuis Visual Studio.

Définissez la propriété “hostspecific” du modèle T4. Cela vous donne access à la propriété Host. Tapez cast Host sur IServiceProvider pour appeler GetService (typeof (DTE)). Cela vous permet de parcourir le contenu de la 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#> <# } #> 

Voir également l’exemple de l’ interface ITextTemplatingEngineHost sur MSDN et T4 Architecture par Oleg Synch .

Basé sur le commentaire de James Close, j’ai pu écrire le modèle suivant pour le débogage de mes chemins de fichiers:

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

Cela générera un fichier .txt et vous aidera très rapidement à déboguer si votre chemin peut être localisé ou non.

En remarque, dans les cas où il n’existait pas de chemin de ../App.config relatif (par exemple, ../App.config ), j’ai trouvé qu’il était test1.txt de placer un fichier (par exemple, test1.txt ) à chaque niveau de répertoire, Comme je l’ai découvert, Host.ResolvePath n’était pas capable de voir en dehors de l’assembly actuel avec ma configuration. Cette mise en garde peut devenir très déroutante car ../../App.config pourrait résoudre MySolution\App.config , mais ../../MyDal/README.txt ne sera pas résolu (le fichier ne sera donc pas résolu trouvé), même si c’est le bon chemin. Le code ci-dessus semble éliminer ce problème autant que je peux voir.

La solution ci-dessus pourrait également être une solution à ce problème – Comment utiliser le générateur d’entités poco

utiliser ces lignes

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

puis utilisez un chemin relatif pour obtenir votre fichier edmx, par exemple, chaîne inputFile = @ “.. \ Modal.edmx”;

Vous pouvez utiliser les macros pour des répertoires spéciaux tels que $(ProjectDir) , $(SolutionDir) partir du modèle et éventuellement lire le fichier .sln ou .csproj pour extraire le répertoire de l’autre projet.

Sur la base de la réponse de Mina et d’autres personnes, j’ai proposé cette solution. Il répertorie le répertoire de travail actuel, le chemin de la solution et utilise l’astuce de Mina pour modifier le répertoire de travail actif.

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