ASP.NET Core 3.0 Flashcards
ConfigureServices method in startup.cs
we define our interface and the class that implements the interface here; we are adding that to IServiceCollection public void ConfigureServices(IServiceCollection services) {
services.AddTransient(); services.AddSingleton(); } if some ask you for Icontent, then provider them with ContentDAL class
To inject a service in cshtml
@model Employee
@inject IEmployeeRepository _empRepository
<div>
Total Employee Count= @_empRepository.GetAllEmployee().count() -switching to code
</div>
with singleton Service
There is only a single instance. An instance is created, when the service is first requested and that single instance is used by all http requests throughout the application -usually the first created when the first dependency injection happens in the controller or any class constructor
in startup.cs:
services.AddSingleton();
//NOTE: register service
services. AddTransient(); services. AddTransient(); services. AddTransient(); services. AddTransient(); services. AddTransient(); services. AddTransient(); services. AddTransient();
in Alert Controller constructor: public AlertController(ILogger logger, IMapper mapper, IAlert alertDal, IOptions customOptions) { _logger = logger; _mapper = mapper; _alertDal = alertDal; }
with Scoped service
we get the same instance within the scope of a given http request but a new instance across different http request
if we issue post and in the action method we have dependency injection and we have cshtml associated with it then we get the same instance for both of them but we issue another post request; again a new instance is created and calls the class constructors sets to default values and operates on that method
in startup.cs:
services.AddScoped();
with a transient service
with a transient service, a new instance is provided every time an instance is requested whether it is in the scope of the same HTTP request or across different http request
Even with in the same post action method. the method has separate service instance and the view has separate service instance
if it is different action methods then both of them have different services instances
ObjectResult Class
Namespace: Microsoft.AspNetCore.Mvc Assembly: Microsoft.AspNetCore.Mvc.Core.dll Inheritance Object-- ActionResult-- ObjectResult Property: Value Method: ExecuteResult(ActionContext) Executes the result operation of the action method synchronously. This method is called by MVC to process the result of an action method.
(Inherited from ActionResult)
–Usage
// execute
var result = await _alertController.ListActiveAlerts(userId.ToString()) as ObjectResult;
var resultList = result.Value as List;
using IOptions for reading configurations
How to use the IOptions pattern for configuration in ASP.NET Core RC2
Share on:
Almost every project will have some settings that need to be configured and changed depending on the environment, or secrets that you don’t want to hard code into your repository. The classic example is connection strings and passwords etc which in ASP.NET 4 were often stored in the section of web.config.
In ASP.NET Core this model of configuration has been significantly extended and enhanced. Application settings can be stored in multiple places - environment variables, appsettings.json, user secrets etc - and easily accessed through the same interface in your application. Further to this, the new configuration system in ASP.NET allows (actually, enforces) strongly typed settings using the IOptions<> pattern.
While working on an RC2 project the other day, I was trying to use this facility to bind a custom Configuration class, but for the life of me I couldn’t get it to bind my properties. Partly that was down to the documentation being somewhat out of date since the launch of RC2, and partly down to the way binding works using reflection. In this post I’m going to go into demonstrate the power of the IOptions<> pattern, and describe a few of the problems I ran in to and how to solve them.
Strongly typed configuration In ASP.NET Core, there is now no default AppSettings["MySettingKey"] way to get settings. Instead, the recommended approach is to create a strongly typed configuration class with a structure that matches a section in your configuration file (or wherever your configuration is being loaded from):
public class MySettings { public string StringSetting { get; set; } public int IntSetting { get; set; } } Would map to the lower section in the appsettings.json below.
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } }, "MySettings": { "StringSetting": "My Value", "IntSetting": 23 } } Binding the configuration to your classes In order to ensure your appsettings.json file is bound to the MySettings class, you need to do 2 things.
Setup the ConfigurationBuilder to load your file Bind your settings class to a configuration section When you create a new ASP.NET Core application from the default templates, the ConfigurationBuilder is already configured in Startup.cs to load settings from environment variables, appsettings.json, and in development environments, from user secrets:
public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment()) { builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); Configuration = builder.Build(); } If you need to load your configuration from another source then this is the place to do it, but for most common situations this setup should suffice. There are a number of additional configuration providers that can be used to bind other sources, such as xml files for example.
In order to bind a settings class to your configuration you need to configure this in the ConfigureServices method of Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure(options => Configuration.GetSection(“MySettings”).Bind(options));
}
Note: The syntax for model binding has changed from RC1 to RC2 and was one of the issues I was battling with. The previous method, using services.Configure(Configuration.GetSection(“MySettings”)), is no longer available
You may also need to add the configuration binder package to the dependencies section of your project.json:
“dependencies”: {
…
“Microsoft.Extensions.Configuration.Binder”: “1.0.0-rc2-final”
…
}
Update: As mentioned by Larry Ruckman, you can now use the old binding syntax if you add the package Microsoft.Extensions.Options.ConfigurationExtensions with version 1.0.0-rc2-final to your project.json
Using your configuration class When you need to access the values of MySettings you just need to inject an instance of an IOptions<> class into the constructor of your consuming class, and let dependency injection handle the rest:
public class HomeController : Controller { private MySettings _settings; public HomeController(IOptions settings) { _settings = settings.Value // _settings.StringSetting == "My Value"; } }
The IOptions<> service exposes a Value property which contains your configured MySettings class.
It’s important to note that there doesn’t appear to be a way to access the raw IConfigurationRoot through dependency injection, so the strongly typed route is the only way to get to your settings.
You can expose the IConfigurationRoot directly to the DI container using services.AddSingleton(Configuration). (Thanks Saša Ćetković for pointing that out!)
Complex configuration classes
The example shown above is all very nice, but what if you have a very complex configuration, nested types, collections, the whole 9 yards?
public class MySettings { public string StringSetting { get; set; } public int IntSetting { get; set; } public Dictionary Dict { get; set; } public List ListOfValues { get; set; } public MyEnum AnEnum { get; set; } }
public class InnerClass { public string Name { get; set; } public bool IsEnabled { get; set; } = true; }
public enum MyEnum { None = 0, Lots = 1 } Amazingly we can bind that using the same configure call to the following, and it all just works:
{ "MySettings": { "StringSetting": "My Value", "IntSetting": 23, "AnEnum": "Lots", "ListOfValues": ["Value1", "Value2"], "Dict": { "FirstKey": { "Name": "First Class", "IsEnabled": false }, "SecondKey": { "Name": "Second Class" } } } }
When values aren’t provided, they get their default values, (e.g. MySettings.Dict[“SecondKey].IsEnabled == true). Dictionaries, lists and enums are all bound correctly. That is until they aren’t…
using IOptions for reading configurations - My example
Add Connection Strings to appsetting.json: { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "ConnectionStrings": { "PHODB": "server=MCPHOSQLTST01;user id=AppPHO;password=C0ff33M8;database=PHO" }, "AllowedHosts": "*" }
--------------- Add new folder to project name it may be "settings". add a class with the same name as the object in appsettings.json for which you would like to create a class. here it is ConnectionString. Create public property for data that needs to be accessed
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication5.Settings { public class ConnectionStrings { public string PHODB { get; set; } } }
in program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingcontex,config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile(“appsettings.json”, optional: true, reloadOnChange: false);
}
) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) ;
add a method to add the json appsettings file; to read the connection string; using system.IO for Directory class
in start up.cs
include the configuration with the class that we created
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure(options => Configuration.GetSection(“ConnectionStrings”).Bind(options));
}
—
use the Dependency injection for IOptions and use it in our api controller:
[ApiController]
[Route(“[controller]”)]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
“Freezing”, “Bracing”, “Chilly”, “Cool”, “Mild”, “Warm”, “Balmy”, “Hot”, “Sweltering”, “Scorching”
};
private readonly ILogger _logger; private readonly ConnectionStrings _connectionStrings; private readonly string _PHODB_ConnectionString; public WeatherForecastController(ILogger logger,IOptions options) { _logger = logger; _connectionStrings = options.Value; _PHODB_ConnectionString = _connectionStrings.PHODB; }
Make sure that the class name created for IOptions and the object in the appsettings.json are the same. The property names also should be the same
https://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
custom options
CustomOptions object is part of an example of how you can use the appsettings to embed custom app settings into various parts of the app. To use the Alerts example, your current rule is to show 3 active alerts at a time. However, if you wanted to make that more configurable without changing code, you could put a property in the CustomOptions section of the appsettings and a corresponding property in the CustomOptions object and then float that around to various DALs or controllers by putting IOptions in the constructor. In the Alert example, you could pick that up in the DAL constructor and set it as a private member in the class and use it in the sproc call to retrieve 3 items. If you wanted to change it to 5, you could change the appsettings property and restart the application to use 5 instead, without any code changes (of course, also changing the appsettings in source control should you wish to keep the change).
As to whether or not you need it from class to class, that’s up to you to decide.
This feels like a smaller app with fewer options, so it might be safe in this instance to just have one CustomOptions object. In the bigger picture, you can nest objects in CustomOptions and read them into the app individually by JSON path, so you could have CustomOptions.AlertOptions, and CustomOptions.PatientOptions, but I don’t know off the top of my head if you’ll even have any custom options in this app just yet.
Adding custom options example
in appsettings.json define custom options
{
“Logging”: {
“LogLevel”: {
“Default”: “Information”,
“Microsoft”: “Warning”,
“Microsoft.Hosting.Lifetime”: “Information”
}
},
“ConnectionStrings”: {
“PHODB”: “server=MCPHOSQLTST01;user id=AppPHO;password=C0ff33M8;database=PHO”
},
“CustomOptions”: {
“Message”: “this is data from appsettings.json, custom options”,
“CustomOptionValue”: “test”
},
“AllowedHosts”: “*”
}
———–
in program.cs, we are already reading the appsettings.json file for connectionstring;so we do not need to put it again
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingcontex, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile(“appsettings.json”, optional: true, reloadOnChange: false);
}
) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); }
--- Create a new class for CustomOptions with the properties similar to appsettings.json file: namespace WebApplication5.Settings { public class CustomOptions { public string Message { get; set; } public string CustomOptionValue { get; set; } } }
in startup.cs
add the mapping
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure(options => Configuration.GetSection(“ConnectionStrings”).Bind(options));
services.Configure(options => Configuration.GetSection(“CustomOptions”).Bind(options));
}
–
update the dependency injection in api controller action method
private readonly ILogger _logger;
private readonly ConnectionStrings _connectionStrings;
private readonly string _PHODB_ConnectionString;
//For custom options private readonly CustomOptions _customOptions; private readonly string _message;
public WeatherForecastController(ILogger logger,IOptions options, IOptions customoptions) { _logger = logger; _connectionStrings = options.Value; _PHODB_ConnectionString = _connectionStrings.PHODB; _customOptions = customoptions.Value; _message = _customOptions.Message; }
How to using AutoMapper on ASP.NET Core 3.0 via Dependency Injection
Step 1. Install AutoMapper extension from Package Manager in your project Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection -Version 7.0.0 Step 2. Register a service in CinfigureServices on Startup.cs // Startup.cs using AutoMapper; public void ConfigureServices(IServiceCollection services){ services.AddAutoMapper(typeof(Startup)); } Step 3. Create a model and a data transfer object // User.cs // The model you want to map from public class User{ public string Name {get;set;} public string Email {get;set;} public string Phone {get;set;} // Constructor to initialize User public User(){ Name = "Nicky"; Email = "myemail@gmail.com"; Phone = "+81234588"; } } // UserDTO.cs // The data transfer object you want to map to public class UserDTO{ public string Name{get;set;} public string Email{get;set;} public string Phone{get;set;} } Step 4. Create an AutoMapping class file to register a mapping relation // AutoMapping.cs using AutoMapper; public class AutoMapping : Profile { public AutoMapping() { CreateMap(); // means you want to map from User to UserDTO } } Step 5. Map User to UserDTO in code // HomeController.cs using AutoMapper; public class HomeController : Controller { private readonly IMapper _mapper; public HomeController(IMapper mapper) { _mapper = mapper; } public IActionResult GetUser() { User user = new User(); var userDTO = _mapper.Map(user); return View(userDTO); } } Finally, you got a dto object: var name = userDTO.Name; // name = "Nicky" var email = userDTO.Email; // email = "myemail@gmail.com" var phone = userDTO.Phone; // phone = "+81234588"
https://www.codementor.io/@zedotech/how-to-using-automapper-on-asp-net-core-3-0-via-dependencyinjection-zq497lzsq
What is Middleware?
Middleware was firstly introduced in ASP.NET Core 1.0 (Q1 2016). Middleware is components of an application that examine the requests responses coming into and coming out from an ASP.NET Core application. In other words, it’s the layer that every request and response have to go through.
ASP.NET Core version 1.1 (Q4 2016) brought some new features, performance improvements, and also addressed many bugs and compatibility issues affecting to the former one. The new features include the ability to configure Middleware as Filters.
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.
How middleware works
How it works?
When an HTTP request comes in, the first request delegate handles that request. It chooses either passing the request on to the next component in the pipeline or performing certain actions before and after the next component is invoked in the pipeline. It allows unnecessary work to be avoided. This is very useful in some scenarios like handling exceptions before anything else or serving static files.
The returned response travels back in the reverse direction back through the pipeline. This allows each component to run code both times: when the request arrives and also when the response is on its way out. (see figure 2)
Middleware :What are Run, Map and Use?
Run, Map and Use are three methods that you will need to use to configure HTTP Pipeline.
Run method
Run method
The Run method is an extension method on IApplicationBuilder and accepts a parameter of RequestDelegate that handles the request. “Run” method enables short-circuiting with a terminal middleware delegate.
Middle ware “Use” method
This method allows you to call the next desired middleware delegate. The call to app.Use() can be used to trigger the next middleware component with a call to next.Invoke() as shown below:
Middleware “Map” method
This method is used to match request delegates based on a request’s path. This method allows branching of the pipeline path. In other words, this method creates separate forked paths/branches for your middleware pipeline and multiple terminating ends.
Built-In Middleware
I will show you, how the built-in middleware works and why the order is important.
Note: We should use the “Use” prefix naming convention when we create new custom Middleware. For example: UseFileUploadErrorPage, UseDebugErrorPage,…
Exception Handling:
UseDeveloperExceptionPage() & UseDatabaseErrorPage(): used in development phase to catch run-time exceptions.
UseExceptionHandler(): used in production for run-time exceptions
Calling these methods first ensures that exceptions are caught.
- HSTS & HTTPS Redirection:
UseHsts(): used in production to enable HSTS (HTTP Strict Transport Security Protocol) and enforce HTTPS.
UseHttpsRedirection(): forces HTTP calls to automatically redirect to equivalent HTTPS addresses.
Calling these methods next ensure that HTTPS can be enforced before resources are served from a web browser. - Static files:
UseStaticFiles(): used to enable static files, such as HTML, JavaScript, CSS and graphics files.
This Middleware is called early on to avoid the need for authentication, session or MVC middleware. - Cookie Policy:
UseCookiePolicy(): used to enforce cookie policy and display GDPR-friendly messaging - Authentication, Authorization & Sessions:
UseAuthentication(): used to enable authentication and then subsequently allow authorization.
UserSession(): manually added to the Startup file to enable the Session middleware.
Calling these after cookie authentication (but before the MVC middleware) ensures that cookies can be issued as necessary and that the user can be authenticated before the MVC engine kicks in. - MVC & Routing:
UseMvc(): enables the use of MVC in your web application, with the ability to customize routes for your MVC application and set other options.
routes.MapRoute(): set the default route and any custom routes when using MVC.
Custom Middleware
https://medium.com/swlh/what-is-middleware-in-asp-net-core-and-how-important-is-it-3021d4fb90d2
We can use some custom Middleware on NuGet. For example: Diagnostic Middleware.
Note: If you want to create your custom Middleware, please read again section: “What are Run, Map and Use?” above.
Diagnostics middleware is used for reporting and handling exceptions and errors in ASP.NET Core, and diagnosing Entity Framework Core migrations errors.
This package includes following middleware and extension methods for it.
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.
order of the middle ware is important, as they get executed in sequence
The below diagram illustrates the typical order of middleware layers in an ASP .NET Core web application. The order is very important, so it is necessary to understand the placement of each request delegate in the pipeline.
Middleware is like interceptor in angular
Middleware is like interceptor in angular
configuration options and their sequence of preferrence
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1
CreateDefaultBuilder provides default configuration for the app in the following order:
ChainedConfigurationProvider : Adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
appsettings.json using the JSON configuration provider.
appsettings.Environment.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
App secrets when the app runs in the Development environment.
Environment variables using the Environment Variables configuration provider.
Command-line arguments using the Command-line configuration provider.
Configuration providers that are added later override previous key settings. For example, if MyKey is set in both appsettings.json and the environment, the environment value is used. Using the default configuration providers, the Command-line configuration provider overrides all other providers.