In the previous article of this series, we discussed how we can access the configuration file like JSON files, and display the data from the file using .NET Core Application. Now, we will learn how we can create shared library for a particular project or create packages from the shared library, so that we can reuse the packages as library in other projects. At the same time, we can also upload the packages into the nuget.org, so that the other developers can also download the package and install into their own project for using the library.
If you want to look at the previous articles of this series, please visit the links given below.
In mixed development ecosystems, we have two options to share libraries. First, we can develop a .NET Standard library, which in theory can be shared directly between the Applications so long as the versions match up. Alternatively, you can use multi-targeting to cross-compile a library for more than one platform.
Concept of PCL or share library through the .NET Standard
Microsoft introduced .NET Standard to provide us a common standard environment for APIs across Microsoft development ecosystem. It can be seen as a successor to Portable Class Libraries (PCLs), which simplifies the business of targeting the different platforms. When PCLs are based on the profiles defined by intersecting platform capabilities, the .NET Standard provides a curated set of APIs.
The main advantage is that we can create libraries, which can be directly referenced by both .NET Framework and .NET Core Applications. You just need to ensure that the .NET Standard Library NuGet package is added to any .NET Framework Application, which wants to reference a .NET Standard library.
Given that there have been more than half a dozen versions of .NET Standard. Already, it’s not always immediately clear, which version to target. In general, the higher the version of .NET Standard, the wider the range of APIs, which will be available to you. The lower the version, the wider the range of platforms, you’ll be able to support.
The main key point is that .NET Framework version support for .NET Standard is pretty limited. Each version of .NET Standard is supported by a different version of .NET Framework. For example, if you want a library to be available to both .NET Core and .NET Framework 4.5.2 Applications, you’ll need to target .NET Standard 1.2.
Although there is an increasing adoption of .NET Standard among commonly-used libraries, the support for anything below version 1.3 is pretty sketchy. In practical terms, this can tie you into a minimum .NET Framework version of 4.6.
Most development shops have a mixture of .NET framework versions in the production. This can make the adoption of .NET Standard libraries quite difficult, particularly in large development ecosystems. You would be surprised how much .NET 4.0 or even 3.5 is lurking in some dark corners. Even version 4.5.2 may still be supported by Microsoft, but it is limited to the version 1.2 of .NET Standard.
Multi-targeting Framework
Since we already discussed the main advantage of .NET Core is that it can be used or implemented in the cross platform domain. For bigger development environments, which cannot guarantee a more recent vintage of the .NET framework, multi-targeting can help to widen the reach of the shared libraries. This allows you to compile a single project natively for both .NET Standard and your preferred version of .NET Framework, though it comes at a cost of having to manage multiple sets of the compiled output.
This has become a lot more straightforward since Visual Studio 2017 was released. Multi-targeting was a pretty choppy experience in Visual Studio 2015, using the old JSON-based xproj format. You can get a project to compile for more than one framework, but you are not able to use a direct project reference in a .NET Framework project. This required some pretty difficult workarounds, which you either had to migrate the target project to the xproj structure or distribute the dependency, using NuGet. Neither approach was ideal.
This has been addressed in the new tooling, though you still have to manually edit the project files to get it working. Re-loading the solution is also recommended after making any manual changes to the frameworks.
The example given below shows how you would adjust the TargetFramework element to get a project to compile for more than one framework.
- <PropertyGroup>
- <TargetFrameworks>net452;netstandard1.3</TargetFrameworks>
- </PropertyGroup>
When you compile this project, you will see the two outputs in the BIN folder, one for each of the specified frameworks. This allows you to create project references to the shared assembly, both for the projects built with .NET Framework 4.5.2 or anything built on .NET Core 1.0.
Actually till now as a developer, we all use NuGet packages as one of the main supportive tool to access the different types of third party API but as NuGet package is an open source library, we any one can contribute his or her own developed library, so that every one can download and install it into their own development projects.
Packages
.NET Core is split into a set of packages, which provide primitive, higher-level data types, app composition types and common utilities. Each of these packages represent a single assembly of the same name. For example, System.Runtime contains System.Runtime.dll.
There are advantages to define the packages in a fine-grained manner, which are given below.
- Fine-grained packages can ship on their own schedule with relatively limited testing of other packages.
- Fine-grained packages can provide differing OS and CPU support.
- Fine-grained packages can have dependencies and they are specific to only one library.
- Apps are smaller because unreferenced packages don't become part of the app distribution.
Some of these benefits are only used in certain circumstances. For example, NET Core packages will typically ship on the same schedule with the same platform support. In the case of Servicing, fixes can be distributed and installed as small single package updates. Due to the narrow scope of change, the validation and time to make a fix available is limited to what is needed for a single library.
The following is a list of the key NuGet packages for .NET Core
- System.Runtime - The most fundamental .NET Core package, including Object, String, Array, Action, and IList<T>.
- System.Collections - A set of (primarily) generic collections, including List<T> and Dictionary<TKey,TValue>.
- System.Net.Http - A set of types for HTTP network communication, including HttpClient and HttpResponseMessage.
- System.IO.FileSystem - A set of types for reading and writing to local or networked disk-based storage, including File and Directory.
- System.Linq - A set of types to query objects, including Enumerable and ILookup<TKey,TElement>.
- System.Reflection - A set of types for loading, inspecting and activating types, including Assembly, TypeInfoand MethodInfo.
.Net Core Frameworks
.NET Core packages supports a set of runtime frameworks. Frameworks describe an available API set (and potentially other characteristics), which you can rely on when you target a given framework. They are versioned as new APIs are added.
For example, System.IO.FileSystem supports the frameworks given below.
- NETFramework,Version=4.6
- .NETStandard,Version=1.3
- 6 Xamarin platforms (for example, xamarinios10)
It is useful to contrast the first two of these frameworks, since they are the examples of the two different ways on which frameworks are defined.
The .NETFramework,Version=4.6 framework represents the available APIs in the .NET Framework 4.6. You can produce the compiled libraries with the .NET Framework 4.6 reference assemblies and then distribute those libraries in NuGet packages in a net46 lib folder. It will be used for apps that target the .NET Framework 4.6 or that are compatible with it. This is how all the frameworks have traditionally worked.
The .NETStandard, Version=1.3 framework is a package-based framework. It relies on the packages that targets the framework to define and expose APIs in terms of the framework.
Package-based Frameworks
There is a two-way relationship between the frameworks and the packages. The first part is defining APIs available for a given framework, for example netstandard1.3. Packages that targets netstandard1.3 (or compatible frameworks, like netstandard1.0) defines APIs available for netstandard1.3. This may sound like a circular definition, but it is not. By virtue of being package-based, the API definition for the framework comes from the packages. The framework itself doesn't define any APIs.
The second part of the relationship is an asset selection. Packages can contain assets for multiple frameworks. Given a reference to a set of packages and/ or metapackages, the framework is needed to determine which asset should be selected, for example net46 or netstandard1.3. It is important to select the correct asset. For example, a net46 asset is not likely to be compatible with .NET Framework 4.0 or .NET Core 1.0.
The two primary package-based frameworks used with .NET Core are given below.
.NET Standard
The .NET Standard framework represents the APIs defined by and built on top of the .NET Standard Library. Libraries, which are intended to run on multiple runtimes should target this framework. They will be supported on any .NET Standard compliant runtime, such as .NET Core, .NET Framework and Mono/Xamarin. Each of these runtimes supports a set of .NET Standard versions, which depends on which APIs they implement.
The net standard framework implicitly references the NETStandard.Library metapackage. For example, the following MSBuild project file indicates that the project targets netstandard1.6, which references the .NET Standard Library version 1.6 metapackage.
Now, to demonstrate this, we first need to create a .NET Core Application with project type ASP.NET Core Web Application (.NET Core) and then select Empty Project.
Now, go to Solution Explorer and right click on the mouse. Click Add New Project.
Now, select Class Library (.NET Standard) project, type the project name and click OK button.
Now, build the solution to check whether there are any errors or not. Now, if the build is error free, then we will create the package file for this library. There are two options to do this.
- The easiest way is to select the project file in Solution Explorer and right click on the mouse. Now, click Pack option.
- Second option is Select the project file in Solution Explorer and right click the mouse. Click Properties option. Now, click Package tab and select Generate NuGet Package on Build.
In both the cases, the below mentioned package file has been created in the bin folder.
Now, if we want to upload this file into the NuGet Website, just rename with extenstion .zip and then upload the package into NuGet site or we can install the package as a local package from Package Manager console.
Now, add the code given below in message.cs file.
- using System;
- namespace MessageLibrary {
- public class message {
- public static string MessageInfo() {
- return "This is Shared Package for .Net App";
- }
- }
- }
Now, add the reference of the library in our main project. The project reference looks, as shown below.
Now, write down the code given below.
Startup.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- namespace Prog4_Package {
- public class Startup {
-
-
- public void ConfigureServices(IServiceCollection services) {}
-
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
- loggerFactory.AddConsole();
- if (env.IsDevelopment()) {
- app.UseDeveloperExceptionPage();
- }
- app.Run(async(context) => {
- var message = MessageLibrary.message.MessageInfo();
- await context.Response.WriteAsync($ "Message From Library {message}!!");
- });
- }
- }
- }
Program.cs
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Hosting;
- namespace Prog4_Package {
- public class Program {
- public static void Main(string[] args) {
- var host = new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseIISIntegration().UseStartup < Startup > ().UseApplicationInsights().Build();
- host.Run();
- }
- }
- }
Now, execute the program. The output is given below.
You can read the next part here,