Установка пакетов NuGet и разрешение ссылок с пользовательским типом проекта с использованием Common Project System
Я создаю тип проекта с помощью Visual Studio Common Project System и подключил менеджер пакетов NuGet. Однако, когда я устанавливаю пакет, он терпит неудачу со следующей ошибкой:
Attempting to gather dependency information for package '[PackageName]' with respect to project '[ProjectName]', targeting '.NETFramework,Version=v4.7'
Gathering dependency information took 3.23 ms
Attempting to resolve dependencies for package '[PackageName]' with DependencyBehavior 'Lowest'
Resolving dependency information took 0 ms
Resolving actions to install package '[PackageName]'
Resolved actions to install package '[PackageName]'
Retrieving package '[AssemblyName] [Version]' from '[Source]'.
Adding package '[PackageName]' to folder '[ProjectDirectory]\packages'
Added package '[PackageName]' to folder '[ProjectDirectory]\packages'
Install failed. Rolling back...
Package '[PackageName]' does not exist in project '[ProjectName]'
Removing package '[PackageName]' from folder '[ProjectDirectory]\packages'
Removed package '[PackageName]' from folder '[ProjectDirectory]\packages'
Executing nuget actions took 1.17 sec
Failed to add reference to '[AssemblyName]'.
Unable to find a type of reference that is appropriate for this file: "[ProjectDirectory]\packages\[PackageName]\lib\net46\[AssemblyName].dll".
Time Elapsed: 00:00:01.2728560
========== Finished ==========
Я декомпилировал сборки NuGet и отладил его, чтобы обнаружить, что ошибка происходит в NuGet.PackageManagement.VisualStudio.VsMSBuildProjectSystem.AddReferenceAsync
на этой линии reference = References.Add(assemblyFullPath);
, Поэтому я попытался выполнить тот же код и получил ту же ошибку при попытке "System" и "[FullAssemblyPath]".
Unable to find a type of reference that is appropriate for this file: [Assembly].
VsMSBuildProjectSystem Исходный код
Я попытался отладить обычный проект Visual Basic и обнаружил, что он выполняет немного другую команду, References3.AddFiles(new[] { assemblyFullPath }, out var referencesArray);
это потому, что объект References может быть приведен к References3. Оказывается, что проект Visual Basic является VSLangProj80.VSProject2
типа и мой пользовательский проект является VSLangProj.VSProject
тип.
Я также заметил, что в моем пользовательском типе проекта ссылки имеют желтый восклицательный знак рядом с ними, потому что они не разрешены. Я считаю, что это источник проблемы. Я не уверен, как Visual Studio разрешает ссылки, но с помощью отладки я смог обнаружить, что цель MSBuild ResolveAssemblyReferences
используется. Когда я перезаписываю его в файле проекта Visual Basic, ссылки также показывают желтый восклицательный знак, но даже когда мой пользовательский проект возвращает ту же информацию, ссылки все еще не разрешены. Там должны быть другие вещи, которые используются.
Я хотел подтвердить, что это может работать, но чтобы переопределить эту функцию, я обнаружил, что MSBuildNuGetProjectSystemFactory
создал VsMSBuildProjectSystem
класс на основе жестко закодированных идентификаторов типов проектов, и это внутренний класс. Кажется, он подключен при экспорте MSBuildNuGetProjectProvider
который реализует INuGetProjectProvider
, Я хотел переопределить его с моим собственным провайдером и вернуть пользовательскую реализацию с этим кодом, но, к сожалению, он никогда не создается. MSBuildNuGetProjectProvider Исходный код
<Export(GetType(INuGetProjectProvider))>
<Name("MSBuildNuGetProjectProvider")>
<Microsoft.VisualStudio.Utilities.Order(After:="ProjectJsonProjectProvider")>
Friend Class MyNuGetProjectProvider : Implements INuGetProjectProvider
<ImportingConstructor>
Public Sub New(threadingService As IVsProjectThreadingService)
Me.New(AsyncServiceProvider.GlobalProvider, threadingService)
End Sub
Public Sub New(vsServiceProvider As Microsoft.VisualStudio.Shell.IAsyncServiceProvider, threadingService As IVsProjectThreadingService)
End Sub
Public ReadOnly Property ProjectType As RuntimeTypeHandle Implements INuGetProjectProvider.ProjectType
Get
Return GetType(MSBuildNuGetProject).TypeHandle
End Get
End Property
Public Async Function TryCreateNuGetProjectAsync(project As IVsProjectAdapter, context As ProjectProviderContext, forceProjectType As Boolean) As Task(Of NuGetProject) Implements INuGetProjectProvider.TryCreateNuGetProjectAsync
Dim projectSystem As New TestProjectSystem(project, context.ProjectContext)
Await projectSystem.InitializeProperties()
Return New MSBuildNuGetProject(projectSystem, context.PackagesPathFactory.Invoke, project.ProjectDirectory)
End Function
End Class
Так что я просто взломал его и использовал отражение, чтобы добавить свой класс в MSBuildNuGetProjectSystemFactory
и мой пользовательский класс выполняется, переопределяя метод, чтобы добавить ссылку и вместо этого ничего не делать. Добавление пакета NuGet прошло успешно, но, конечно, ссылка не добавлена в проект. MSBuildNuGetProjectSystemFactory Исходный код
Friend Class TestProjectSystem : Inherits VsMSBuildProjectSystem
Private mProjectAdapter As IVsProjectAdapter
Public Sub New(a As IVsProjectAdapter, c As INuGetProjectContext)
MyBase.New(a, c)
Me.mProjectAdapter = a
End Sub
Public Overrides Async Function AddReferenceAsync(referencePath As String) As Threading.Tasks.Task
'Dim project = TryCast(Me.mProjectAdapter.Project.Object, VSLangProj.VSProject)
'project.References.Add(referencePath)
End Function
End Class
Так что я до сих пор не знаю, как Visual Studio разрешает сборки, и надеюсь, что после исправления менеджер пакетов NuGet также будет работать. Я думал, что это может использовать IVsDesignTimeAssemblyResolution
но я никогда не смог получить экземпляр своего класса через MEF. Мне интересно, обрабатывается ли он в неуправляемом коде Visual Studio и не существует точек расширения, учитывая, что создается другой класс проекта.
Если это так, то я думаю, что я могу использовать INuGetProjectProvider
Интерфейс, чтобы переопределить добавление ссылки и сделать это путем непосредственного редактирования файла XML. Но почему мой INuGetProjectProvider
реализация никогда не создается через MEF? Я попытался изменить атрибут Order на 0 и 1000. Имеет ли Visual Studio MEF область действия для Nuget в своих собственных сборках, чтобы мой класс никогда не поднимался?