How can I make a .NET Core class library and reference it from a .NET 4.6 project?
Asked Answered
D

2

21

I want to:

  • Make a class library that defines some interfaces and simple generic helper classes. It'll rely on generic collections and IQueryable<T> but no third party dependencies (well, JetBrains.Annotations).
  • Be able to reference that class library from everywhere (specifically UWP, net46 and ASP.Net Core RC2)
  • Ideally, use the project.json system throughout, although I'm prepared to sacrifice that if need be.
  • Publish the finished library to a NuGet feed and from there use it in other apps

When creating my class library project in Visual Studio 2015.2, I found the Class Library (.NET Core) template, which states

A project template for creating a class library as a NuGet package that can target any platform

Any platform! Brilliant... But I can't get it to work. After a lot of fiddling, I currently have the following project.json (I've probably completely broken it by now):

{
"title": "My Really Useful Class Library",
"copyright": "Copyright © 2015-16 Tigra Astronomy, all rights reserved",
"description": "Really neat stuff",
"language": "en-GB",
"version": "1.0.0-*",
"dependencies": {
    "JetBrains.Annotations": "10.1.4",
    },
"frameworks": {
    "netstandard1.5": {
        "imports": "dnxcore50",
        "dependencies": {
            "NETStandard.Library": "1.5.0-rc2-24027",
            "System.Linq.Expressions": "4.0.11-rc2-24027"
            }
        }
    "net46": {
        "frameworkAssemblies": {
            "System.Collections": "4.0.*"
            },
        "dependencies": {}
        }
    },
    "buildOptions": {
        "xmlDoc": true
        }
}

The next thing I did was create my .NET Framework 4.6 project in the same solution, and try to reference the class library. It lets me add the reference but I'm getting build errors, unresolved symbols, R# is unhappy, etc.

I guess I'm not doing it right (no surprise, really, as I'm fumbling in the dark).

I've read some of the docs about TFMs, frameworks and libraries but none of it really makes much sense.

What do I really need to put in my class library's project.json, so that I can reference it from my .net framework 4.6 app, and also from UWP and ASP.NET Core RC2 apps? Is this really the right approach or have I started out on the wrong foot?

Dodeca answered 18/6, 2016 at 23:8 Comment(2)
Please excuse me for not selecting a 'correct' answer yet. I'm still working through a number of scenarios having upgraded to the latest RTM releases and the latest preview tooling.Dodeca
Make sure to check the <Project ToolsVersion="14.0" element in your cs proj. VS doesn't seem to load the tooling to work with .net core references if you aren't using that version in the referencing project.Spurn
C
34

Right now there are two ways of creating C# projects: xproj and csproj. Assuming we're using project.json for both of them, that still works differently for the project types -- for xproj, the project.json contains everything needed to build the project; for csproj, it only contains the nuget dependencies.

That said, some project types, like UWP, cannot be built with xproj due to needing a more complicated build pipeline than what xproj/project.json supports. (BTW, this was one key reason for moving back to msbuild.)

There are also two ways of creating a .NET Standard-based class library: you can use xproj with project.json, as you've done, or you can create a regular csproj "Portable Class Library" project. With VS 2015 Update 3 RC, you can change the PCL to target a .NET Standard version (netstandard1.x instead of a PCL profile, 259, etc).

If you use a csproj-based class library to target netstandard1.x, things should just work for you when adding project references. Note that UWP currently supports up to netstandard1.4 based on the platform map. The challenge is if you want to use an xproj/project.json-based project instead. One key reason for using xproj today is to enable cross-compiling between multiple target frameworks. That is to say, create more than one output from your project. That's different than creating a single output that can be referenced from any compatible project. Both have their uses, it depends on your needs.

If you decide to create an xproj-based class library, there's a workaround you can use to reference it from a UWP project or any other compatible project type if the "Add References" dialog doesn't work (which it doesn't as csproj->xproj is pretty much broken). Instead of using the dialog, edit your UWP csproj to point to the output of the xproj like this:

<Reference Include="System.Reactive.Interfaces">
  <HintPath>..\System.Reactive.Interfaces\bin\$(Configuration)\netstandard1.0\System.Reactive.Interfaces.dll</HintPath>
</Reference>

The above snippet is taken from the Rx.NET UWP Test Runner here

If you do this, you'll also need to add build dependency from your UWP project to your xproj since MSBuild/Visual Studio won't know about it and build things in the wrong order. To do this, right click on your UWP project in the Solution Explorer, then select "Build Dependencies -> Project Dependencies". In that dialog, check the box for your xproj to ensure that VS/MSbuild knows to build that one first.

You can see the full Rx.NET solution here, which includes xproj->xproj references and the UWP -> xproj references I mention above.

Castleman answered 19/6, 2016 at 13:55 Comment(7)
Thanks Oren, that's starting to make some sense now. I can also begin to understand why MS is saying "wait for the new tooling". Perhaps I should try VS2015.3 RC... I probably do want my library to ultimately work on UWP/ARM based targets under IoT Core, hence my wish to use an xproj.Dodeca
If your goal is to be compatible with UWP and ASPNet Core 1.0 and you only want a single output, the easiest approach would likely be a csproj that targets netstandard1.4. You don't need an xproj for that and project-to-project references are easier that way.Castleman
Oh in fact I can see that link in 2015 Update 2... Is 2015.3 RC worth installing at this stage? As it is an RC it should be fairly stable...Dodeca
When I changed my PCL to target .NETStandard1.5, I was then unable to install JetBrains.Annotations - during the package restore I get an error saying that "AnyCPU" is incompatible with one of the project's targets. Changing the build configuration to 'x86' didn't seem to help. Conversely, I'm able to install that package into my .NETCore based library, which is also targeting NetStandard1.5. Another mystery! Is this a tooling issue or some limitation?Dodeca
It's my understanding that despite being available in Update 2, using .NETStandard in PCL project types didn't work very well. It's supposed to work much better in Update 3. If you need to bring in a non-netstandard dependency, then you'll need to use an imports statement in your target framework to override the NuGet compat checking and force the import.Castleman
@OrenNovotny Do you plan to update the Portable.BouncyCastle package to target NetStandard? (the repo has no issue tracker)Libra
As a follow-up to this, I recently blogged about how to do this with VS 2017: oren.codes/2017/01/04/…Castleman
V
3

The new project templates/.xproj works a bit differently. The new Class Libraries (and application templates) produce nuget packages, rather than plain assemblies.

Within that nuget package all targets are packed into it. That being said, you add the new project same way as you add any other nuget package: You put the nuget into a nuget feed, reference this in Visual Studio and then fetch it from there.

If you don't have a nuget server running (Visual Studio Team Services + NuGet package, myget, self-hosted) you can also put the packages into a folder (local or network share) and add this folder as a nuget source.

If that's "too" much work, you can also create two projects into one folder: A *.csproj and a *.xproj. The *.csproj targets the .NET 4.6 Framework and the *.xproj stays as you pointed above and has multiple targets. With this setup, you can normally reference the project the way you used before (if they are in the same solution), by simply adding an reference.

Victual answered 19/6, 2016 at 0:30 Comment(1)
The new templates do not produce nuget packages by default. This was part of DNX/RC1 but the RC2 project templates don't do this automatically in VS. You'd have to run dotnet pack to create the packages.Castleman

© 2022 - 2024 — McMap. All rights reserved.