Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Кажется в VS2017 EnvDTE игнорирует атрибуты.

Пример:

namespace ConsoleApp2
{
    [Test]
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    class Test : Attribute { }
}

Добавляю в приложение шаблон Template1.tt:

<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".txt" #>
<#@ Assembly Name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #> 
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#
	Init();
	WriteLine(Classes.Count.ToString());

//попытка получить атрибуты:
	foreach(CodeClass cc in Classes) {
		foreach(CodeElement ce in cc.Members){
			if(ce.Kind == vsCMElement.vsCMElementFunction){
				CodeFunction cf = ce as CodeFunction;
				WriteLine(ce.Name + " " + cf.Attributes.Count.ToString());
			}
		}
	}
#>
<#+

public CodeNamespace Ns {get;set;}
public List<CodeClass> Classes {get;set;}

public void Init(){

	IServiceProvider hostServiceProvider = (IServiceProvider)Host;
	DTE dte  = (DTE)hostServiceProvider.GetService(typeof(DTE));

	Project proj=null;
	foreach(Project p in dte.Solution.Projects){
		if(p.Name == "ConsoleApp2"){
			proj=p;
			break;
		} 
	} 

	foreach(CodeElement ce in proj.CodeModel.CodeElements) {
		if(ce.Name=="ConsoleApp2"){
			Ns = ce as CodeNamespace;
			break;
		}
	}

	Classes = new List<CodeClass>();
	GetClasses(Ns);
}

public void GetClasses(CodeNamespace cn){
	foreach(CodeElement ce in cn.Members) {
		if(ce.Kind == vsCMElement.vsCMElementNamespace) {
			GetClasses(ce as CodeNamespace);
        } else if(ce.Kind == vsCMElement.vsCMElementClass) {
			Classes.Add(ce as CodeClass);
		}
    }
}
 
#>
на выходе:

2
Main 0
Это у всех так или только у меня?
Или я не там ищу атрибут Test?
18 май 17, 19:42    [20494027]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
В примере косяк, [Test] у Main должен стоять.
18 май 17, 19:53    [20494064]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Блин, пример заработал.
18 май 17, 20:12    [20494099]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
А вот в пустом проекте типа WebApplication не пашут атрибуты в шаблончеге.
18 май 17, 20:23    [20494126]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Не пашут лишь у методов контроллеров. Вот гадство, именно там они и нужны.
19 май 17, 10:23    [20495170]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Antonariy
Не пашут лишь у методов контроллеров. Вот гадство, именно там они и нужны.
Скомпилируй сборку работай с ней из T4 через рефлекшен. Не забудь указать следующую опцию, чтобы T4 "отпускал" файл сборки после своей работы.
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>
19 май 17, 10:36    [20495242]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
* Скомпилируй сборку и работай ...
19 май 17, 10:37    [20495247]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
* Скомпилируй сборку и работай ...
Если ты о Reflection, то он блокирует сборку, и даже пляски с аппдоменами не спасают. И гемор с зависимостями.

В общем, достоверно обнаружил, что атрибуты не видны, если файл с исходником не в корне проекта, а в папке. Двойное гадство.
19 май 17, 11:09    [20495449]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
Antonariy
Не пашут лишь у методов контроллеров. Вот гадство, именно там они и нужны.
Скомпилируй сборку работай с ней из T4 через рефлекшен. Не забудь указать следующую опцию, чтобы T4 "отпускал" файл сборки после своей работы.
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>
Не заметил этого сообщения, попробую.
19 май 17, 11:10    [20495459]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Рефлекшн обломался:

Ошибка		Выполнение преобразования: System.IO.FileNotFoundException: Не удалось загрузить файл или сборку "System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" либо одну из их зависимостей. Не удается найти указанный файл.
Имя файла: 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
в Microsoft.VisualStudio.TextTemplating6E191A85ED77A05CD85D8E03765372E33142481F5E036A4E4C2916AA9B1D39F2C379D43E983ED2B7A82C5E314F85E5216BA7CD97091222A4B24FF8AF71DCC1B2.GeneratedTextTransformation.TransformText()
в System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
в Microsoft.VisualStudio.TextTemplating.TransformationRunner.PerformTransformation()
19 май 17, 11:34    [20495581]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
У меня это, так же, работает для анализа классов MVC/WebAPI конроллеров, проблем нет.

Гружу сборку через:
var controllersAssembly = Path.Combine(ProjectFolder, "Bin", Path.ChangeExtension(ProjectName, "dll"));
Assembly.LoadFrom(controllersAssembly);

+ Работа с EnvDTE
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDTE" #> 
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="EnvDTE" #>
<#+
	string TemplateFolder 
	{
		get { return Path.GetDirectoryName(Host.TemplateFile); }
	}

	string SolutionFolder
	{
		get
		{
			var dte = GetIdeService<DTE>();
			return Path.GetDirectoryName(dte.Solution.FullName);
		}
	}

	string ProjectFolder
	{
		get { return Path.GetDirectoryName(Project.FullName); }
	}

	string ProjectName
	{
		get { return Project.Name; }
	}

	Project Project
	{
		get
		{
			var dte = GetIdeService<DTE>();
			var item = dte.Solution.FindProjectItem(Host.TemplateFile);

			if (item != null && item.ContainingProject != null)
				return item.ContainingProject;

			throw new InvalidOperationException("Can't find project.");
		}
	}

	T GetIdeService<T>()
	{
		var sp = (IServiceProvider)Host;
		return (T)sp.GetService(typeof(T));
	}
#>
19 май 17, 11:43    [20495632]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Добавлю, работаю с VS2013, MVC5. Про заморочки с другими версиями не в курсе.
19 май 17, 11:48    [20495656]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
У меня это, так же, работает для анализа классов MVC/WebAPI конроллеров, проблем нет.
С приведенным кодом и у меня проблем не будет.

С рефлекшеном проблемы начинаются тут: foreach(var t in Assembly.LoadFrom(controllersAssembly).ExportedTypes)

А с DTE - гемор с атрибутами. Попробуй мой шаблон у себя запустить, только замени "ConsoleApp2" на имя своего проекта и корневого неймспейса. У меня сейчас нет другой студии, а тип приложения пофиг. Я в консольном закинул Program.cs в папку, и атрибуты стали невидимы.
19 май 17, 12:07    [20495754]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Antonariy
Алексей К
У меня это, так же, работает для анализа классов MVC/WebAPI конроллеров, проблем нет.
С приведенным кодом и у меня проблем не будет.

С рефлекшеном проблемы начинаются тут: foreach(var t in Assembly.LoadFrom(controllersAssembly).ExportedTypes)
Ну у меня вот так работает:
<#+
	class Controller
	{
		public string VarName;

		public string Path;

		public string[] Actions;
	}

	enum ControllersTypes { Mvc, Api }

	const string S_Controller = "Controller";
	const string S_MvcController = "System.Web.Mvc.Controller";
	const string S_ApiController = "System.Web.Http.ApiController";

	Controller[] GetControllers()
	{
		var assembly = Assembly.LoadFrom(ControllersAssembly);

		var q =
			from t in assembly.GetTypes()
			let ctt = GetControllerType(t)
			where ctt.HasValue
			let ct = CreateController(t, ctt.Value)
			orderby ct.VarName
			select ct;

		return q.ToArray();
	}

	Controller CreateController(Type type, ControllersTypes controllerType)
	{
		var name = type.Name.Substring(0, type.Name.Length - S_Controller.Length);

		return new Controller
		{
			VarName = name,
			Path = GetControllerPath(name, controllerType),
			Actions = GetControllerActions(type)
		};
	}

	ControllersTypes? GetControllerType(Type type)
	{
		if (type.Name.EndsWith(S_Controller) == false)
			return null;

		if (HasBaseType(type, S_MvcController))
			return ControllersTypes.Mvc;

		if (HasBaseType(type, S_ApiController))
			return ControllersTypes.Api;

		return null;
	}

	bool HasBaseType(Type type, string typeName)
	{
		while (true)
		{
			type = type.BaseType;

			if (type == null)
				break;

			if (type.FullName == typeName)
				return true;
		}

		return false;
	}

	string GetControllerPath(string name, ControllersTypes controllerType)
	{
		if (controllerType == ControllersTypes.Mvc)
			return name;

		if (controllerType == ControllersTypes.Api)
			return "api/" + name;

		throw new ArgumentException("type");
	}

	string[] GetControllerActions(Type type)
	{
		var q =
			from t in GetControllerActionsTypes(type)
			from m in t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
			where m.IsSpecialName == false
			select m.Name;

		return q.Distinct().OrderBy(n => n).ToArray();
	}

	IEnumerable<Type> GetControllerActionsTypes(Type type)
	{
		while (true)
		{
			yield return type;
			type = type.BaseType;

			if (type == null || type.FullName == S_MvcController || type.FullName == S_ApiController)
				break;
		}
	}
#>
19 май 17, 13:13    [20496183]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Antonariy, а вообще, может через Roslyn попробовать? Его изобрели вроде как как раз для этого.
19 май 17, 13:20    [20496245]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
assembly.GetTypes() - не удается загрузить один или более запрошенных типов.
19 май 17, 13:22    [20496256]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
Antonariy, а вообще, может через Roslyn попробовать? Его изобрели вроде как как раз для этого.
Тынц?
19 май 17, 13:24    [20496267]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Antonariy
Алексей К
Antonariy, а вообще, может через Roslyn попробовать? Его изобрели вроде как как раз для этого.
Тынц?
Тынц
19 май 17, 13:30    [20496313]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13368
Antonariy
assembly.GetTypes() - не удается загрузить один или более запрошенных типов.
Вероятно его не устраивает версия .Net, используемая в процессе VS IDE.
19 май 17, 13:33    [20496327]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
Antonariy
assembly.GetTypes() - не удается загрузить один или более запрошенных типов.
Вероятно его не устраивает версия .Net, используемая в процессе VS IDE.
Точно, у меня Сore.
19 май 17, 13:50    [20496392]     Ответить | Цитировать Сообщить модератору
 Re: Кто-нибудь в T4 и EnvDTE разбирается?  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 62035
Алексей К
Antonariy
пропущено...
Тынц?
Тынц
Это трындец и перебор, натягивать объектную модель на каждый символа кусок. Меня лишь интерфейс сборки интересует.

А текст можно и через dte анализировать, или вообще без ничего. но это костыль. Уж лучше в названия методов добавлять префиксы/постфиксы вместо атрибутов.
19 май 17, 14:03    [20496460]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить