.NET Core, .NET Standard and Transitive Dependencies across Solutions - c#

My question is similar to this one, although it doesn't really address my issue.
I am working on some new AWS Lambda functions, and I would like to keep their implementation in separate class libraries for reuse. I'm testing this concept using two solutions:
A solution with a single .NET Standard class library project. This class library has a reference to HTML Agility Pack.
A solution with a single .NET Core 2.0 console application project.
Class library:
using System;
using HtmlAgilityPack;
namespace ClassLibrary1
{
public class Class1
{
public static bool FoundDotNet(string html)
{
bool foundDotNet = false;
HtmlDocument document = new HtmlDocument();
document.LoadHtml(html);
var titleNode = document.DocumentNode.SelectSingleNode("//title");
if (titleNode != null)
{
string titleText = titleNode.InnerText;
if (titleText.ToLower().Contains(".net"))
{
foundDotNet = true;
}
}
return foundDotNet;
}
}
}
Console application:
using System;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var foundDotNet = ClassLibrary1.Class1.FoundDotNet("<html><head><title>.NET WTF Buddy</title></head><body>You're doin' me a confuse.</body></html>");
Console.WriteLine(foundDotNet);
}
}
}
Both projects build without issue. However, the HTML Agility Pack assembly isn't copied into the Debug directory for either of the projects, and when I try to run the console application, I get Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'HtmlAgilityPack'
I have the package management format set to "PackageReference" for both projects, which I thought would handle the transitive dependency correctly. HTML Agility Pack is listed in the json.deps file, so I'm not sure what the problem is.
"HtmlAgilityPack/1.7.1": {
"dependencies": {
"System.Net.Http": "4.3.2",
"System.Xml.XPath": "4.3.0",
"System.Xml.XPath.XmlDocument": "4.3.0",
"System.Xml.XmlDocument": "4.3.0"
}
If I move the the class library project into the same solution as the console application, it works fine. What's preventing me from separating my code into separate solutions?

I'm using a large, complicated library in several solutions and the library has many transitive dependencies.
First, set up your library. Right click on the library's project name and choose Properties. About halfway down you'll see a tab labeled Packages. You can use that to auto-generate the NuGet package every time you rebuild the project. Just increment the version number. I use four position version numbering -- the first three are semver-style (major release, minor release, patch release), and the fourth one I increment manually for each new build.
I recommend creating a folder on your drive or network specifically for your local NuGet packages. You can create folders under that for each project. Then you point your debug and release build output to that project folder, and the NuGet package will be generated there, too.
Finally, back in Visual Studio, go to Tools -> Options -> NuGet Package Manager -> Package Sources and add that top-level folder as a package source.
From there it's simple -- open your NuGet dependencies in your consuming app. There's a drop-down at the top right where you can choose the package source. It will automatically search all the child folders and find whatever packages you've created. Now when you tweak your library, it's just a single click to update the client apps.

Related

Creating and maintaining same codebase (class library) with multiple assembly versions as dependency

Given following source code which need to be maintained within a class library project:
using Newtonsoft.Json;
namespace Zephyr.SharedProject.Core
{
public class TestClass
{
public TestClass()
{
string json = JsonConvert.SerializeObject(new
{
PropertyA = 1
});
}
}
}
What are the options do we have if our class library need to support different versions of Newtonsoft.Json?
For example, it was known that the product which consumes the class library have following dependencies:
Product version
Newtonsoft.Json version
1
10.0.1
2
11.0.1
3
12.0.1
Assuming Newtonsoft.Json does not introduce breaking change and same source code can be used with all version above, how would one create and maintain Visual Studio solution to support scenarios above?
I'm thinking having a single project which holds the source code and creating each version-specific project by adding the source code as link1 with corresponding dependencies which looks like following:
Solution
Core Project references Newtonsoft.Json v???
TestClass (source code)
Project_v1 references Newtonsoft.Json v10.0.1
TestClass (added as link)
Project_v2 references Newtonsoft.Json v11.0.1
TestClass (added as link)
Project_v3 references Newtonsoft.Json v12.0.1
TestClass (added as link)
1Right click project, Add > Existing Item > Add As Link
Having project structure above would allow us to maintain a single file and each project can have their own dependency which is fine where we can have unit test for each project as well.
However I'm in dilemma to define the dependency on Core Project as it's ambiguous and would shows compilation error in Visual Studio due to missing reference.
I'm aware binding redirect would solve the problem at consumer-side for version mismatch but I'm interested with the solution from producer (class library) perspective, kindly enlighten me if there's any better approach, cheers!
A shared project can be created in Microsoft Visual Studio which acts a central repository that contains the source codes or files.
The project itself doesn't require any references which can then be added as reference for version specific projects.
When open the source code in editor, one can easily switch between the context of referenced projects to make sure everything's good in case there are any conflict due to different dependencies.
The final project structure would then looks similar to:
Product version
Project type
Newtonsoft.Json version
All
Shared
N/A
1
Class library
10.0.1
2
Class library
11.0.1
3
Class library
12.0.1
P/S: This feature has been around for quite some time and I just recently found out about it, hopefully the information provided helps!
Extra: channel 9 video - Sharing Code Across Platforms With Visual Studio 2015

How to build XLL with Excel-DNA

I am trying to follow the simplest example at the Excel-DNA.net front page to create a simplest UDF for Excel. My code builds correctly, except it builds into dll instead of xll. How do I build it into an xll file?
I literally follow the example from the page (copy pasting it here)
Create a new Class Library (.NET Framework) project in Visual Basic, C# or F#.
Use the Manage NuGet Packages dialog or the Package Manager Console to install the Excel-DNA package:
PM> Install-Package ExcelDna.AddIn
Add your code (C#, Visual Basic.NET or F#):
using ExcelDna.Integration;
public static class MyFunctions
{
[ExcelFunction(Description = "My first .NET function")]
public static string SayHello(string name)
{
return "Hello " + name;
}
}
Compile, load and use your function in Excel:
=SayHello("World!")
All is fine, except it builds into DLL...
The most likely reason why your project is not creating an .xll is because the library you created is targeting ".NET Standard" and not ".NET Framework". The project file format used when targeting ".NET Standard" is not compatible with the NuGet package.
Maybe you can check that again when creating the project, paying particular attention to the "... (.NET Framework)" vs "... (.NET Standard)" option.

NuGet dependencies in MEF loaded assemblies

I am trying to code an application in C#.NET Core that can be extended using MEF. Currently, I am able to do that without any issues with libraries, that have no dependencies or have the same dependencies as the host app (so dependencies are already loaded). But, if I want to use a library with a NuGet reference, that is not used by the main app, the loading of this library fails on that reference.
How can I force the main app to load the missing NuGet dependency, if it tries to load an assembly with such reference? It seems to me as a pretty common use case, but I am lost here and cannot find a way out. Thanks.
For reference, I am posting the portion of the code.
[ImportMany]
private IEnumerable<Lazy<IService, IServiceMetadata>> _asrServices;
...
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(Directory.GetCurrentDirectory(), "Services")));
CompositionContainer _container = new CompositionContainer(catalog);
...
foreach (Lazy<IService, IServiceMetadata> _service in _asrServices)
{
var _serviceInstance = _service.Value // here the loading fails
}
Jiri
.NET currently has two build "systems". One is the original project files, that import Microsoft.Common.props and Microsoft.CSharp.targets (assuming it's a c# project) and lots of XML in between, that has been around ever since .NET was first released, apparently in 2002. Since .NET Core was made generally available in 2016 there has been a new project system generally called SDK projects because the way a *proj file references the build system is though an Sdk element or attribute in the msbuild xml. Although it's off-topic, because there's a common bad assumption, I want to point out that although SDK projects were created for .NET Core, you can target the .NET Framework from SDK projects.
With the original project files, when you build, all the projects references get copied to the output directory. However, with SDK projects, only the project's assembly is copied to output (I'm not sure, but I think even content set to copy to output doesn't actually get copied on build). In order to get everything in a single directory, you should use the dotnet cli's publish command.
So, if you have a build script that builds your project and copies all the plugins somewhere, you should add a dotnet publish step to the script for each plugin using the SDK style project file.

My NuGet package doesn't seem to update in projects that use it as a dependency

Forgive what must be a very simple oversight on my part but I simply cannot get this to work as expected.
I am building a .NET Framework 4.6 Class Library that needs to be downloaded by other applications from a private nuget repository. Here is my process:
I have a test project, ConsoleApp5. It has a simple main function in it.
I download my NuGet package, MyPackage (right click on project and click Manage NuGet Packages, select appropriate repo and package, click install.)
I run my test. In this case, I'm simply trying to instantiate a class, something not difficult. I'm getting an error about class accessibility.
Back in MyPackage, I replace all instances of the word protected with public. I add a new class as well by right-clicking on the project, selecting Add Item, targeting a class and giving it the name TestClass.
I go to Project > MyPackage Properties... > Application (tab) > Assembly Information, and I manually update the version patch number by one. So now it is 1.0.5.
I go to the project directory in the Developer Command Line and run the following command: C:\Users\jptak\Downloads\nuget.exe pack -Version 1.0.5
Then I run the following command to push the update (Success message: Your package was pushed.): C:\Users\jptak\Downloads\nuget.exe push MyPackage.1.0.5.nupkg MySecretCodeGoesHere -src http://my.nuget.server.goes.here.com
I go back to ConsoleApp5, Manage NuGet Packages, see the update in the appropriate package, and click the update arrow. The download completes and the new version number is there.
I go to use new classes or check that old errors are fixed and all of my tests fail. TestClass is not there.
This leads me to believe that the code I am writing is not making it to the NuGet server. Does anyone know what I am missing from this process to make the most recent version of the code get updated on the server?
This process is foreign to me as I am not a .NET developer (I work with PHP mostly).
Here are some more pieces of information about my IDE settings:
In Build > Configuration Manager... > Debug has been switched to Release
I have tried building, rebuilding, and cleaning my project. I haven't seen that any of these processes has had any effect on the code being pushed at all.
Here is the code from my ConsoleApp5:
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
string testclient = "testclient";
string testpass = "testpass";
string scope = "validate-contract";
string accessToken = "";
string retrievedScope = "";
MyPackage.TestClass test = new MyPackage.TestClass();
}
}
Error: TestClass does not exist in namespace. Did you forget an Assembly Reference?
Here's the TestClass code in MyPackage:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyPackage
{
public class TestClass
{
public TestClass()
{
}
}
}
The NuGet server I'm using is: https://github.com/Daniel15/simple-nuget-server
EDIT 1
Upon inspecting the .nupkg file, I can confirm that the old code is still there and that the new code has not made it into the .nupkg. This seems to support the idea that the problem is with the packaging process and not on the nuget server. How does one refresh the dll files before each nuget pack / nuget push?
Bit long for a comment, not exactly an answer but here we go:
So top debugging tips for NuGet packages are:
Download the package manually. A .nupkg file is just a zip file that can be opened with 7Zip or any other archive tool.
Once inside you can inspect both the .nuspec file that has been used to pack the package, and inside the lib folder are the dlls that have been supplied.
A decompiler like DotPeek or ILSpy can be used on the dll to see exactly what is going on inside the dll.
Possible causes of your symptoms could include the NuGet server giving a false success, or your application failing to update the package and still refering to the old one.

How to add nuget packages to c# project files with nuget.core

I am trying to upgrade a bunch of old c# projects to consume nuget packages that I have made from old assembly dependencies. I want to write a C# program to update all the csproj files to reference the package.
I have the code using nuget.core making a dictionary of dependent assemblies to a nuget package. I can iterate over the references in my project file and find the needed nuget package from my repository.
var localRepo = PackageRepositoryFactory.Default.CreateRepository(nugetCachePath);
var packages = localRepo.GetPackages();
foreach (var package in packages)
{
foreach (var assemblyReference in package.AssemblyReferences)
{
assemblyToPackage.Add(Path.GetFileNameWithoutExtension(assemblyReference.Name).ToLower(),package);
}
}
I think I need to use Nuget.Core ProjectManager to add the reference to my project file (csproj).
<ItemGroup>
<PackageReference Incluse="KB.MyOldAssemblyPackage">
<Version>1.0.0</Version>
</PackageReference>
</ItemGroup>
What I can't figure out is how to get an instance of ProjectManager or any examples on how to use it to add the nuget reference. I know I could simply inject the xml with an xdocument but since I made the effort to use nuget.core I was hoping to find a solution using it.
Any help out there?
I don't understand what ways to manage packages you use now, but if it's packages.config, then I think better migrate to PackageReference. For it's may use NuGet PackageReference Upgrader that convert your dependencies from packages.config to PackageReference format.
After that you can add/remove our packages with NuGet Package Manager UI extension that built-in in Visual Studio 2017.
UPD2. Visual Studio 17 Preview 3 has tool for migrate from packages.config to PackageReference.
Also MSBuild 15.1 + has built-in NuGet targets such as restore and pack that you can combining with custom build targets. It's make easier build process.
If you still want to write program to added references to .csproj you can create extension for Visual Studio.
UPD1. Get IEnumerable<Project> from GlobalProjectCollection and parse libraries names from the Include attributes:
GetReferences -
public static IEnumerable<string> GetReferences(IEnumerable<Project> project)
{
return project.Select(p => p.GetItems("Reference").Select(i => i.EvaluatedInclude);
}
After that check availability this library in your NuGet repository with help your code and if exists, then remove current reference and create new:
CreateReference-
using Microsoft.Build.Evaluation;
using System.Collections.Generic;
namespace NuGetReference
{
public static class Reference
{
public static void CreateReference(string projectName, string packageName, string packageVersion)
{
Project project = ProjectCollection.GlobalProjectCollection.LoadProject(projectName);
project.AddItemFast("PackageReference", packageName, new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Version", packageVersion) });
project.Save();
}
}
}
Migrate from packages.config to PackageReference | Project Class | GlobalProjectCollection | AddItemFast
Short answer.
You can't.
The NuGet.Core dll is NuGet 2.x, while PackageReference was introduced in 4.x
4.x has a more modular approach, and there isn't one package you can use to achieve your goal.
If you have Visual Studio 2017, you can use the latest 15.7 release (to be released in 2 weeks or just use the preview) to migrate your packages to PackageReference.
That's a built in tool that should handle most of your scenarios if compatible.
If you're really stuck with having to this programmatically the following code should be a great start.

Categories

Resources