Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 108

ASP.

NET Core Tutorials


ASP.NET Core is a new version of ASP.NET by Microsoft. It is an
open-source web framework which can be run on Windows, Mac, or
Linux.

These tutorials will help you understand ASP.NET Core web


application step by step. Tutorials are broken down into chapters,
where each chapter contains a number of related topics that are
packed with easy to understand explanations and real-world
examples.

These tutorials are designed for beginners and professionals who


want learn how to build ASP.NET Core web applications step by step.

Prerequisites
Basic knowledge of C#, HTML, Visual Studio, and Object Oriented
Programming is required.

.NET Core Overview


.NET Core is a new version of .NET Framework, which is a free, open-source, general-
purpose development platform maintained by Microsoft. It is a cross-platform
framework that runs on Windows, macOS, and Linux operating systems.

.NET Core Framework can be used to build different types of applications such as
mobile, desktop, web, cloud, IoT, machine learning, microservices, game, etc.

.NET Core is written from scratch to make it modular, lightweight, fast, and cross-
platform Framework. It includes the core features that are required to run a basic .NET
Core app. Other features are provided as NuGet packages, which you can add it in your
application as needed. In this way, the .NET Core application speed up the
performance, reduce the memory footprint and becomes easy to maintain.

Why .NET Core?


There are some limitations with the .NET Framework. For example, it only runs on the
Windows platform. Also, you need to use different .NET APIs for different Windows
devices such as Windows Desktop, Windows Store, Windows Phone, and Web
applications. In addition to this, the .NET Framework is a machine-wide framework.
Any changes made to it affect all applications taking a dependency on it. Learn more
about the motivation behind .NET Core here.

Today, it's common to have an application that runs across devices; a backend on the
web server, admin front-end on windows desktop, web, and mobile apps for
consumers. So, there is a need for a single framework that works everywhere. So,
considering this, Microsoft created .NET Core. The main objective of .NET Core is to
make .NET Framework open-source, cross-platform compatible that can be used in a
wide variety of verticals, from the data center to touch-based devices.

.NET Core Characteristics


Open-source Framework: .NET Core is an open-source framework  maintained by
Microsoft and available on GitHub under MIT and Apache 2 licenses. It is a .NET
Foundation project .

You can view, download, or contribute to the source code using the following GitHub
repositories:

 Language compiler platform Roslyn: https://github.com/dotnet/roslyn


 .NET Core runtime: https://github.com/dotnet/runtime
 .NET Core SDK repository. https://github.com/dotnet/sdk
 ASP.NET Core repository. https://github.com/dotnet/aspnetcore

Cross-platform: .NET Core runs on Windows, macOS, and Linux operating systems.


There are different runtime for each operating system that executes the code and
generates the same output.

Consistent across Architectures: Execute the code with the same behavior in


different instruction set architectures, including x64, x86, and ARM.

Wide-range of Applications: Various types of applications can be developed and run


on .NET Core platform such as mobile, desktop, web, cloud, IoT, machine learning,
microservices, game, etc.

Supports Multiple Languages: You can use C#, F#, and Visual Basic programming
languages to develop .NET Core applications. You can use your favorite IDE,
including Visual Studio 2017/2019, Visual Studio Code, Sublime Text, Vim, etc.
Modular Architecture: .NET Core supports modular architecture approach using
NuGet packages. There are different NuGet packages for various features that can be
added to the .NET Core project as needed. Even the .NET Core library is provided as a
NuGet package. The NuGet package for the default .NET Core application model
is Microsoft.NETCore.App .

This way, it reduces the memory footprint, speeds up the performance, and easy to
maintain.

CLI Tools: .NET Core includes CLI tools (Command-line interface) for development


and continuous-integration.

Flexible Deployment: .NET Core application can be deployed user-wide or system-


wide or with Docker Containers .

Compatibility: Compatible with .NET Framework and Mono APIs by using .NET


Standard specification .

.NET Core Version History


Version Latest Version Visual Studio Release Date End of Support

.NET 5 Preview 1 VS 2019 16th March, 2020

.NET Core 3.x - latest 3.1.3 VS 209 24th March, 2020 12th March, 2022

.NET Core 2.x 2.1.17 VS 2017, 2019 24th March, 2020 21st August, 2021

.NET Core 1.x 1.1.13 VS 2017 14th May, 2019 27th May, 2019

Both, .NET 3.1, and .NET Core 2.1 will have long term support.

.NET Core 3.x applications only run on .NET Core Framework.

.NET Core 2.x applications run on .NET Core as well as .NET Framework.

.NET Core Composition


The .NET Core Framework composed of the following parts:
.NET Core

 CLI Tools: A set of tooling for development and deployment.


 Roslyn: Language compiler for C# and Visual Basic
 CoreFX: Set of framework libraries.
 CoreCLR: A JIT based CLR (Command Language Runtime).

Useful Links
 Find .NET Core type and member declarations, files, and assemblies on .NET Core Source
Browser.
 Get the help on .NET Core types on .NET Core API Reference Docs.
 Learn about .NET Core in detail on https://docs.microsoft.com/en-us/dotnet/core
 Download .NET Core runtime and SDK from https://dotnet.microsoft.com/download/dotnet-
core

ASP.NET Core Overview


ASP.NET Core is the new version of the ASP.NET web framework
mainly targeted to run on .NET Core platform.

ASP.NET Core is a free, open-source, and cross-platform framework


for building cloud-based applications, such as web apps, IoT apps,
and mobile backends. It is designed to run on the cloud as well as
on-premises.
Same as .NET Core, it was architected modular with minimum
overhead, and then other more advanced features can be added as
NuGet packages as per application requirement. This results in high
performance, require less memory, less deployment size, and easy to
maintain.

ASP.NET Core is an open source framework supported by Microsoft


and the community, so you can also contribute or download the
source code from the ASP.NET Core Repository on Github .

ASP.NET 3.x runs only on .NET Core 3.x, whereas ASP.NET Core 2.x
runs on .NET Core 2.x as well as .NET Framework.

ASP.NET Core

Why ASP.NET Core?


 Supports Multiple Platforms: ASP.NET Core applications can run on
Windows, Linux, and Mac. So you don't need to build different apps for
different platforms using different frameworks.
 Fast: ASP.NET Core no longer depends on System.Web.dll for browser-
server communication. ASP.NET Core allows us to include packages that we
need for our application. This reduces the request pipeline and improves
performance and scalability.
 IoC Container: It includes the built-in IoC container for automatic
dependency injection which makes it maintainable and testable.
 Integration with Modern UI Frameworks: It allows you to use and
manage modern UI frameworks such as AngularJS, ReactJS, Umber,
Bootstrap, etc. using Bower (a package manager for the web).
 Hosting: ASP.NET Core web application can be hosted on multiple platforms
with any web server such as IIS, Apache etc. It is not dependent only on IIS
as a standard .NET Framework.
 Code Sharing: It allows you to build a class library that can be used with
other .NET frameworks such as .NET Framework 4.x or Mono. Thus a single
code base can be shared across frameworks.
 Side-by-Side App Versioning: ASP.NET Core runs on .NET Core, which
supports the simultaneous running of multiple versions of applications.
 Smaller Deployment Footprint: ASP.NET Core application runs on .NET
Core, which is smaller than the full .NET Framework. So, the application
which uses only a part of .NET CoreFX will have a smaller deployment size.
This reduces the deployment footprint.

.NET Core vs ASP.NET Core


.NET Core ASP.NET Core

Open-source and Cross-platform Open-source and Cross-platform

.NET Core is a runtime to execute ASP.NET Core is a web framework to build web apps, IoT apps, and mobile
applications build on it. backends on the top of .NET Core or .NET Framework.

Install .NET Core Runtime to run There is no separate runtime and SDK are available for ASP.NET Core. .NET Core
applications and install .NET Core SDK to runtime and SDK includes ASP.NET Core libraries.
build applications.

.NET Core GitHub Repository: ASP.NET Core GitHub Repository: https://github.com/dotnet/aspnetcore


.NET Core Runtime
.NET Core SDK

.NET Core 3.1 - latest version ASP.NET Core 3.1


There is no separate versioning for ASP.NET Core. It is the same as .NET Core
versions.

Install .NET Core, ASP.NET Core


Here you will learn to prepare a development environment for
building .NET Core/ASP.NET Core applications.

.NET Core can be installed in two ways: By installing Visual Studio


2017/2019 or by installing .NET Core Runtime or SDK.

.NET Core installer already contains ASP.NET Core libraries, so there


is no separate installer for ASP.NET Core.
Install Visual Studio
Currently, .NET Core 2.1 and .NET Core 3.1 is having long term
support. Visual Studio 2017 supports .NET Core 2.1, whereas Visual
Studio 2019 supports both the versions.

You can use your favorite IDE, such as Visual Studio, Visual Studio
Code, Sublime Text, etc. to develop, restore, build, and run .NET
Core application. Here, we will use Visual Studio 2019.

If you don�t have Visual Studio on your development PC, then it is


recommended to install the latest Visual Studio 2019. If you already
have either Visual Studio 2017 or 2019, then you already have
installed .NET Core 2.1.

Download and install Visual Studio 2019 based on your OS from  here.
Select the appropriate edition as per your license. The community
edition is free for students, open-source contributors, and
individuals.

During installation, select ".NET Core cross-platform development"


workload. This will install .NET Core 2.1. However, you need to install
.NET Core 3.1 SDK separately.
Once installed, you can verify it by opening a command prompt (or
terminal in Mac) and type dotnet --version and press Enter. This
will display the installed version and usage information, as shown
below.

C:\Users\dev>dotnet --version

2.1.805

ADVERTISEMENT
Install .NET Core 3.x
As you have seen, Visual Studio 2019 installer includes .NET Core 2.1
but not .NET Core 3.x. You need to install it separately.

To download the latest version of .NET Core, go


to https://dotnet.microsoft.com/download  and select the platform you
are using.

Install .NET Core SDK for Windows


As you can see above, .NET Core Runtime and .NET Core SDK are
different things. .NET Core Runtime is only used to run .NET Core
application, whereas .NET Core SDK includes tools and libraries to
develop .NET Core applications. To set up a development
environment, we need to install .NET Core SDK for the platform we
use for development such as Windows, Linux, or Mac. Here we will
install .NET Core SDK because we are preparing a development
environment for building .NET Core applications. If you are aiming to
run .NET Core application, then install .NET Core Runtime on your
server or cloud or client desktop.

Click on the Download .NET Core SDK button to download the


latest version of .NET Core SDK installer. It will download .NET Core
3.1 SDK as of this writing.

After downloading the installer, click on it to start the installation.

Click on Install button and follow the wizard to install .NET Core 3.1
SDK.
Create ASP.NET Core Application
Here, we will learn how to create our first ASP.NET Core 3.0
application in Visual Studio 2019.

Open Visual Studio 2019 and click on Create a new project, as


shown below.

Create a New ASP.NET Core 3.0 Project

The "Create a new project" dialog box includes different .NET Core
3.0 application templates. Each will create predefined project files
and folders depends on the application type. Here we will create a
simple web application, so select ASP.NET Core Web
Application template and click Next, as shown below.

Select Application Template

Next, give the appropriate name, location, and the solution name for
the ASP.NET Core application. In this example, we will give the name
"MyFirstCoreWebApp" and click on the Create button, as shown
below.
Configure Project

Next, select appropriate ASP.NET Core Web application template


such as Empty, API, Web Application, MVC, etc. Here, we want to
create a web application, so select the Web Application template.
We don't want HTTPS at this point, so uncheck Configure for
HTTPS checkbox, as shown below. Also, make sure you have
selected the appropriate .NET Core and ASP.NET Core versions. Click
on the Create button to create a project.
Select Web Application Template

This will create a new ASP.NET Core web project in Visual Studio
2019, as shown below. Wait for some time till Visual Studio restores
the packages in the project. Restoring process means Visual Studio
will automatically add, update or delete configured dependencies as
NuGet packages in the project.
Create ASP.NET Core 3 Application

We will understand the project structure in the next chapter. To run


this web application, click on IIS Express or press Ctrl + F5. This
will open the browser and display the following result.
The above output comes from the Index.cshtml page under
the Pages folder.

You can also see the IIS express icon on the system tray. Right click
on it. You can see the ASP.NET sites currently running in your
development machine.

ASP.NET Core sites in System Tray


Thus, we can create a new cross-platform ASP.NET Core 3.0
application that runs on .NET Core.

ASP.NET Core - Project Structure


Here, you will learn about the project structure and significance of
each file created by ASP.NET Core 2.0 application template using
Visual Studio 2017.

The following is a default project structure when you create an empty


ASP.NET Core application in Visual Studio.

ASP.NET Core Project Structure

The above solution explorer displays project solution. We can change


it to folder view by clicking Solution and Folders icon and selecting
Folder View option. This displays the solution explorer with all project
folders and files as shown below.

Solution Explorer - Folder View

 Note:

ASP.NET Core project files and folders are synchronized with physical files and
folders. If you add a new file or folder in project folder then it will directly reflect in
the solution explorer. You don't need to add it in the project explicitly by right
clicking on the project.
.csproj
ASP.NET Core 1.0 does not create .csproj file, instead, it uses .xproj
and project.json files to manage the project. This has changed in
ASP.NET Core 2.0. Visual Studio now uses .csproj file to manage
projects. We can edit the .csproj settings by right clicking on the
project and selecting Edit <project-name>.csproj as shown below.

Edi
t .csproj

The .csproj for the above project looks like below.


Edit .csproj

The csproj file includes settings related to targeted .NET Frameworks,


project folders, NuGet package references etc.
ADVERTISEMENT

Dependencies
The Dependencies in the ASP.NET Core 2.1 project contain all the
installed server-side NuGet packages, as shown below.
Dependencies

Right click on "Dependencies" and then click "Manage NuGet


Packages.." to see the installed NuGet packages, as shown below.

Dependencies
As you can see, it has installed three
packages, Microsoft.AspNetCore.App package is for ASP.NET web
application, Microsoft.AspNetCore.Razor.Design package is for
Razor engine, and Microsoft.NETCore.App package is for .NET Core
API.

You can install all other required server side dependencies as NuGet
packages from Manage NuGte Packages window or using Package
Manager Console.

Properties
The Properties node includes launchSettings.json file which includes
Visual Studio profiles of debug settings. The following is a default
launchSettings.json file.
launchSettings.json

We can also edit settings from the debug tab of project properties.
Right click on the project -> select Properties -> click Debug tab.
Project Properties

In the debug tab, select a profile which you want to edit as shown
above. You may change environment variables, url etc.

ASP.NET Core - wwwroot Folder


By default, the wwwroot folder in the ASP.NET Core project is
treated as a web root folder. Static files can be stored in any folder
under the web root and accessed with a relative path to that root.

In the standard ASP.NET application, static files can be served from


the root folder of an application or any other folder under it. This has
been changed in ASP.NET Core. Now, only those files that are in the
web root - wwwroot folder can be served over an http request. All
other files are blocked and cannot be served by default.

Generally, there should be separate folders for the different types of


static files such as JavaScript, CSS, Images, library scripts etc. in the
wwwroot folder as shown below.

wwwroot

You can access static files with base URL and file name. For example,
we can access above app.css file in the css folder
by http://localhost:<port>/css/app.css.
Remember, you need to include a middleware for serving static files
in the Configure method of Startup.cs. Learn more about it in Serving
Static File section.

Rename wwwroot Folder


You can rename wwwroot folder to any other name as per your
choice and set it as a web root while preparing hosting environment
in the program.cs.

For example, let's rename wwwroot folder to Content folder. Now,


call UseWebRoot() method to configure Content folder as a web root
folder in the Main() method of Program class as shown below.

public class Program


{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseWebRoot("Content")
.UseIISIntegration()
.UseStartup<MyStartup>()
.Build();

host.Run();
}
}

Thus, you can rename the default web root folder wwwroot as per
your choice.

ASP.NET Core - Program.cs


ASP.NET Core web application is actually a console project which
starts executing from the entry point public static void
Main() in Program class where we can create a host for the web
application.
Setup Host in ASP.NET Core 2.x
The following is the Program class in ASP.NET Core 2.x:

Program.cs

 Copy

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;

namespace MyFirstCoreApp
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>


WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}

As you can see above, the Main() method calls method


expression BuildWebHost() to build web host with pre-configured
defaults. The BuildWebHost expression can also be written as a
method that returns IWebHost as shown below.

public static void Main(string[] args)


{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args)


{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}

Let's understand hosting steps.

The WebHost is a static class which can be used for creating an


instance of IWebHost and IWebHostBuilder with pre-configured
defaults. The CreateDefaultBuilder() method creates a new instance
of WebHostBuilder with pre-configured defaults. Internally, it
configures Kestrel, IISIntegration and other configurations. The
following is CreateDefaultBuilder() method.

CreateDefaultBuilder()

 Copy

public static IWebHostBuilder CreateDefaultBuilder(string[] args)


{
var builder = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;

config.AddJsonFile("appsettings.json", optional: true,


reloadOnChange: true)
.AddJsonFile($ "appsettings.
{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new
AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional:
true);
}
}

config.AddEnvironmentVariables();

if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetS
ection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseIISIntegration()
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes =
context.HostingEnvironment.IsDevelopment();
});

return builder;
}

As you can see above, the CreateDefaultBuilder method creates an


instance of WebHostBuilder and sets up Kestrel, content root
directory, IIS integration.

Kestrel  is an open-source, cross-platform web server for ASP.NET


Core. It is designed to be used behind proxy because it has not yet
matured to be exposed as a full-fledge web server.

It also calls ConfigureAppConfiguration() to load configurations from


appsettings.json files, environment variables and user secrets.
The ConfigureLogging() method setup logging to console and debug
window.

ASP.NET Core - Startup Class


Here, we will have an overview of Startup class contained in
Startup.cs in the root folder of the project.

ASP.NET Core application must include Startup class. It is like


Global.asax in the traditional .NET application. As the name suggests,
it is executed first when the application starts.
The startup class can be configured using UseStartup<T>() method at
the time of configuring the host in the Main() method
of Program class as shown below.

public class Program


{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args)


{
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}

The name "Startup" is by ASP.NET Core convention. However, we


can give any name to the Startup class, just specify it as the generic
parameter in the UseStartup<T>() method. For example, to name the
Startup class as MyStartup, specify it as .UseStartup<MyStartup>().

Open Startup class in Visual Studio by clicking on the Startup.cs in


the solution explorer. The following is a default Startup class in
ASP.NET Core 2.x.
startup.cs

As you can see, Startup class includes two public


methods: ConfigureServices and Configure.

The Startup class must include a Configure method and can


optionally include ConfigureService method.

ConfigureServices()
The Dependency Injection pattern is used heavely in ASP.NET Core
architecture. It includes built-in IoC container to provide dependent
objects using constructors.

The ConfigureServices method is a place where you can register your


dependent classes with the built-in IoC container. After registering
dependent class, it can be used anywhere in the application. You just
need to include it in the parameter of the constructor of a class
where you want to use it. The IoC container will inject it
automatically.

ASP.NET Core refers dependent class as a Service. So, whenever you


read "Service" then understand it as a class which is going to be
used in some other class.
ConfigureServices method includes IServiceCollection parameter to
register services to the IoC container. Learn more about it in the
next chapter.

Configure()
The Configure method is a place where you can configure application
request pipeline for your application using IApplicationBuilder
instance that is provided by the built-in IoC container.

ASP.NET Core introduced the middleware components to define a


request pipeline, which will be executed on every request. You
include only those middleware components which are required by
your application and thus increase the performance of your
application.

The following is a default Configure method.

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World!");
});
}

As you can see, the Configure method includes three parameters


IApplicationBuilder, IHostingEnvironment, and ILoggerFactory by
default. These services are framework services injected by built-in
IoC container.

At run time, the ConfigureServices method is called before the


Configure method. This is so that you can register your custom
service with the IoC container which you may use in the Configure
method.
.NET Core Command-Line Interface
The .NET Core command-line interface (CLI) is a new cross-platform
tool for creating, restoring packages, building, running and
publishing .NET applications.

We created our first ASP.NET Core application using Visual Studio in


the previous chapter. Visual Studio internally uses this CLI to restore,
build and publish an application. Other higher level IDEs, editors and
tools can use CLI to support .NET Core applications.

The .NET Core CLI is installed with .NET Core SDK for selected
platforms. So we don't need to install it separately on the
development machine. We can verify whether the CLI is installed
properly by opening command prompt in Windows and writing dotnet
and pressing Enter. If it displays usage and help as shown below
then it means it is installed properly.

.NET Core Command-line Interface

Command Structure
The following is a command structure.
dotnet <command> <argument> <option>

All the commands start with driver named dotnet. The driver starts
the execution of the specified command. After dotnet, we can supply
command (also known as verb) to perform a specific action. Each
command can be followed by arguments and options. The following
are .NET Core 2.x CLI commands.

Basic Commands Description

new Creates a new project, configuration file, or solution based on the specified template.

restore Restores the dependencies and tools of a project.

build Builds a project and all of its dependencies.

Run Runs source code without any explicit compile or launch commands.

publish Packs the application and its dependencies into a folder for deployment to a hosting system.

test Executes unit tests.

vtest Runs tests from the specified files.

pack Packs the code into a NuGet package.

clean Cleans the output of a project.

sln Modifies a .NET Core solution file.

help Display help on the specified command

store Stores the specified assemblies in the runtime package store.

Project Modification Commands Description

add package Adds a package reference to a project.

add reference Adds project-to-project (P2P) references.

remove package Removes package reference from the project.

remove reference Removes project reference

list reference Lists all project-to-project references

Advanced Commands Description

nuget delete Deletes or unlists a package from the server.


Advanced Commands Description

nuget locals Clears or lists local NuGet resources.

nuget push Pushes a package to the server and publishes it.

msbuild Builds a project and all of its dependencies.

dotnet install script Script used to install the .NET Core CLI tools and the shared runtime.

Let's create, restore, build, and run .NET Core console application
using command-line interface without using Visual Studio.
ADVERTISEMENT

Create a New Project


To create a new .NET Core project, we have to use new command
followed by template name argument. We can create console, class
library, web, mvc, webapi, razor, angular, react etc. projects using
CLI. Use console template to create a new .NET Core console
application.

The following creates new console project in the current directory


with the same name as current directory.

dotnet new console

The following command creates a new console project named


MyConsoleApp. The -n or --name option species the name of a
project.

dotnet new console -n MyConsoleApp

The following command creates a new console application named


MyConsoleApp to MyProjects directory. The -o or --output option is
used to specify an output directory where the project should be
generated.

dotnet new console -n MyConsoleApp -o C:\MyProjects


After creating a project, navigate to the project directories in
command prompt to apply project specific commands which is
C:\MyConsoleApp in our case.

Add Package Reference


We often need to add NuGet package reference for different
purposes. For example, apply the following command to add
Newtonsoft.json package to our console project.

C:\MyConsoleApp>dotnet add package Newtonsoft.json

This will add Newtonsoft.json package to our project. We can verify it


by opening .csproj file.

Restore Packages
To restore packages or to update existing packages, we can use
restore command as below.

C:\MyConsoleApp>dotnet restore

Build Project
To build a new or existing project, apply C:\MyConsoleApp>dotnet
build command.

Run project
To run our console project, apply dotnet run command as shown
below.
As you can see above, it displays an output "Hello World!".

Getting Help
We can get help on any .NET Core CLI commands by typing -h or
-help at the end of the command we want to get help on. For
example, dotnet new -h will display help on the new command,
arguments and options we can use with it, as shown below.
Thus, we can use .NET Core command-line interface to create,
restore packages, build, run, and publish different types of .NET Core
applications.

ASP.NET Core - Dependency Injection


ASP.NET Core is designed from scratch to support Dependency
Injection. ASP.NET Core injects objects of dependency classes
through constructor or method by using built-in IoC container.

Built-in IoC Container


ASP.NET Core framework contains simple out-of-the-box IoC
container which does not have as many features as other third party
IoC containers. If you want more features such as auto-registration,
scanning, interceptors, or decorators then you may replace built-in
IoC container with a third party container.
The built-in container is represented
by IServiceProvider implementation that supports constructor
injection by default. The types (classes) managed by built-in IoC
container are called services.

There are basically two types of services in ASP.NET Core:

1. Framework Services: Services which are a part of ASP.NET Core framework


such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory etc.
2. Application Services: The services (custom types or classes) which you as a
programmer create for your application.

In order to let the IoC container automatically inject our application


services, we first need to register them with IoC container.

Registering Application Service


Consider the following example of simple ILog interface and its
implementation class. We will see how to register it with built-in IoC
container and use it in our application.

public interface ILog


{
void info(string str);
}

class MyConsoleLogger : ILog


{
public void info(string str)
{
Console.WriteLine(str);
}
}

ASP.NET Core allows us to register our application services with IoC


container, in the ConfigureServices method of the Startup class.
The ConfigureServices method includes a parameter
of IServiceCollection type which is used to register application
services.

Let's register above ILog with IoC container in ConfigureServices()


method as shown below.
Example: Register Service

 Copy

public class Startup


{
public void ConfigureServices(IServiceCollection services)
{
services.Add(new ServiceDescriptor(typeof(ILog), new
MyConsoleLogger()));
}

// other code removed for clarity..


}

As you can see above, Add() method of IServiceCollection instance


is used to register a service with an IoC container.
The ServiceDescriptor  is used to specify a service type and its
instance. We have specified ILog as service type
and MyConsoleLogger as its instance. This will register ILog service as
a singleton by default. Now, an IoC container will create a singleton
object of MyConsoleLogger class and inject it in the constructor of
classes wherever we include ILog as a constructor or method
parameter throughout the application.

Thus, we can register our custom application services with an IoC


container in ASP.NET Core application. There are other extension
methods available for quick and easy registration of services which
we will see later in this chapter.

Understanding Service Lifetime


Built-in IoC container manages the lifetime of a registered service
type. It automatically disposes a service instance based on the
specified lifetime.

The built-in IoC container supports three kinds of lifetimes:

1. Singleton: IoC container will create and share a single instance of a service


throughout the application's lifetime.
2. Transient: The IoC container will create a new instance of the specified
service type every time you ask for it.
3. Scoped: IoC container will create an instance of the specified service type
once per request and will be shared in a single request.

The following example shows how to register a service with different


lifetimes.

Example: Register a Service with Lifetime

 Copy

public void ConfigureServices(IServiceCollection services)


{
services.Add(new ServiceDescriptor(typeof(ILog), new
MyConsoleLogger())); // singleton

services.Add(new ServiceDescriptor(typeof(ILog),
typeof(MyConsoleLogger), ServiceLifetime.Transient)); // Transient

services.Add(new ServiceDescriptor(typeof(ILog),
typeof(MyConsoleLogger), ServiceLifetime.Scoped)); // Scoped
}
ADVERTISEMENT

Extension Methods for Registration


ASP.NET Core framework includes extension methods for each types
of
lifetime; AddSingleton(), AddTransient() and AddScoped() methods
for singleton, transient and scoped lifetime respectively.

The following example shows the ways of registering types (service)


using extension methods.

Example: Extension Methods

 Copy

public void ConfigureServices(IServiceCollection services)


{
services.AddSingleton<ILog, MyConsoleLogger>();
services.AddSingleton(typeof(ILog), typeof(MyConsoleLogger));

services.AddTransient<ILog, MyConsoleLogger>();
services.AddTransient(typeof(ILog), typeof(MyConsoleLogger));
services.AddScoped<ILog, MyConsoleLogger>();
services.AddScoped(typeof(ILog), typeof(MyConsoleLogger));
}

Constructor Injection
Once we register a service, the IoC container automatically performs
constructor injection if a service type is included as a parameter in a
constructor.

For example, we can use ILog service type in any MVC controller.


Consider the following example.

Example: Using Service

 Copy

public class HomeController : Controller


{
ILog _log;

public HomeController(ILog log)


{
_log = log;
}
public IActionResult Index()
{
_log.info("Executing /home/index");

return View();
}
}

In the above example, an IoC container will automatically pass an


instance of MyConsoleLogger to the constructor of HomeController. We
don't need to do anything else. An IoC container will create and
dispose an instance of ILog based on the registered lifetime.
Action Method Injection
Sometimes we may only need dependency service type in a single
action method. For this, use [FromServices] attribute with the
service type parameter in the method.

Example: Action Method Injection

 Copy

using Microsoft.AspNetCore.Mvc;

public class HomeController : Controller


{
public HomeController()
{
}

public IActionResult Index([FromServices] ILog log)


{
log.info("Index method executing");

return View();
}
}

Property Injection
Built-in IoC container does not support property injection. You will
have to use third party IoC container.

Get Services Manually


It is not required to include dependency services in the constructor.
We can access dependent services configured with built-in IoC
container manually using RequestServices property of HttpContext as
shown below.

Example: Get Service Instance Manually

 Copy
public class HomeController : Controller
{
public HomeController()
{
}
public IActionResult Index()
{
var services = this.HttpContext.RequestServices;
var log = (ILog)services.GetService(typeof(ILog));

log.info("Index method executing");

return View();
}
}

It is recommended to use constructor injection instead of getting it


using RequestServices.

ASP.NET Core: Built-in IoC Container


ASP.NET Core framework includes built-in IoC container for
automatic dependency injection. The built-in IoC container is a
simple yet effective container. Let's understand how the built-in IoC
container works internally.

The followings are important interfaces and classes for built-in IoC
container:

Interfaces:

1. IServiceProvider
2. IServiceCollection

Classes:

1. ServiceProvider
2. ServiceCollection
3. ServiceDescription
4. ServiceCollectionServiceExtensions
5. ServiceCollectionContainerBuilderExtensions
The following diagram illustrates the relationship between these
classes:

bui
lt-in IoC Container

IServiceCollection
As you know, we can register application services with built-in IoC
container in the Configure method of Startup class by using
IServiceCollection. IServiceCollection interface is an empty interface.
It just inherits IList<servicedescriptor>. See the source code here.

The ServiceCollection class implements IServiceCollection interface.


See the ServiceCollection source code here.

So, the services you add in the IServiceCollection type instance, it


actually creates an instance of ServiceDescriptor and adds it to the
list.

IServiceProvider
IServiceProvider includes GetService method.
The ServiceProvider class implements IServiceProvider interface
which returns registered services with the container. We cannot
instantiate ServiceProvider class because its constructors are
marked with internal access modifier.

ServiceCollectionServiceExtensions
The ServiceCollectionServiceExtensions class includes extension
methods related to service registrations which can be used to add
services with lifetime. AddSingleton, AddTransient, AddScoped
extension methods defined in this class.

ServiceCollectionContainerBuilderExtensions
ServiceCollectionContainerBuilderExtensions class
includes BuildServiceProvider extension method which creates and
returns an instance of ServiceProvider.

There are three ways to get an instance of IServiceProvider:

Using IApplicationBuilder
We can get the services in Configure method using
IApplicationBuilder's ApplicationServices property as shown below.

public void Configure(IServiceProvider pro, IApplicationBuilder app,


IHostingEnvironment env)
{
var services = app.ApplicationServices;
var logger = services.GetService<ILog>() }

//other code removed for clarity


}

Using HttpContext
var services = HttpContext.RequestServices;
var log = (ILog)services.GetService(typeof(ILog));

Using IServiceCollection
public void ConfigureServices(IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();

ASP.NET Core - Middleware


ASP.NET Core introduced a new concept called Middleware. A
middleware is nothing but a component (class) which is executed on
every request in ASP.NET Core application. In the classic ASP.NET,
HttpHandlers and HttpModules were part of request pipeline.
Middleware is similar to HttpHandlers and HttpModules where both
needs to be configured and executed in each request.

Typically, there will be multiple middleware in ASP.NET Core web


application. It can be either framework provided middleware, added
via NuGet or your own custom middleware. We can set the order of
middleware execution in the request pipeline. Each middleware adds
or modifies http request and optionally passes control to the next
middleware component. The following figure illustrates the execution
of middleware components.

AS
P.NET Core Middleware

Middlewares build the request pipeline. The following figure


illustrates the ASP.NET Core request processing.
ASP.NET Core Request Processing

Configure Middleware
We can configure middleware in the Configure method of the Startup
class using IApplicationBuilder instance. The following example
adds a single middleware using Run method which returns a string
"Hello World!" on each request.

public class Startup


{
public Startup()
{
}
public void Configure(IApplicationBuilder app, IHostingEnvironment
env, ILoggerFactory loggerFactory)
{
//configure middleware using IApplicationBuilder here..

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World!");

});

// other code removed for clarity..


}
}

In the above example, Run() is an extension method


on IApplicationBuilder instance which adds a terminal middleware
to the application's request pipeline. The above configured
middleware returns a response with a string "Hello World!" for each
request.
Understand Run Method
We used Run extension method to add middleware. The following is
the signature of the Run method:

Method Signature:

public static void Run(this IApplicationBuilder app, RequestDelegate handler)

The Run method is an extension method on IApplicationBuilder and


accepts a parameter of RequestDelegate. The RequestDelegate is a
delegate method which handles the request. The following is a
RequestDelegate signature.

Method Signature:

public delegate Task RequestDelegate(HttpContext context);

As you can see above, the Run method accepts a method as a


parameter whose signature should match with RequestDelegate.
Therefore, the method should accept the HttpContext parameter and
return Task. So, you can either specify a lambda expression or
specify a function in the Run method. The lambda expression
specified in the Run method above is similar to the one in the
example shown below.

public class Startup


{
public Startup()
{
}

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.Run(MyMiddleware);
}

private Task MyMiddleware(HttpContext context)


{
return context.Response.WriteAsync("Hello World! ");
}
}
The above MyMiddleware function is not asynchronous and so will
block the thread till the time it completes the execution. So, make it
asynchronous by using async and await to improve performance and
scalability.

// other code removed for clarity

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.Run(MyMiddleware);
}

private async Task MyMiddleware(HttpContext context)


{
await context.Response.WriteAsync("Hello World! ");
}

Thus, the above code snippet is same as the one below.

app.Run(async context => await context.Response.WriteAsync("Hello


World!") );

//or

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World!");
});

So, in this way, we can configure middleware using Run method.


ADVERTISEMENT

Configure Multiple Middleware


Mostly there will be multiple middleware components in ASP.NET
Core application which will be executed sequentially. The Run method
adds a terminal middleware so it cannot call next middleware as it
would be the last middleware in a sequence. The following will always
execute the first Run method and will never reach the second Run
method.
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World From 1st
Middleware");
});

// the following will never be executed


app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World From 2nd
Middleware");
});
}

To configure multiple middleware, use Use() extension method. It is


similar to Run() method except that it includes next parameter to
invoke next middleware in the sequence. Consider the following
example.

Example: Use()

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello World From 1st
Middleware!");

await next();
});

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World From 2nd
Middleware");
});
}
The above example will display Hello World From 1st Middleware!
Hello World From 2nd Middleware! in the browser.

Thus, we can use Use() method to configure multiple middlewares in


the order we like.

Add Built-in Middleware Via NuGet


ASP.NET Core is a modular framework. We can add server side
features we need in our application by installing different plug-ins via
NuGet. There are many middleware plug-ins available which can be
used in our application.

The followings are some built-in middleware:

Middleware Description

Authentication Adds authentication support.

CORS Configures Cross-Origin Resource Sharing.

Routing Adds routing capabilities for MVC or web form

Session Adds support for user session.

StaticFiles Adds support for serving static files and directory browsing.

Diagnostics Adds support for reporting and handling exceptions and errors.

Let's see how to use Diagnostics middleware.

Diagnostics Middleware
Let's install and use Diagnostics middleware. Diagnostics middleware
is used for reporting and handling exceptions and errors in ASP.NET
Core, and diagnosing Entity Framework Core migrations errors.

Open project.json and add Microsoft.AspNetCore.Diagnostics


dependency if it is not added. Wait for some time till Visual Studio
restores the packages.
This package includes following middleware and extension methods
for it.

Middleware Extension Method Description

DeveloperExceptionPageMiddleware UseDeveloperExceptionPage() Captures synchronous and asynchronous exceptions from


the pipeline and generates HTML error responses.

ExceptionHandlerMiddleware UseExceptionHandler() Catch exceptions, log them and re-execute in an


alternate pipeline.

StatusCodePagesMiddleware UseStatusCodePages() Check for responses with status codes between 400 and
599.

WelcomePageMiddleware UseWelcomePage() Display Welcome page for the root path.

We can call respective Use* extension methods to use the above


middleware in the configure method of Startup class.

Let's add welcomePage middleware which will display welcome page


for the root path.

Example: Add Diagnostics Middleware

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.UseWelcomePage();
//other code removed for clarity
}

The above example will display the following welcome page for each
request.
This way we can use different Use* extension methods to include
different middleware.

Add Custom Middleware in ASP.NET


Core Application
Here, you will learn how to create and add your own custom
middleware into the request pipeline of ASP.NET Core application.

The custom middleware component is like any other .NET class


with Invoke() method. However, in order to execute next middleware
in a sequence, it should have RequestDelegate type parameter in the
constructor.

Visual Studio includes template for creating standard middleware


class. For this, right click on the project or folder where you want to
create middleware class and select Add -> New Item. This will open
Add New Item popup. Search for word "middleware" in the top right
search box as shown below.
Add Custom Middleware

Select Middleware Class item and give it a name and click on Add
button. This will add a new class for the middleware with extension
method as shown below.

Example: Custom Middleware

 Copy

// You may need to install the Microsoft.AspNetCore.Http.Abstractions


package into your project
public class MyMiddleware
{
private readonly RequestDelegate _next;

public MyMiddleware(RequestDelegate next)


{
_next = next;
}

public Task Invoke(HttpContext httpContext)


{

return _next(httpContext);
}
}

// Extension method used to add the middleware to the HTTP request


pipeline.
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this
IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}

As you can see above, the Invoke() method is not asynchronous. So,
change it to asynchronous and write your custom logic before calling
next();

Example: Async Middleware

 Copy

public class MyMiddleware


{
private readonly RequestDelegate _next;
private readonly ILogger _logger;

public MyMiddleware(RequestDelegate next, ILoggerFactory


logFactory)
{
_next = next;

_logger = logFactory.CreateLogger("MyMiddleware");
}
public async Task Invoke(HttpContext httpContext)
{
_logger.LogInformation("MyMiddleware executing..");

await _next(httpContext); // calling next middleware

}
}

// Extension method used to add the middleware to the HTTP request


pipeline.
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this
IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}

Add Custom Middleware


Now, we need to add our custom middleware in the request pipeline
by using Use extension method as shown below.

Example: Add Middleware into Request Pipeline

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.UseMyMiddleware();

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World!");
});
}

We can add middleware


using app.UseMiddleware<MyMiddleware>() method of
IApplicationBuilder also.
Configure the Default File to be Served
on the Root Request
As we learned in the Set Default File
section, app.UseDefaultFiles() middleware serves the following files
on the root request.

1. Default.html
2. Default.htm
3. Index.html
4. Index.htm

Suppose, you want to set home.html as a default page which should


be displayed on the root access. To do that,
specify DefaultFilesOptions in the UseDefaultFiles method as
shown below.

public class Startup


{
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("home.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World");
});
}
}

Now, this will display home.html from wwwroot folder on the root
request http://localhost:<port>.

ASP.NET Core - Environment Variable


Typically, in professional application development, there are multiple
phases where an application is tested before publishing it to the real
users. These phases by convention are development, staging, and
production. We as developers might like to control the behavior of an
application based on the phases the application is in. Environment
variable indicates the runtime environment in which an application is
currently running.

ASP.NET Core uses an environment variable


called ASPNETCORE_ENVIRONMENT to indicate the runtime environment.
The value of this variable can be anything as per your need but
typically it can be Development, Staging, or Production. The value is
case insensitive in Windows and Mac OS but it is case sensitive on
Linux.

In Visual Studio, we can set ASPNETCORE_ENVIRONMENT in the debug tab


of project properties. Open project properties by right clicking on the
project in the solution explorer and select Properties.
Open
Project Properties

This will open properties page. Click on Debug tab and you will see
Environment Variables as shown below.
Environment Variable

You may change the value as per your need. This value will be saved
in the launchSettings.json file as shown below.
launchsettings.json

You may also change the environment variable directly in


launchSettings.json.
ADVERTISEMENT

Access Environment Variable at Runtime


We can get the value of an environment variable in our code to
execute some additional code based on its value.
The IHostingEnvironment service includes EnvironmentName property
which contains the value of ASPNETCORE_ENVIRONMENT variable.
ASP.NET Core also includes extension methods to check the
environment such as IsDevelopment(), IsStating(), IsEnvironment()
and IsProduction().

The IHostingEnvironment service is provided by ASP.NET hosting


layer and can be used anywhere in your application via Dependency
Injection. The following example shows how we can check the
environment variable in the Configure method of Startup class.

Example: Access Environment Variable

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
if (env.IsEnvironment("Development"))
{
// code to be executed in development environment

if (env.IsDevelopment())
{
// code to be executed in development environment

if (env.IsStaging())
{
// code to be executed in staging environment

if (env.IsProduction())
{
// code to be executed in production environment

}
}

ASP.NET Core - Exception Handling


Exception handling is one of the most important features of any
application. Fortunately, ASP.NET Core includes a middleware that
makes exception handling easy. In this chapter, we will learn about
exception handling in ASP.NET Core application.

By default, ASP.NET Core returns a simple status code for any


exception that occurs in an application. Consider the following
example of Configure method which throws an error.

public class Startup


{
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{
app.Run(context => { throw new Exception("error"); });
}
}

The above code will display the following result.


Install Microsoft.AspNetCore.Diagnostics Package
To handle exceptions and display user friendly messages, we need to
install Microsoft.AspNetCore.Diagnostics NuGet package and add
middleware in the Configure() method. If you are using Visual Studio
templates to create ASP.NET Core application then this package
might be already installed. If not then you can
add Microsoft.AspNetCore.Diagnostics package via NuGet manager.

The Microsoft.AspNetCore.Diagnostics package includes following


extension methods to handle exceptions in different scenario:

1. UseDeveloperExceptionPage
2. UseExceptionHandler

UseDeveloperExceptionPage
The UseDeveloperExceptionPage extension method adds middleware
into the request pipeline which displays developer friendly exception
detail page. This helps developers in tracing errors that occur during
development phase.

As this middleware displays sensitive information, it is advisable to


add it only in development environment.

public class Startup


{
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{
if (env.IsDevelopment() || env.IsStaging())
{
app.UseDeveloperExceptionPage();
}

app.Run(context => { throw new Exception("error"); });


}
}

The above code will display the following result.


Exc
eption Handling

As you can see above, the developer exception page includes 4 tabs:
Stack, Query, Cookies, and Headers. Stack tab displays information
of stack trace, which indicates where exactly an error occurred.
Query tab displays information about query string. Cookies tab
displays information about cookies set by the request and Headers
tab displays information about headers.
ADVERTISEMENT

UseExceptionHandler
In MVC Core application, we might want some other controller to
handle all exceptions and display custom user friendly error
messages. The UseExceptionHandler extension method allows us to
configure custom error handling route. This is useful when an
application runs under production environment.

Example: Exception Handler in MVC

 Copy
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{

if (env.IsDevelopment() || env.IsStaging())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

//code removed for clarity


}

In the above example, the UseExceptionHandler("/Home/Error") sets


the error handler path. If an error occurred in the MVC application
then it will redirect the request to /home/error, which will execute the
Error action method of HomeController.

Create a simple Error action method in HomeController class as


shown below.

HomeController:

 Copy

public class HomeController : Controller


{
public HomeController()
{
}

public IActionResult Error()


{
return View();
}

// other code removed for the clarity

The following is the content of Error.cshtml.


Error.cshtml

 Copy

@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your
request.</h2>

<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display
more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed
applications</strong>, as it can result in sensitive information from
exceptions being displayed to end users. For local debugging,
development environment can be enabled by setting the
<strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to
<strong>Development</strong>, and restarting the application.
</p>

Now, when an error occurs, it displays the page shown below.


Exc
eption Handling

Thus, we can configure middleware to handle exceptions in ASP.NET


Core application.

 Note:

Visual Studio automatically creates Error.cshtml under Home folder when you
create ASP.NET Core project with MVC template.

ASP.NET Core - Serving Static Files


Here, we will learn how to serve static files such as html, JavaScript,
CSS, or image files on HTTP request without any server-side
processing.

ASP.NET Core application cannot serve static files by default. We


must include Microsoft.AspNetCore.StaticFiles middleware in the
request pipeline.
Install StaticFiles Middleware
The Microsoft.AspNetCore.StaticFiles middleware package is
already included in the meta package Microsoft.AspNetCore.All, so
we don't need to install it separately in ASP.NET Core 2.x application.

To install StaticFiles middleware in ASP.NET Core 1.x application,


open NuGet package manager by right clicking on project in the
solution explorer and select Manage NuGet Packages... Search for
staticfiles in the search box in the browse tab. This will
display Microsoft.AspNetCore.StaticFiles middleware as shown
below.

Ins
tall StaticFiles Middleware

Click on the Install button on the right pane to install it. Once


installed, the Microsoft.AspNetCore.StaticFiles is automatically
included in the dependencies section of the project.json.
StaticFiles
Dependency in project.json

Using StaticFiles Middleware


By default, all the static files of a web application should be located
in the web root folder wwwroot. To understand this, let's create a
simple default.html in the wwwroot folder with the following content.
Default.html

Now, to serve the above Default.html static file, we must add


StaticFiles middleware in the Configure() method of Startup file as
shown below.

public class Startup


{
public Startup()
{
}

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.UseStaticFiles();

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World");
});
}
}

As you can see above, the app.UseStaticFiles() method adds


StaticFiles middleware into the request pipeline.
The UseStaticFiles is an extension method included in the
StaticFiles middleware so that we can easily configure it.

Now, open the browser and send http


request http://localhost:<port>/default.html which will display
default.html as a response as shown below.

Ser
ving HTML File

This way we can serve any other file stored in wwwroot folder or sub-
folder. For example, consider the following test.js file in the wwwroot
folder.
test.js

Now, we can access this file by sending


http://localhost:<port>/test.js request.
Ser
ving JS File

Suppose, you want to serve files from the outside of web root folder
(wwwroot). For example, you include images in the following Images
folder as shown below.
Serving Static Files

Now, specify StaticFileOptions parameter in
the UseStaticFiles method to serve images from the Images folder
as shown below.

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.UseStaticFiles(); // For the wwwroot folder

app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory
(), @"Images")),
RequestPath = new PathString("/app-
images")
});
}
As you can see, we used FileProvider option to specify Images
folder from which static files will be served. The RequestPath option
specifies the relative path in the URL which maps to the static folder.

Now, a request to http://localhost/app-images/MyImage.png will


serve the MyImage.png file.
ADVERTISEMENT

Set Default File


As we have seen above, default.html or test.js was served on the
specific request for it. However, what if we want to serve default
html file on the root request?

Currently, when you send http://localhost:<port> request, it will be


handled by run method and display the following result.

To serve default.html on the root request http://localhost:<port>,


call UseDefaultFiles() method before UseStaticFiles() in
the Configure method as shown below.
public void Configure(IApplicationBuilder app, IHostingEnvironment
env)
{
app.UseDefaultFiles();
app.UseStaticFiles();

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World");
});
}

The UseDefaultFiles configures the DefaultFiles middleware which is


a part of StaticFiles middleware. This will automatically serve html
file named default.html, default.htm, index.html or index.htm on the
http request http://localhost:<port>. The above example will display
default.html file on http://localhost:<port> as shown below.

Ser
ving Static Files

 Note:

Order of middleware is very important. app.UseDefaultFiles() should be added


before app.UseStaticFiles() in the request pipeline.
FileServer
The FileServer middleware combines the functionalities of
UseDefaultFiles and UseStaticFiles middlware. So, instead of using
both the middlware, just use UseFileServer in the Configure method.

UseFileServer = UseDefaultFiles + UseStaticFiles

Example: UseFileServer

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env)
{
app.UseFileServer();

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World");
});
}

Thus, we can serve static files on http requests.

Serve static files from different folder


than wwwroot folder in ASP.NET Core
You can configure middleware to serve static files from other folders
along with default web root folder wwwroot.

For example, we will server admin.html from the following admin


folder and also test.html from wwwroot folder.
Now, configure the StaticFiles middleware in the Configure() method
of Startup class as shown below.

Example: Configure StaticFiles Middleware

 Copy

public class Startup


{
// This method gets called by the runtime. Use this method to
configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment
env, ILoggerFactory loggerFactory)
{
app.UseStaticFiles();

app.UseStaticFiles(new StaticFileOptions() {
FileProvider = new
PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"Content")),
RequestPath = new PathString("/Admin")
});

app.Run(async (context) =>


{
await context.Response.WriteAsync("Hello World!");
});
}
}

As you can see, app.UseStaticFiles() enables default web root


folder wwwroot to serve the static files.

app.UseStaticFiles(new StaticFileOptions() {
FileProvider = new
PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"admin")),
RequestPath = new PathString("/admin")
});

The above code configures Content admin folder to serve static files
on the request path /admin. So now, we will be able to execute HTTP
request http://localhost:1234/admin/admin.html to display static
admin.html page.

Fundamentals of Logging in .NET Core


.NET Core SDK is a light weight SDK which includes a bare minimum
set of features required to build an application. We can install NuGet
packages for other features we require for our application. For this,
Microsoft provides .NET APIs as .NET Extensions.

.NET Extensions is an open-source, cross-platform set of APIs for


commonly used programming patterns and utilities, such as
dependency injection, logging, and app configuration. Most APIs in
this project are meant to work on many .NET platforms, such as .NET
Core, .NET Framework, Xamarin, and other. While commonly used in
ASP.NET Core applications, these APIs are not coupled to the
ASP.NET Core application model. They can be used in console apps,
WinForms and WPF, etc. You can find the documentation and the
source code of extensions at https://github.com/aspnet/Extensions .

All the extensions are included under


the Microsoft.Extensions namespace. You can find all built-in and
third party extensions at nuget.org/packages .

The Logging API is included in


the Microsoft.Extensions.Logging package. The Logging API does
not work as standalone. It works with one or more logging providers
that store or display logs to a particular medium such as Console,
Debug, TraceListeners etc.

So, there are two important building blocks for implementing logging
in a .NET Core based application:

1. Logging API
2. Logging Providers

The following figure illustrates logging in .NET Core:

.NET Frameworks

As you can see in the above figure, the logging API


in Microsoft.Extensions.Logging works on the .NET Core based
applications whether it is ASP.NET Core or EF Core. You just need to
use the logging API with one or more logging providers to implement
logging in any .NET Core based application.

Logging API
As mentioned before, Microsoft provides logging API as an extension
in the wrapper Microsoft.Extensions.Logging  which comes as a NuGet
package.

Microsoft.Extensions.Logging includes the necessary classes and


interfaces for logging. The most important are the ILogger,
ILoggerFactory, ILoggerProvider interfaces and the LoggerFactory
class.

The following figure shows the relationship between logging classes.

Logging API

Let's have an overview of each of the above class.

ILoggerFactory
The ILoggerFactory is the factory interface for creating an
appropriate ILogger type instance and also for adding
the ILoggerProvider instance.

public interface ILoggerFactory : IDisposable


{
ILogger CreateLogger(string categoryName);
void AddProvider(ILoggerProvider provider);
}

The Logging API includes the built-in LoggerFactory class that


implements the ILoggerFactory interface. We can use it to add an
instance of type ILoggerProvider and to retrieve the ILogger instance
for the specified category. Visit ILoggerFactory  and LoggerFactory  for
more information.

ILoggerProvider
The ILoggerProvider manages and creates an appropriate logger,
specified by the logging category.

public interface ILoggerProvider : IDisposable


{
ILogger CreateLogger(string categoryName);
}

We can create our own logging provider by implementing


the ILoggerProvider interface. Visit ILoggerProvider  for more
information.

ILogger
The ILogger interface includes methods for logging to the underlying
storage. There are many extension methods which make logging
easy. Visit ILogger for more information.

public interface ILogger


{
void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception exception, Func<TState, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope<TState>(TState state);
}

Logging Providers
A logging provider displays or stores logs to a particular medium
such as a console, a debugging event, an event log, a trace listener,
and others. Microsoft provides various logging providers as NuGet
packages.

The following table lists important logging providers.

Logging Provider's NuGet Package Output Target

Microsoft.Extensions.Logging.Console Console

Microsoft.Extensions.Logging.AzureAppServices Azure App Services 'Diagnostics logs' and 'Log stream' features

Microsoft.Extensions.Logging.Debug Debugger Monitor

Microsoft.Extensions.Logging.EventLog Windows Event Log

Microsoft.Extensions.Logging.EventSource EventSource/EventListener

Microsoft.Extensions.Logging.TraceSource Trace Listener


Logging Provider's NuGet Package Output Target

Microsoft has also collaborated with various logging framework teams


(including third parties like NLog, Serilog, Loggr, Log4Net, and
others) to extend the list of providers compatible
with Microsoft.Extensions.Logging. The following are some thrid-
party logging providers:

Logging Provider Description

elmah.io Provider for the Elmah.Io service

Loggr Provider for the Logger service

NLog Provider for the NLog library

Serilog Provider for the Serilog library

Let's take an example using


the Microsoft.Extensions.Logging.Console package which displays
logs on the Console.
ADVERTISEMENT

Console Logging Provider


Let's see how to display logs on the console using the NuGet package
for a console provider.

The Microsoft.Extensions.Logging.Console package includes logging


classes which send log output to the console.

The following figure illustrates how the logging API works with the
console logging provider.
Log
ging API with Console Logging Provider

As you can see in the above figure,


the ConsoleLogger implements ILogger, while
the ConsoleLoggingProvider implements ILoggingProvider.
The ConsoleLoggerExtensions class includes extension
method AddConsole(), which adds a console logger to
the LoggerFactory.

Now, let's see how to display logs on the Console in the .NET Core
console application.

First of all, create a new console application using the Console App
(.NET Core) template in Visual Studio 2017 (or later).

Now, you need to install a NuGet package


of Microsoft.Extensions.Logging. You can install it either using the
NuGet Package Manager or executing the following command in the
Package Manager Console.

PM> Install-Package Microsoft.Extensions.Logging

Now, you need to install a logging provider of your choice. Here, we


will send logs on the Console, so, install
the Microsoft.Extensions.Logging.Console package either using NPM
or execute the following command in the Package Manager Console
in Visual Studio.

PM> Install-Package Microsoft.Extensions.Logging.Console

After successfully installing the above two packages, you can now
implement logging in your .NET Core console application, as shown
below.

Example: Logging in .NET Core Console App

 Copy

namespace DotnetCoreConsoleApp
{
class Program
{
static void Main(string[] args)
{
ILoggerFactory loggerFactory = new LoggerFactory(
new[] { new ConsoleLoggerProvider((_, __)
=> true, true) }
);
//or
//ILoggerFactory loggerFactory = new
LoggerFactory().AddConsole();

ILogger logger = loggerFactory.CreateLogger<Program>();


logger.LogInformation("This is log message.");
}
}
}
Output:

info: DotnetCoreConsoleApp.Program[0]

      This is log message.


In the above example, we created an object of
the LoggerFactory class and assigned it to the ILoggerFactory type
variable, as shown below.

ILoggerFactory loggerFactory = new LoggerFactory(


new[] { new ConsoleLoggerProvider ((_, __) => true, true) }
);

The LoggerFactory can contain one or more logging providers, which


can be used to log to multiple mediums concurrently. The constructor
of the LoggerFactory accepts an array of different logger provider
objects as new[] { }. We want to display logs on the console, so we
need to create an object of the console logger
provider ConsoleLoggerProvider.

There are four constructors of the ConsoleLoggerProvider. Use the


one that allows lambda expression (Func<>) for log filtration and
includeScope Boolean. Here, we don't want to filter any information
so the lambda expression would always return true (_, __) => true,
as shown below.

new ConsoleLoggerProvider((_, __) => true, true)

Then, we can use this object of the LoggerFactory to create a logger


using which we can actually log information, errors, warnings, traces,
debugs etc. loggerFactory.CreateLogger<Program>() creates a logger
specific to the Program class so that the logger will display a message
with context info, e.g. DotnetCoreConsoleApp.Program[0].

Most logging providers include an extension method


of ILoggerFactory, which is a shortcut to add a provider to the logger
factory. For example, to add a console logger provider to
the LoggerFactory, just call
the LoggerFactory.AddConsole() extension method with the same
parameters as ConsoleLoggerProvider, as shown below.

public ILoggerFactory loggerFactory = new


LoggerFactory().AddConsole();

This is more readable and maintainable than creating a logger


provider manually. The above logger factory will display the same
output as above.
Log Levels
Log levels indicate the importance or severity of log messages. Built-
in log providers include extension methods to indicate log levels.

The following table lists log levels in .NET Core.

Log Level Severity Extension Method Description

Trace 0 LogTrace() Logs messages only for tracing purposes for the developers.

Debug 1 LogDebug() Logs messages for short-term debugging purposes.

Information 2 LogInformation() Logs messages for the flow of the application.

Warning 3 LogWarning() Logs messages for abnormal or unexpected events in the application flow.

Error 4 LogError() Logs error messages.

Critical 5 LogCritical() Logs failures messages that require immediate attention.

We can use extension methods to indicate the level of the log


messages as shown below.

namespace DotnetCoreConsoleApp
{
class Program
{
static void Main(string[] args)
{
ILoggerFactory loggerFactory = new
LoggerFactory().AddConsole((_, __) => true);
ILogger logger = loggerFactory.CreateLogger<Program>();

logger.LogInformation("Logging information.");
logger.LogCritical("Logging critical information.");
logger.LogDebug("Logging debug information.");
logger.LogError("Logging error information.");
logger.LogTrace("Logging trace");
logger.LogWarning("Logging warning.");
}
}
}
The above example will display the following output:

Logging in ASP.NET Core


ASP.NET Core uses the same logging mechanism as .NET Core
logging. So, it is highly recommended to go through the previous
chapter Logging in .NET Core  before reading this.

Here, we will implement logging in the ASP.NET Core 2.x MVC


application.

As explained in the previous chapter, the logging API


in Microsoft.Extensions.Logging namespace works with one or more
built-in or third party logging providers. So, in an ASP.NET Core MVC
application, we will also have to install the NuGet
package Microsoft.Extensions.Logging and one or more logging
providers of our choice.

Create an ASP.NET Core MVC application in Visual Studio 2017 (or


later). When you create the ASP.NET Core MVC web application in
Visual Studio 2017 (or later), it automatically includes the NuGet
package for Microsoft.Extensions.Logging and the following logging
providers under the Microsoft.AspNetCore.App NuGet package. So,
we don't have to install it manually.

1. Microsoft.Extensions.Logging.Console
2. Microsoft.Extensions.Logging.Debug
3. Microsoft.Extensions.Logging.EventSource
4. Microsoft.Extensions.Logging.TraceSource
Add Logging Providers
As mentioned in the previous chapter, we need to add providers
in LoggerFactory. In the ASP.NET Core MVC application, the call to
the WebHost.CreateDefaultBuilder(args) method in the Program.cs
internally adds the Console, Debug, and EventSource logging
providers.

Example: Program.cs

 Copy

public class Program


{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args)


=>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

Look at the source code of


the WebHost.CreateDefaultBuilder() method on GitHub and you will
find the following code:

.ConfigureLogging((hostingContext, logging) =>


{
logging.AddConfiguration(hostingContext.Configuration.GetSecti
on("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
}).

Thus, if you want to use these providers, no need to add them


manually. If you want to use other providers or any default provider,
then you need to remove all the existing providers and add the
provider of your choice. To configure logging providers, call
the ConfigureLogging() extension method of IWebHostBuilder, as
shown below.

Example: Program.cs

 Copy

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>


WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(logBuilder =>
{
logBuilder.ClearProviders(); // removes all providers from
LoggerFactory
logBuilder.AddConsole();
logBuilder.AddTraceSource("Information, ActivityTracing"); //
Add Trace listener provider
})
.UseStartup<Startup>();

In the above example, the ConfigureLogging() method takes action


to delegate Action<ILogBuilder> to configure logging providers. To
add logging providers of your choice, remove all the default providers
using ClearProviers() and then call the extension method of a
provider to add it, such as AddTraceSource() which will add the trace
listener provider, and the AddConsole() method which will add the
Console logging provider.

You can also configure the logging provider using ILoggerFactory in


the Configure() method of the Startup class. Let's see an example
on how to store logs in a text file.

Store Logs in a Text File


To store logs in a file, install the NuGet
package Serilog.Extensions.Logging.File . Serillog includes an
extension method for ILoggerFactory but not for ILogBuilder (in v
1.1.0). So, go to the Startup.cs file and add
the ILoggerFactory parameter in the Configure() method. Then, call
the AddFile() extension method to add Serillog file provider, as
shown below. ASP.NET Core dependency injection will automatically
pass an instance of the LoggerFactory for this parameter.
Example: Startup.cs

 Copy

public void Configure(IApplicationBuilder app, IHostingEnvironment


env, ILoggerFactory loggerFactory)
{
// other code remove for clarity
loggerFactory.AddFile("Logs/mylog-{Date}.txt");
}

This will store all the logs in the mylog-<date>.txt file, under the
Logs folder in your application.
ADVERTISEMENT

Create Logs in the Controller


We can use ILogger or ILoggerFactory anywhere in an application
using ASP.NET Core DI (Dependency Injection). Consider the
following example of HomeController:

Example: Logging in MVC Controller

 Copy

namespace AspDotNetCoreMvcApp.Controllers
{
public class HomeController : Controller
{
private readonly ILogger _logger;

public HomeController(ILogger<HomeController> logger){


_logger = logger;
}

public IActionResult Index()


{
_logger.LogInformation("Log message in the Index()
method");

return View();
}

public IActionResult About()


{
_logger.LogInformation("Log message in the About()
method");

return View();
}
}
}

In the above example, the ILogger<HomeController> parameter is


included in the constructor. ASP.NET Core DI will pass
the ILogger instance, which can be used to log in
the Index() and About() action methods.

Passing HomeController as generic type for


the ILogger<HomeController>, will be used as a category. For
example, specifying ILogger<HomeController< will display a fully
qualified name AspDotNetCoreMvcApp.Controllers.HomeController in
the logs, as shown below.

info: AspDoteNetCoreMvcApp.Controllers.HomeController[0]

       Log message in the Index() method

Let's understand the above log message. Here, we logged


information using the LogInformation() method, so it starts with
"info:" followed by the fully qualified name of the class where a log is
created: AspDoteNetCoreMvcApp.Controllers.HomeController[0]. [0]
is the event id. You can specify this event id to identify a record, e.g.
Id, page number or other important information which uniquely
identifies a log. We didn't specify any event id, so it will be 0. The
next line is an actual log message: "Log message in the Index()
method".

The same can be achieved by passing ILoggerFactory in the


constructor.

public class HomeController : Controller


{
private readonly ILogger _logger;
public HomeController(ILoggerFactory logFactory)
{
_logger = logFactory.CreateLogger<HomeController>();
}

public IActionResult Index()


{
_logger.LogInformation("Log message in the Index() method");

return View();
}

public IActionResult About()


{
_logger.LogInformation("Log message in the About() method");

return View();
}
}

Now, run the above application from command prompt by navigating


to /<app root folder>/bin/debug/netcoreapp2.1/, run the dotnet
<app name>.dll command and then open http://localhost:5000 in the
browser. It will display the same logs on the Console as above.

Logs:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Index", controller = "Home"}. Executing acti
on AspDoteNetCoreMvcApp.Controllers.HomeController.Index (AspDotNetCoreMvcApp)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method AspDoteNetCoreMvcApp.Controllers.HomeController.In
dex (AspDotNetCoreMvcApp) - Validation state: Valid
info: AspDoteNetCoreMvcApp.Controllers.HomeController[0]
Log message in the Index() method
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method AspDoteNetCoreMvcApp.Controllers.HomeController.Ind
ex (AspDotNetCoreMvcApp), returned result Microsoft.AspNetCore.Mvc.ViewResult in
0.8505ms.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
Executing ViewResult, running view Index.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]
Executed ViewResult - view Index executed in 231.2839ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action AspDoteNetCoreMvcApp.Controllers.HomeController.Index (Asp
DotNetCoreMvcApp) in 288.6931ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 946.274ms 200 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/images/banner1.svg
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/images/banner2.svg
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 5.6471ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 6.5811ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/css/site.min.css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2811ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/js/site.min.js
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/images/banner3.svg
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.178ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2342ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/css/site.min.css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.1173ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/js/site.min.js
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2539ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/favicon.ico
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.3253ms 404

Thus, we can implement logging in ASP.NET Core MVC application.

.NET Core Application Types


We can create two types of applications in .NET Core.

1. Portable Application
2. Self-contained application

Portable Application
Portable applications are applications which expect .NET Core
runtime on the deployment machines. It cannot be run on a machine
which does not have .NET Core runtime installed.

.NET Core
Portable Application
Self-contained Application
Self-contained applications are applications which include .NET Core
runtime when we publish it. It can run on a machine which does not
have .NET Core runtime installed.

.NET Core Self-contained Application

Configure Application Type


We can configure ASP.NET Core application as portable or self-
contained application using type property
of Microsoft.NETCore.App dependency in project.json. The
"type":"platform" indicates that this application expects .NET Core on
the machine. This makes it a portable application.

For the self-contained application, remove type-platform from the


dependency. This makes it a self-contained application which
means .NET Core will be included when you build and publish an
application.

Code Sharing in .NET Core


With .NET Core, we can currently develop applications with three
different .NET frameworks for different platforms. The traditional or
standard .NET Framework is for Windows, Mono framework for iOS,
OSx and Android and .NET Core for Windows, Mac and Linux.

.NET Frameworks

These frameworks use different framework class libraries. It means


code written in one framework cannot be used with other
frameworks. For example, a console application developed with .NET
Framework cannot run on .NET Core or vice-versa. Thus, code-
sharing is not allowed.

It would be nice to write code once and share with other applications
with different .NET frameworks. Isn't it?
Co
de Sharing

To solve this problem of code sharing, we can use the following three
approaches:

1. Create Portable Class Library


2. Target Multiple Frameworks ASP.NET Core app
3. Target .NET Standard

Creating portable class library to share code with other .NET


frameworks is not a new thing in .NET. Learn about it here.

Target Multiple Frameworks in .NET Core


2.x App
As mentioned in the previous chapter, creating a .NET Core
application which targets multiple frameworks is one of the
approaches for code sharing.

We can create .NET Core application and configure multiple target


frameworks for it so that it can run with all the configured target
frameworks. To demonstrate this, let's create .NET Core 2.0 console
application which can run with .NET Core as well as traditional .NET
framework in Visual Studio 2017.

The first step is to create a new project in Visual Studio 2017 by


clicking on File -> New Project.. This will open New Project popup as
shown below.
Create .NET Core 2.x Console Application

In the New Project popup, select Console Application (.NET Core),


provide the appropriate name and click OK. This will create new
console project as shown below.
Console Application

Now, we can configure multiple frameworks by editing .csproj file.


So, right click on the project in solution explorer and select Edit
<project-name>.csproj as shown below.
Edi
t .csproj

The .csproj will look like below.

.csproj:

 Copy

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

</Project>
As you can see above, <TargetFramework> is netcoreapp2.0. It means
currently this application can run on .NET Core 2.0 framework. We
can include multiple monikers for multiple frameworks here, in order
to target multiple frameworks.

To target multiple frameworks, change <TargetFramework> to


plural <TargetFrameworks> and include monikers for different
frameworks you want to target separated by ;.

Here, we will support two more frameworks .NET Framework 4.0 &
4.6. So include net40 and net46 monikers respectively as shown
below. Look at TFMs for all supported target frameworks here.

.csproj:

 Copy

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net45;net46</TargetFrameworks>
</PropertyGroup>

</Project>
ADVERTISEMENT

As soon as you save the above .csproj file, Visual Studio will load and
include the references for .NET 4.5 and .NET 4.6
into Dependencies section as shown below.
Multi Frameworks Dependencies

Now, open program.cs and let's add framework specific code using
preprocessor conditions #if and #elif as shown below.

Program.cs

 Copy

using System;

namespace MultiFrameworkConsole
{
public class Program
{
public static void Main(string[] args)
{

#if NET40
Console.WriteLine("Target framework: .NET Framework 4.0");
#elif NET45
Console.WriteLine("Target framework: .NET Framework 4.5");
#else
Console.WriteLine("Target framework: .NET Core 2.0");
#endif
Console.ReadKey();
}
}
}

As you can see above, to write framework specific code, use symbol
with condition for .NET framework moniker and replace the dot with
an underscore and change lowercase letters to uppercase.

To run the application for specific framework, click on the run


dropdown and select a targeted framework as shown below.

Multi
Frameworks Dependencies

Now, run the application and you will see the following output.
Framework Specific References
Sometimes you may need to include specific references for a
particular framework. For example, .NET Core 2.0 meta package
already includes System.Net reference which is not included in .NET
4.0 and 4.5. So, we need to include it in .csproj file using conditional
reference as shown below.

.csproj:

 Copy

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net45;net46</TargetFrameworks>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">


<Reference Include="System.Net" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System.Net" />
</ItemGroup>
</Project>

Now, System.Net reference will be added to .NET 4.0 & 4.5 and


System.Net specific code will be executed for all frameworks.

You might also like