HI WELCOME TO KANSIRIS
Showing posts with label asp.net core. Show all posts
Showing posts with label asp.net core. Show all posts

ASP.NET Core - Environment Variable

Leave a Comment
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.

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
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 

    }
} 
Learn all about exception handling in ASP.NET Core application and how this environment variable can be used there, in the next chapter.

ASP.NET Core - Logging

Leave a Comment
ASP.NET Core framework provides built-in supports for logging. However, we can also use third party logging provider easily in ASP.NET Core application.
Before we see how to implement logging in ASP.NET Core application, let's understand the important logging interfaces and classes available in ASP.NET Core framework. The following are built-in interfaces and classes available for logging under Microsoft.Extensions.Logging namespace .
  1. ILoggingFactory
  2. ILoggingProvider
  3. ILogger
  4. LoggingFactory
The following figure shows the relationship between logging classes.
Logging Infrastructure
Let's have an overview on each of them.

ILoggerFactory

The ILoggerFactory is the factory interface for creating an appropriate ILogger type instance and also to add ILoggerProvider instance.
ILoggerFactory:
public interface ILoggerFactory : IDisposable
{
    ILogger CreateLogger(string categoryName);
    void AddProvider(ILoggerProvider provider);
}
ASP.NET Core framework includes built-in LoggerFactory class that implements ILoggerFactoryinterface. We can use it to add an instance of type ILoggerProvider and to retrieve ILoggerinstance for the specified category.
ASP.NET Core runtime creates an instance of LoggerFactory class and registers it for ILoggerFactory with the built-in IoC container when the application starts. Thus, we can use ILoggerFactory interface anywhere in your application. The IoC container will pass an instance of LoggerFactory to your application wherever it encounters ILoggerFactory type.

ILoggerProvider

The ILoggerProvider manages and creates appropriate logger specified by logging category.
ILoggerProvider:
public interface ILoggerProvider : IDisposable
{
   ILogger CreateLogger(string categoryName);
}
We can create our own logging provider by implementing ILoggerProvider interface.

ILogger

ILogger interface includes methods for logging to the underlying storage.
ILogger:
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);
} 

Built-in Logging Providers

There are different logging providers available as NuGet packages which we can use to send log output to the different medium such as console, debug window, EventSource etc. ASP.NET Core ships with the following providers:
  1. Console
  2. Debug
  3. EventSource
  4. EventLog
  5. TraceSource
  6. Azure App Service
Let's have an overview of Console logger.

Console Logger

The Microsoft.Extensions.Logging.Console package includes logging classes which sends log output to the console. The following are important classes for console logging.
  1. ConsoleLoggingProvider
  2. ConsoleLogger
  3. ConsoleLoggerExtension
  4. ConsoleLoggerSettings
  5. ConsoleLoggerScope
The following figure illustrates the console logger classes.
Logging Infrastructure
As you can see in the above figure, the ConsoleLogger implements ILogger and ConsoleLoggingProvider implements ILoggingProvider. The ConsoleLoggerExtensions class includes extension method AddConsole() which adds console logger to LoggerFactory.
Now, let's use console logger to display log output to the console in both ASP.NET Core 1.x and 2.x application.

Step 1 - Install NuGet Package

ASP.NET Core 1.x:
Include Microsoft.Extensions.Logging.Console dependencies in project.json if it is not added already.
"dependencies": {
        "Microsoft.NETCore.App": {
            "version": "1.0.1",
            "type": "platform"
        },
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
        "Microsoft.Extensions.Logging.Console": "1.0.0"
    } 
Visual Studio will restore the packages automatically as soon as project.json is saved.
ASP.NET Core 2.x:
By default, Microsoft.Extensions.Logging.Console is included in the meta package Microsoft.AspNetCore.All, so we don't need to install it separately in ASP.NET Core 2.x application.

Step 2 - Use Provider

ASP.NET Core 1.x:
Now, in order to use console logger, we first need to configure it. First, we need to add ConsoleLoggerProvider to the providers list using LoggerFactory. As you can see in the LoggerFactory class above, it provides AddProvider() method which adds our custom ILoggerProvider type instance to the list. The Microsoft.Extensions.Logging.Console package includes all necessary classes. So, we can add ConsoleLoggerProvider instance as shown below.
Example: Add ConsoleLoggerProvider
public class Startup
{
    public Startup()
    {
    } 
 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddProvider(new ConsoleLoggerProvider((category, logLevel) => logLevel >= LogLevel.Information, false));
        
        //code removed for clarity 
    }
}
As you can see above, we add an instance of ConsoleLoggerProvider to the factory. Now, we can start logging. The console will display all the logs whose LogLevel is Information or above.
We can also use AddConsole() extension method instead of configuring console logger manually as shown below.
Example: Add Console Logger
public class Startup
{
    public Startup()
    {
    } 
 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole();

        //code removed for clarity 
    }
}
ASP.NET Core 2.x:
The CreateDefaultBuilder() already includes console and debug logging providers. So there is no need to add it again in the Configure() method in ASP.NET Core 2.x application.

Step 3 - Create Logs

This step is applicable for both ASP.NET Core 1.x and 2.x application.
Now, we can create logs and see it on the console by getting an instance of ILogger using LoggerFactory and start logging as shown below.
Example: Add Console Logger
public class Startup
{
    public Startup()
    {
    } 
 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {

        loggerFactory.AddConsole();

        //start logging to the console
        var logger = loggerFactory.CreateLogger<ConsoleLogger>();
        logger.LogInformation("Executing Configure()");

        //code removed for clarity 
    }
}
We can also use ILogger anywhere in our application. IoC container will inject ConsoleLoggerinstance wherever it sees ILogger. For example, we can use ILogger in the MVC-controller as shown below.
Example: Logging in MVC Controller
public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }
    public IActionResult Index()
    {
        _logger.LogInformation("Executing Home/Index");

        return View();
    } 
}
You will see the above log on the console when you browse http://localhost:5000/home/index.
We can use any of the above mentioned built-in logging providers by following the same process.

Log Levels

Log levels indicate the importance or severity of the log messages. Built-in log providers include extension methods to indicate log levels.
ASP.NET Core defines following log levels.
Log LevelSeverityExtension MethodDescription
Trace0LogTrace()Log messages only for tracing purpose for the developers
Debug1LogDebug()Log messages for short-term debugging purpose
Information2LogInformation()Log messages for the flow of the application.
Warning3LogWarning()Log messages for abnormal or unexpected events in the application flow.
Error4LogError()Log error messages.
Critical5LogCritical()Log messages for the failures that require immediate attention
We can use extension method to indicate level of the log messages as shown below.
Example: Log Level
public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index(string id)
    {
        _logger.LogInformation("Home/Index Executing..");

        if (String. IsNullOrEmpty(id))
        {
            _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "Index({ID}) NOT FOUND", id);

            return NotFound();
        }

        return View();
    } 
}

Third-party Logging Providers

The following are some logging providers that work with ASP.NET Core:
Logging ProviderDescription
elmah.ioProvider for the Elmah.Io service
LoggrProvider for the Logger service
NLogProvider for the NLog library
SerilogProvider for the Serilog library
Learn about ASP.NET Core environment variables in the next chapter.

ASP.NET Core - Middleware

Leave a Comment
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.
ASP.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.

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()
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:
MiddlewareDescription
AuthenticationAdds authentication support.
CORSConfigures Cross-Origin Resource Sharing.
RoutingAdds routing capabilities for MVC or web form
SessionAdds support for user session.
StaticFilesAdds support for serving static files and directory browsing.
DiagnosticsAdds 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.
MiddlewareExtension MethodDescription
DeveloperExceptionPageMiddlewareUseDeveloperExceptionPage()Captures synchronous and asynchronous exceptions from the pipeline and generates HTML error responses.
ExceptionHandlerMiddlewareUseExceptionHandler()Catch exceptions, log them and re-execute in an alternate pipeline.
StatusCodePagesMiddlewareUseStatusCodePages()Check for responses with status codes between 400 and 599.
WelcomePageMiddlewareUseWelcomePage()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
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.
Next, learn how to implement logging functionality in the ASP.NET Core application.