Reputation: 496
I am creating a project type using Visual Studio Common Project System and hooked up the NuGet package manager. However, when I install a package it fails with the following error:
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 ==========
I decompiled the NuGet assemblies and debugged it to find that the error is occurring in NuGet.PackageManagement.VisualStudio.VsMSBuildProjectSystem.AddReferenceAsync
on this line reference = References.Add(assemblyFullPath);
. So I tried executing the same code and got the same error when trying "System" and "[FullAssemblyPath]".
Unable to find a type of reference that is appropriate for this file: [Assembly].
VsMSBuildProjectSystem Source Code
I tried debugging a normal Visual Basic project and found that it executes a slightly different command, References3.AddFiles(new[] { assemblyFullPath }, out var referencesArray);
, this is because the References object can be cast to References3. It turns out that a Visual Basic project is a VSLangProj80.VSProject2
type and my custom project is a VSLangProj.VSProject
type.
I also noticed that in my custom project type the references have a yellow exclamation mark beside them, because they are unresolved. I believe this is the source of the problem. I'm not sure how Visual Studio resolves references but through debugging I was able to discover that the MSBuild target ResolveAssemblyReferences
is used. When I override it in the Visual Basic project file, the references also show a yellow exclamation, but even when my custom project returns the same information, the references are still unresolved. There must be other things that are used.
I wanted to confirm that it could work but to override that function I found that MSBuildNuGetProjectSystemFactory
created the VsMSBuildProjectSystem
class based on hard coded project type GUIDs and it's an internal class. It appears to be hooked up by exporting MSBuildNuGetProjectProvider
that implements INuGetProjectProvider
. I wanted to override it with my own provider and return a custom implementation with this code but unfortunately it never gets instantiated. MSBuildNuGetProjectProvider Source Code
<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
So I just hacked it and used reflection to add my class to MSBuildNuGetProjectSystemFactory
and my custom class gets executed, overriding the method to add the reference and instead do nothing. Adding a NuGet package succeeded, but of course the reference is not added to the project. MSBuildNuGetProjectSystemFactory Source Code
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
So I still don't know how visual studio is resolving assemblies and I hope that once it is fixed, the NuGet package manager will work as well. I thought it might use IVsDesignTimeAssemblyResolution
but I could never get my class instantiated through MEF. I'm wondering if it is handled in Visual Studio unmanaged code and no extension points exist, considering it's a different project class being created.
If that is the case then I think I can use the INuGetProjectProvider
interface to override adding the reference and do it through editing the XML file directly. But why is my INuGetProjectProvider
implementation never being instantiated through MEF? I tried changing the Order attribute to 0 and 1000. Does Visual Studio MEF have a scope for Nuget within its own assemblies so my class is never picked up?
Upvotes: 1
Views: 487