I need to reference a Type in one of the assemblies referenced by the project containing my Visual Studio T4 template. However, the referenced assembly is installed from a NuGet package. As that Nuget reference evolves, so will the path that NuGet places it in within my solution's packages folder. For example, suppose my NuGet package is:
Facade.Contract.1.0.1-alpha
Then the relative path to it from my project is:
..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll
If the prerelease is updated to beta, that path will change. When the package is released, the path will change. And every time the path changes, the assembly line in my *.tt file is out of date:
<## assembly name="..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll" #>
I don't think there's a way to accomplish this directly with the assembly directive; however, I'm open to some crazy ideas. Could I load the assembly myself into the current, or a subordinate or reflection-only AppDomain?
I think I could, but I'm not sure how to go about dynamically discovering the path to the referenced assembly in the project's references using T4 logic.
Any ideas?
I've found a solution using VSLangProject as suggested by this article: http://t4-editor.tangible-engineering.com/blog/add-references-to-visual-studio-project-from-t4-template.html
Given a string serviceContractReferenceAssembly a to identify the name of the reference assembly in my containing project, and serviceContractReferenceType to identify the type within that assembly, the following worked:
var templateItem = dte.Solution.FindProjectItem(this.Host.TemplateFile);
var project = templateItem.ContainingProject;
var vsProject = project.Object as VSLangProj.VSProject;
foreach(var referenceObj in vsProject.References)
{
var reference = (VSLangProj.Reference)referenceObj;
if(reference.Name != serviceContractReferenceAssembly) continue;
var serviceContractAssembly = Assembly.LoadFile(reference.Path);
var serviceContractType = serviceContractAssembly.GetType(serviceContractReferenceType);
// Do something with it here
}
The Nuget team has made an extension available that allows you some control over the packages in a solution/project. So if you have control over the environment and can be sure everyone has this installed you might be able to search for the installed packages and then dynamically load them during your T4 execution. Since these Nuget assemblies are already complied and not part of your solution/project I would think using the standard Assembly.Load would work but you would need to test that.
Related
I used NuGet Package Explorer (for the first time) to create a .nupkg to share with others. I have one DLL that targets NetStandardLibrary 2.0,
But when I try to add the package I receive the following error:
Could not install package 'iCANMVCSDK 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.7.2', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
I thought that by using NETStandard 2.0 it could be installed in any .NET app. I also tried adding additional assemblies:
I rebuild, repackage, and I still get the same error. What am I missing?
I tried editing the project file like this:
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
When I try to build after adding net472, I receive the following error:
The type or namespace name 'Http' does not exist in the namespace 'System.Net'
What really makes no sense to me is that I can add the DLL directly into the project (the one that targes NET 4.72) and it works as expected. The problem is when attempting to install it as a NuGet package.
So i got roslyn built on my Mac OSX in a folder
dotnet/roslyn/Binaries/Debug/csccore
Here is the list of files I get
CommonNetCoreReferences_DoNotUse.dll*
CommonNetCoreReferences_DoNotUse.pdb*
Microsoft.CodeAnalysis.CSharp.dll*
Microsoft.CodeAnalysis.CSharp.pdb*
Microsoft.CodeAnalysis.CSharp.xml*
Microsoft.CodeAnalysis.dll*
Microsoft.CodeAnalysis.pdb*
Microsoft.CodeAnalysis.xml*
Microsoft.DiaSymReader.Native.amd64.dll*
Microsoft.DiaSymReader.Native.x86.dll*
Microsoft.Win32.Primitives.dll*
Microsoft.Win32.Registry.dll*
System.AppContext.dll*
System.Collections.Concurrent.dll*
System.Collections.Immutable.dll*
System.Collections.dll*
System.ComponentModel.DataAnnotations.dll*
System.Console.dll*
System.Core.dll*
System.Diagnostics.Debug.dll*
System.Diagnostics.FileVersionInfo.dll*
System.Diagnostics.Process.dll*
System.Diagnostics.StackTrace.dll*
System.Diagnostics.Tools.dll*
System.Diagnostics.Tracing.dll*
System.Dynamic.Runtime.dll*
System.Globalization.Calendars.dll*
System.Globalization.Native.dylib*
System.Globalization.dll*
System.IO.Compression.Native.dylib*
System.IO.Compression.dll*
System.IO.FileSystem.Primitives.dll*
System.IO.FileSystem.Watcher.dll*
System.IO.FileSystem.dll*
System.IO.Pipes.dll*
System.IO.dll*
System.Linq.Expressions.dll*
System.Linq.dll*
System.Native.a*
System.Native.dylib*
System.Net.Http.Native.dylib*
System.Net.NameResolution.dll*
System.Net.Primitives.dll*
System.Net.Sockets.dll*
System.Net.dll*
System.Numerics.dll*
System.ObjectModel.dll*
System.Private.CoreLib.dll*
System.Private.CoreLib.ni.dll*
System.Private.Uri.dll*
System.Reflection.Emit.ILGeneration.dll*
System.Reflection.Emit.Lightweight.dll*
System.Reflection.Emit.dll*
System.Reflection.Extensions.dll*
System.Reflection.Metadata.dll*
System.Reflection.Primitives.dll*
System.Reflection.TypeExtensions.dll*
System.Reflection.dll*
System.Resources.ResourceManager.dll*
System.Runtime.Extensions.dll*
System.Runtime.Handles.dll*
System.Runtime.InteropServices.RuntimeInformation.dll*
System.Runtime.InteropServices.dll*
System.Runtime.Loader.dll*
System.Runtime.Numerics.dll*
System.Runtime.Serialization.dll*
System.Runtime.dll*
System.Security.Claims.dll*
System.Security.Cryptography.Algorithms.dll*
System.Security.Cryptography.Cng.dll*
System.Security.Cryptography.Csp.dll*
System.Security.Cryptography.Encoding.dll*
System.Security.Cryptography.Native.dylib*
System.Security.Cryptography.OpenSsl.dll*
System.Security.Cryptography.Primitives.dll*
System.Security.Cryptography.X509Certificates.dll*
System.Security.Principal.Windows.dll*
System.Security.Principal.dll*
System.ServiceModel.Web.dll*
System.ServiceModel.dll*
System.Text.Encoding.CodePages.dll*
System.Text.Encoding.Extensions.dll*
System.Text.Encoding.dll*
System.Text.RegularExpressions.dll*
System.Threading.Overlapped.dll*
System.Threading.Tasks.Extensions.dll*
System.Threading.Tasks.Parallel.dll*
System.Threading.Tasks.dll*
System.Threading.Thread.dll*
System.Threading.ThreadPool.dll*
System.Threading.dll*
System.Windows.dll*
System.Xml.Linq.dll*
System.Xml.ReaderWriter.dll*
System.Xml.Serialization.dll*
System.Xml.XDocument.dll*
System.Xml.XPath.XDocument.dll*
System.Xml.XPath.dll*
System.Xml.XmlDocument.dll*
System.Xml.dll*
System.dll*
corerun*
csc*
csc.cmd
csc.exe*
csc.exe.config*
csc.pdb*
csc.xml*
libclrjit.dylib*
libcoreclr.dylib*
libdbgshim.dylib*
libmscordaccore.dylib*
libmscordbi.dylib*
libsos.dylib*
mscorlib.dll*
mscorlib.ni.dll*
pbcopy
sosdocsunix.txt*
Now how do i get it using in Visual Studio Code?
How do i refer local DLLs?
.Net Core projects can reference dependencies in two ways:
NuGet packages
project-to-project references
Notably, directly referencing assemblies is missing.
This means you have two options:
Build Roslyn NuGet packages, put them into a directory and configure that directory as a package source using NuGet.Config for your .Net Core project. Then reference the packages normally.
Make the relevant Roslyn projects part of your solution using global.json and then reference them as projects using "target": "project" instead of specifying a version of the package in project.json.
I have a portable class library project that targets .NET 4.6 and Universal Windows Platform. This class library contains just one class with the following line of code in its constructor:
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
Now I create a new .NET 4.6 console application project in the same solution and add a project reference to the portable class library. Calling the method that houses the above line of code results in the following exception at runtime:
Could not load file or assembly 'System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
What am I doing wrong here? There are no compile-time errors or warnings.
Things I have tried: add missing(?) NuGet package manually
It seems that System.IO.FileSystem is a library delivered via NuGet, as part of the Microsoft.NETCore mega-package. Okay, perhaps I need to explicitly add this package to any project that uses my portable class library. I attempt to do so.
Could not install package 'Microsoft.NETCore.Platforms 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
No luck with this approach.
Things I have tried: create a project.json file
While there is no clear info on the web, I read a few tidbits about a new project.json based NuGet harness or build system. Just to experiment, I created the following project.json file in my console application project:
{
"dependencies": {
},
"frameworks": {
"net46": { }
},
"runtimes": {
"win-anycpu": { }
}
}
It works! The runtime error goes away! However, I soon found that this was either not the right solution or not a complete solution. I started writing some code to read configuration section values, which involved making use of the IConfigurationSectionHandler interface, and got the following compile-time error:
error CS0246: The type or namespace name 'IConfigurationSectionHandler' could not be found (are you missing a using directive or an assembly reference?)
This interface is part of the System assembly. I see a reference to this assembly, but it has a yellow exclamation mark icon, and a warning appears in the warnings window:
The referenced component 'System' could not be found.
This is where I ran out of ideas. Am I missing something totally obvious?
I have found the solution. My initial attempt was to install the Microsoft.NETCore package into the console application, resulting in the error shown in my original post.
However, if I install only the narrowly-scoped packages, e.g. System.IO.FileSystem, then I achieve success and the application works correctly. Apparently there is something special about the Microsoft.NETCore "master package" that prevents it from correctly installing into dependent projects.
I can import MEF assemblies into my host application. However, when the Imported assembly has other dependencies, e.g. other external assemblies, I get a ReflectionTypeLoadException.
I don't think I should have to reference external dependencies in my host project but cannot see how to get these external dependencies to resolve/load.
The Imports are retrieved using a DirectoryCatalog where I have the Import-annotated assemblies. I have tried adding the external dependency assemblies into the folder as well but that doesn't seem to get me anywhere. Here is the code:
var catalog = new DirectoryCatalog(assemblyLocation);
var container = new CompositionContainer(catalog);
var pluginRepo = new PluginRepository()
{
TestAdaptors = container.GetExportedValues<ITestAdaptor>()
};
foreach (var testAdaptor in pluginRepo.TestAdaptors)
{
testAdaptor.Execute();
}
Is there a different approach I should use? How can I get these external dependencies to load?
It turned out that yes, I can place all of the external assemblies in the folder with the Import-annotated assemblies and they are correctly loaded and therefore I don't have to reference these external dependencies in my host project.
The problem was that the test project I was given had some spurious, unused assemblies which were failing due to missing dependencies. (Yet another reminder of why a build server is your best friend!).
However, we are at the early stage of development of this so issues like this can be expected.
I am currently trying to publish a load of nuget packages for all the projects in this solution. The projects are setup in a simple tree, with Myre being the base project and everything depending on it:
Myre <- Myre.Debugging <- Myre.Debugging.UI <- Myre.UI
Myre <- Myre.UI
Myre <- Myre.Entities <- Myre.Graphics
I'm trying to package up each separate project as a nuget package with the correct dependencies on the other Myre subproject packages as necessary.
My first step was to make a package for Myre (nuspec and bat file of process). This seems to work nicely, the gallery shows Myre as having a ninject (another nuget package) dependency and all is well.
The problem comes when I tried to make the next package. Myre.Debugging depends upon Myre (with a normal project reference) and nothing else. Using this nuspec with nuget pack (verbose) gives:
Attempting to build package from '(x86) Myre.Debugging.csproj'.
Packing files from 'C:\Long_Path\Myre\Myre.Debugging\bin\x86\Release'.
Add file 'C:\Long_Path\Myre\Myre.Debugging\bin\x86\Release\Myre.Debugging.dll' to package as 'lib\net40-Client\Myre.Debugging.dll'
Add file 'C:\Long_Path\Myre\Myre\bin\x86\Release\Myre.dll' to package as 'lib\net40-Client\Myre.dll'
Add file 'C:\Long_Path\Myre\Myre\bin\x86\Release\Myre.XML' to package as 'lib\net40-Client\Myre.XML'
Found packages.config. Using packages listed as dependencies
Id: Myre.Debugging
Version: 1.0.0.2
Authors: Microsoft
Description: Description
Dependencies: Ninject (= 3.0.1.10)
Added file 'lib\net40-Client\Myre.Debugging.dll'.
Added file 'lib\net40-Client\Myre.dll'.
Added file 'lib\net40-Client\Myre.XML'.
Successfully created package 'C:\Long_Path\Myre\Myre.Debugging\Myre.Debugging.1.0.0.2.nupkg'.
As you can see it picks up a packages.config file (presumably from Myre since there isn't one here) which it then determines a Ninject dependency from. If I wanted Myre.Debugging and Myre to be a single package that would be fine. However this is not what I want, I want Myre.Debugging to pick up a dependency on the Myre package.
How can I setup nuget to use Myre as a package reference and not simply to copy the Myre assemblies into the Myre.Debugging package?
Edit:: I tried not using -IncludeReferencedProjects and specifying:
<dependencies>
<dependency id="Myre" version="1.0.0.1" />
</dependencies>
But for some reason this just creates a package with no dependencies at all! Even if manually specifying dependencies like this did work, it's hardly ideal.
According to the NuGet command line reference for the Pack command, the IncludeReferencedProjects switch works as follows:
Include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package.
In your case, Myre.Debugging.nuspec does not match the project file names: (x86) Myre.Debugging.csproj, etc. I suspect that you'll need to match up those file names to get that command line option to work.
Alternatively, if you want to get this to work with a <dependencies> element in your nuspec file, you may be facing another variant on the name mismatch problem. Your Myre.nuspec file defines its ID as follows:
<id>$id$</id>
The NuSpec reference says that the $id$ token is replaced by "The Assembly name." If it's talking about the name of the DLL (ignoring the extension), then I think the generated IDs will be (x86) Myre, etc. You might want to try hard-coding the ID temporarily just to see if that resolves the issue.
I haven't tried making these suggested changes, and I can't guarantee they will work, but I hope this points you in the right direction. Good luck!