1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64
Cross Platform - can be hosted on IIS, Apache, Docker, or even self-host in your own process
Unified Programming Model for MVC and Web API - the Controller that we create inherits from the same Controller base class and returns IActionResult. In the case of a Web API, the controller returns a JsonResult and in the case of an MVC style web application it returns a ViewResult
Dependency Injection : Out of the box, ASP.NET Core has built-in support for dependency injection.
Testability
Open-source and community-focused
2. Setting up machine for asp.net core development - NA
3. Creating asp.net core web application - NA
The File System determines what files and folders belong to the project.
Microsoft.AspNetCore.App : This NuGet package is called metapackage. A metapackage has no content of its own but is a list of dependencies (other packages).
15 Introduction to MVC
Nothing useful
16. Setup mvc in asp.net core
UseStaticFiles is used before mvc middleware to avoid any extra processing should the request come for any static file. UseMvcWithDefaultRoute will look for 'Home' controller with 'Index' action method. If it does not find one, it will check for next middleware that can server the request. If there is no middleware that can support this request, the page will crash.
17. ASP.NET Core AddMvc vs AddMvcCore
In addition to AddMvc() method we also have AddMvcCore() method on the IServiceCollection interface.
AddMvcCore() method only adds the core MVC services. On the other hand, AddMvc() method adds all the required MVC services. AddMvc() method calls AddMvcCore() method internally, to add all the core MVC services. So if we are calling AddMvc() method there is no need to explicitly call AddMvcCore() method again.
E.g. to return the json data from an action method, JsonFormatterServices need to be registered with the dependency injection container. AddMvc() method does this but not the AddMvcCore() method.
21. Views in ASP.NET Core MVC
View files that belong to a specific controller are stored in a sub-folder in the Views folder and that sub-folder has the same name as the controller
22. Customize view discovery in asp.net core mvc
a. return View();
b. return View("Test");
c. return View("MyViews/Test.cshtml");
d. return View("../Test/Update");
23. Passing data to view in ASP.NET Core MVC
In ASP.NET Core MVC, there are 3 ways to pass data from a controller to a view
Using ViewData
Using ViewBag
Using a strongly typed model object. This is also called Strongly typed view.
ViewData is a dictionary of weakly typed objects. To store and retrieve data from the ViewData dictionary we use string keys. No need to cast if we are casting to string type. If it is any other type except String, we need to explicitly cast it to the type we are expecting. ViewData is dynamically resolved at runtime, so it does not provide compile-time type checking and as a result we do not get intellisense. So, chances of typo are there which we come to know on runtime.
24. ViewBag in ASP.NET Core MVC
ViewBag is a wrapper around ViewData. With ViewBag we use dynamic properties instead of string keys.
Unlike ViewData, where we need to explicitly cast the object of a comlex type, we dont need to do that in a ViewBag.
25 Stringly typed view in Core
The preferred approach to pass data from a controller to a view is by using a strongly typed view. To create a strongly typed view, in the controller action method, pass the model object to the View() helper method. a strongly typed view provides compile-time type checking and intellisense.
31 _ViewImports.cshtml in ASP.NET Core MVC
_ViewImports.cshtml file is usually placed in the Views folder. It is used to include the common namespaces so we do not have to include them in every view that needs those namespaces.
For example, if we include the following 2 namespaces in the ViewImports file, then all the types in these 2 namespaces are available to every view in the "Home" folder without having to type the fully qualified name of the Type.
@using EmployeeManagement.Models;
47. DbContext in entity framework core
One of the very important classes in Entity Framework Core is the DbContext class. This is the class that we use in our application code to interact with the underlying database. It is this class that manages the database connection and is used to retrieve and save data in the database.
a. The DbContext class includes a DbSet<TEntity> property for each entity in the model.
b. We will use this DbSet property Employees to query and save instances of the Employee class.
c. The LINQ queries against the DbSet<TEntity> will be translated into queries against the underlying database.
d. The DbContextOptions instance carries configuration information such as the connection string, database provider to use etc.
48. Using sql server with entity framework core
Difference between AddDbContext() and AddDbContextPool() methods
a. The difference between AddDbContext() and AddDbContextPool() methods is, AddDbContextPool() method provides DbContext pooling.
b. From a performance standpoint AddDbContextPool() method is better over AddDbContext() method.
c. AddDbContextPool() method is introduced in ASP.NET Core 2.0
49. Repository pattern in asp.net core
Repository Pattern is an abstraction of the Data Access Layer. It hides the details of how exactly the data is saved or retrieved from the underlying data source. The details of how the data is stored and retrieved is in the respective repository.
public class SQLEmployeeRepository : IEmployeeRepository
{
private readonly AppDbContext context;
public SQLEmployeeRepository(AppDbContext context)
{
this.context = context;
}
///other DB methods
}
Which class to bind in the app is in Startup class in Startup.cs file.
public void ConfigureServices(IServiceCollection services)
{
// Rest of the code
services.AddScoped<IEmployeeRepository, SQLEmployeeRepository>();
}
We are using AddScoped() method because we want the instance to be alive and available for the entire scope of the given HTTP request. For another new HTTP request, a new instance of SQLEmployeeRepository class will be provided and it will be available throughout the entire scope of that HTTP request.
50. Entity framework core migrations
Migration is an entity framework core feature that keeps the database schema and our application model classes (also called entity class) in sync.
If you have not executed at-least the initial migration in your application you might get the following SqlException
SqlException: Cannot open database "EmployeeDB" requested by the login.
To work with migrations, we can either use the Package Manager Console (PMC) or the .NET core command-line interface (CLI)
Creating a Migration in Entity Framework Core
The following command creates the initial migration : Add-Migration InitialCreate
When the above command completes, you will see a file in the "Migrations" folder that contains the name InitialCreate.cs.
For updating the database, we use Update-Database command. To the Update-Database command we may pass the migration name we want to execute. If no migration is specified, the command by default executes the last migration.
After the migration is executed, when you navigate to the application we no longer get the following SqlException
51 Entity framework core seed data
In your application DbContext class, override OnModelCreating() method. In this example, HasData() method configures Employee entity to have the specified seed data.
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().HasData(
new Employee
{
Id = 1,
Name = "Mark",
Department = Dept.IT,
Email = "mark@pragimtech.com"
}
);
}
}
-- Now use the migrations to update your model and DB
-- may be also move the seeding part to a extension method
52 Keeping domain models and database schema in sync in asp.net core
As we develop our application and add new features, our application domain classes change. When the domain classes change, the corresponding changes have to be made to the underlying database schema. Otherwise the database schema goes out of sync and the application does not work as expected. We use migrations to keep the database schema in sync as the application domain classes change.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Dept? Department { get; set; }
public string PhotoPath { get; set; } --- new prop added
}
step a -> Add-Migration AddPhotoPathToEmployees --- this creates a file by the name --[TimeStap]_AddPhotoPathToEmployees.cs -
This class contains 2 methods - Up() and Down(). Up() method contains code to apply the changes made to the model class to the underlying database schema. Down() method contains code to undo the changes.
step b -> Update-Database
To apply the migration and update the database use Update-Database command. This command executes the code in Up() method and applies the changes to the underlying database objects.
[DbContextClassName]ModelSnapshot.cs - As the name implies this file contains the snapshot of your current model. This file is created when the first migration is added and updated with each subsequent migration. EF core migrations API uses this file to determine what has changed when adding the next migration.
__EFMigrationsHistory table -- It is created in the database, when the first migration is executed. This table is used to keep track of the migrations that are applied to the database. There will be an entry for every migration that is applied.
To remove a migration execute Remove-Migration command. It only removes one migration at a time and that too only the latest migration that is not yet applied to the database. If all the migrations are already applied, executing Remove-Migration command throws the exception saying 'migration_name' has already been applied to the DB.
Removing a migration that is already applied to the database
Let's say we have the following 3 migrations already applied to the database.
Migration_One
Migration_Two
Migration_Three
We want to remove both migration Migration_Two and Migration_Three. Since all these 3 migrations are already applied to the database, executing Remove-Migration command will throw an error.
To be able to remove a migration that is already applied to the database, we first have to undo the changes the migration made to the database. The way we do this is by executing Update-Database command with a migration name.
If we relate this to our example, we want to undo the changes done by Migration_Two and Migration_Three and bring the database state to the state it was in, when Migration_One was executed. To achieve this we execute Update-Database command with Migration_One name as -- Update-Database Migration_One
Executing the above command will undo the changes made by Migration_Two and Migration_Three. EF core will also remove the entries for these 2 migrations from __EFMigrationsHistory table.
However, the migration code files will still be there in the Migrations folder. To remove the code files use Remove-Migration command. Since we want to remove both Migration_Three and Migration_Two code files, we want to execute Remove-Migration command twice
53. File upload in asp.net core mvc
Create a prop in the model by the return type IFormFile. This interface gives a couple of different properties on the uplaoded file.
public IFormFile Photo { get; set; }
html-->
@* asp-for tag helper is set to "Photo" property. "Photo" property type is IFormFile
so at runtime asp.net core generates file upload control (input type=file)
*@
<div class="form-group row">
<label asp-for="Photo" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
<input asp-for="Photo" class="form-control custom-file-input">
<label class="custom-file-label">Choose File...</label>
</div>
</div>
</div>
In the details view html(where you show the image), use this html->
<img class="card-img-top" src="@photoPath" asp-append-version="true" />
asp-append-version is used for cache busting
61 - Logging in ASP.NET Core
FYI, We can run an asp.net core application from the Command Line or from Visual Studio like below:
c:\Projects\EmployeeManagement\EmployeeManagement>dotnet run
Add the below line:
"Logging": {
"LogLevel": { --- Log level is used to control how much log data is logged or displayed.
"Default": "Warning",
"Microsoft": "Warning" --- only add this line in your core project
}
}
When you add this line, and run the project (either from IIS or from the command line using the dotnet run command), we see lot of information logged to the console
ASP.Net core logging providers -A logging provider is the component that stores or displays logs. .Net Core can display logs in the following:
Console, Debug ,EventSource ,EventLog ,TraceSource ,AzureAppServicesFile ,AzureAppServicesBlob ,ApplicationInsights
Third Party providers are:
NLog,elmah,Serilog,Sentry,Gelf,JSNLog,KissLog.net,Loggr,Stackdriver
Q- How is this logging being done automatically?
Ans: 'CreateDefaultBuilder' in the startup class (when the application is being configured) be default adds 3 diff providers - Console, Debug, EventSource
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
})
62. Logging exceptions in ASP.NET Core
If there are exceptions, while users are using our application we need to log the exceptions somewhere.
Logging Exceptions in ASP.NET Core is a 2 step process
1. Inject an instance of ILogger where you need the logging functionality
private readonly ILogger<ErrorController> logger;
public ErrorController(ILogger<ErrorController> logger)
{
this.logger = logger;
}
2. LogError() method logs the exception under Error category.
logger.LogError($"The path {exceptionHandlerPathFeature.Path} " +
$"threw an exception {exceptionHandlerPathFeature.Error}");
You can also use LogWarning() to log the warnings
63. Logging to file in asp.net core using nlog
Using NLog in ASP.NET Core
Step 1 : Install NLog.Web.AspNetCore nuget package
Step 2 : Create nlog.config file in the root of your project. Here is the minimum configuration required:
Step 3 : Enable copy to bin folder
Right click on nlog.config file in the Solution Explorer and select Properties. In the Properties window set-> Copy to Output Directory = Copy if newer
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
// Enable NLog as one of the Logging Provider
logging.AddNLog(); -- Added this line only. Rest are already there in the ASP.Net core by default
})
.UseStartup<Startup>();
}
64. ASP.NET Core LogLevel configuration
LogLevel indicates the severity of the logged message.
Trace = 0 Debug = 1 Information = 2 Warning = 3 Error = 4 Critical = 5 None = 6
LogTrace(), LogDebug() ,LogInformation() ,LogWarning(), LogError(), LogCritical() are the different methods for the logging various logs.
LogLevel setting in appsettings.json file is used to control how much log data is logged or displayed.
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning"
}
}
}
Since we have set "Default": "Trace", we see everything from Trace level and higher. Since Trace is the lowest level we see all the logs.
Log filtering in ASP.NET Core
LOG CATEGORY is the fully qualified name of the class that logged the message. The log category is displayed as a string in the logged message so we can use it easily determine from which class the log came from. LOG CATEGORY is used to filter logs.
It is also possible to filter logs by Provider and by Category
Log Filtering by Log Category and by Logging Provider
{
"Logging": {
"Debug": { --- THis is logging provider debug (just like Console, Debug ,EventSource, etc)
"LogLevel": {
"Default": "Warning",-- This is a log category
"EmployeeManagement.Controllers.HomeController": "Warning", -- This is a log category
"EmployeeManagement.Models.SQLEmployeeRepository": "Warning",-- This is a log category
"Microsoft": "Warning" -- This is a log category
}
},
"LogLevel": {
"Default": "Trace",
"EmployeeManagement.Controllers.HomeController": "Trace",
"EmployeeManagement.Models.SQLEmployeeRepository": "Trace",
"Microsoft": "Trace"
}
}
}
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64
1. Introduction
ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-based, Internet-connected applications.Cross Platform - can be hosted on IIS, Apache, Docker, or even self-host in your own process
Unified Programming Model for MVC and Web API - the Controller that we create inherits from the same Controller base class and returns IActionResult. In the case of a Web API, the controller returns a JsonResult and in the case of an MVC style web application it returns a ViewResult
Dependency Injection : Out of the box, ASP.NET Core has built-in support for dependency injection.
Testability
Open-source and community-focused
2. Setting up machine for asp.net core development - NA
3. Creating asp.net core web application - NA
4. ASP.NET core project file
One significant change is, the project file does not contain any folder or file reference. In previous versions of ASP.NET, when we add a file or folder to the project using solution explorer, a reference to that file or folder is included in the project file. In ASP.NET core, the project file does not contain any folder or file reference.The File System determines what files and folders belong to the project.
Microsoft.AspNetCore.App : This NuGet package is called metapackage. A metapackage has no content of its own but is a list of dependencies (other packages).
5. Main method in asp.net core
In an ASP.NET Core project we have a file with name Program.cs. In this file we have a public static void Main() method . an asp.net core application initially starts as a console application and the Main() method in Program.cs file is the entry point. This Main() method configures asp.net core and starts it and at that point it becomes an asp.net core web application.15 Introduction to MVC
Nothing useful
16. Setup mvc in asp.net core
UseStaticFiles is used before mvc middleware to avoid any extra processing should the request come for any static file. UseMvcWithDefaultRoute will look for 'Home' controller with 'Index' action method. If it does not find one, it will check for next middleware that can server the request. If there is no middleware that can support this request, the page will crash.
17. ASP.NET Core AddMvc vs AddMvcCore
In addition to AddMvc() method we also have AddMvcCore() method on the IServiceCollection interface.
AddMvcCore() method only adds the core MVC services. On the other hand, AddMvc() method adds all the required MVC services. AddMvc() method calls AddMvcCore() method internally, to add all the core MVC services. So if we are calling AddMvc() method there is no need to explicitly call AddMvcCore() method again.
E.g. to return the json data from an action method, JsonFormatterServices need to be registered with the dependency injection container. AddMvc() method does this but not the AddMvcCore() method.
21. Views in ASP.NET Core MVC
View files that belong to a specific controller are stored in a sub-folder in the Views folder and that sub-folder has the same name as the controller
22. Customize view discovery in asp.net core mvc
a. return View();
b. return View("Test");
c. return View("MyViews/Test.cshtml");
d. return View("../Test/Update");
23. Passing data to view in ASP.NET Core MVC
In ASP.NET Core MVC, there are 3 ways to pass data from a controller to a view
Using ViewData
Using ViewBag
Using a strongly typed model object. This is also called Strongly typed view.
ViewData is a dictionary of weakly typed objects. To store and retrieve data from the ViewData dictionary we use string keys. No need to cast if we are casting to string type. If it is any other type except String, we need to explicitly cast it to the type we are expecting. ViewData is dynamically resolved at runtime, so it does not provide compile-time type checking and as a result we do not get intellisense. So, chances of typo are there which we come to know on runtime.
24. ViewBag in ASP.NET Core MVC
ViewBag is a wrapper around ViewData. With ViewBag we use dynamic properties instead of string keys.
Unlike ViewData, where we need to explicitly cast the object of a comlex type, we dont need to do that in a ViewBag.
25 Stringly typed view in Core
The preferred approach to pass data from a controller to a view is by using a strongly typed view. To create a strongly typed view, in the controller action method, pass the model object to the View() helper method. a strongly typed view provides compile-time type checking and intellisense.
26 Why do we need a ViewModel in ASP.NET Core MVC
In some cases, a model object may not contain all the data a view needs. This is when we create a ViewModel. It contains all the data a view needs.
27 List View In Core
@foreach (var employee in Model)
{
<tr>
<td>
@employee.Id
</td>
<td>
@employee.Name
</td>
<td>
@employee.Department
</td>
</tr>
}
28. Layout view in asp.net core mvc
Without a Layout View, we would repeat all the HTML for these different sections in every view in our application. With layout views, maintaining the consistent look and feel across all the views becomes much easier
Since a layout view is not specific to a controller, we usually place the layout view in a sub folder called "Shared" in the "Views" folder
@RenderBody() is the location where view specific content is injected. For example, if index.chtml view is rendered using this layout view, index.cshtml view content is injected at the location where we have @RenderBody() method call.
29 Sections in layout page in ASP.NET Core MVC
A layout page in ASP.NET Core MVC can also include a section. A section can be optional or mandatory. It provides a way to organize where certain page elements should be placed.
In the layout page, call RenderSection() method at the location where you want the section content to be rendered. In our case, we want the script file to be included just before the closing </body> tag. This is the reason we have placed the call to @RenderSection() method just before the closing </body> tag.
Making the layout section optional
There are 2 options to mark a layout section as optional
Option 1 : Set required parameter of RenderSection() method to false
@RenderSection("Scripts", required: false)
Option 2 : Use IsSectionDefined() method
@if (IsSectionDefined("Scripts"))
{
@RenderSection("Scripts", required: false)
}
@foreach (var employee in Model)
{
<tr>
<td>
@employee.Id
</td>
<td>
@employee.Name
</td>
<td>
@employee.Department
</td>
</tr>
}
28. Layout view in asp.net core mvc
Without a Layout View, we would repeat all the HTML for these different sections in every view in our application. With layout views, maintaining the consistent look and feel across all the views becomes much easier
Since a layout view is not specific to a controller, we usually place the layout view in a sub folder called "Shared" in the "Views" folder
@RenderBody() is the location where view specific content is injected. For example, if index.chtml view is rendered using this layout view, index.cshtml view content is injected at the location where we have @RenderBody() method call.
29 Sections in layout page in ASP.NET Core MVC
A layout page in ASP.NET Core MVC can also include a section. A section can be optional or mandatory. It provides a way to organize where certain page elements should be placed.
In the layout page, call RenderSection() method at the location where you want the section content to be rendered. In our case, we want the script file to be included just before the closing </body> tag. This is the reason we have placed the call to @RenderSection() method just before the closing </body> tag.
Making the layout section optional
There are 2 options to mark a layout section as optional
Option 1 : Set required parameter of RenderSection() method to false
@RenderSection("Scripts", required: false)
Option 2 : Use IsSectionDefined() method
@if (IsSectionDefined("Scripts"))
{
@RenderSection("Scripts", required: false)
}
Providing Section Content
Every view that intends to provide content for the section, must include a section with the same name.
30 _ViewStart.cshtml in ASP.NET Core MVC
It's a special file in ASP.NET Core MVC. The code in this file is executed before the code in an individual view is executed. So this means, instead of setting the Layout property in each individual view, we can move that code into the _ViewStart.cshtml file.
@{
Layout = "_Layout";
}
_ViewStart.cshtml file is hierarchical.The layout page specified in the ViewStart file in the Home sub-folder overwrites the layout page specified in the ViewStart file in the Views folder.
31 _ViewImports.cshtml in ASP.NET Core MVC
_ViewImports.cshtml file is usually placed in the Views folder. It is used to include the common namespaces so we do not have to include them in every view that needs those namespaces.
For example, if we include the following 2 namespaces in the ViewImports file, then all the types in these 2 namespaces are available to every view in the "Home" folder without having to type the fully qualified name of the Type.
@using EmployeeManagement.Models;
@using EmployeeManagement.ViewModels;
@addTagHelper ,@removeTagHelper ,@tagHelperPrefix ,@model, @inherits, @inject
These tags are also supported
32 Routing in ASP.NET Core MVC
There are 2 routing techniques in ASP.NET Core MVC. Conventional Routing and Attribute Routing.
The incoming request URL is mapped to a controller action method. This mapping is done by the routing rules defined in our application.
-------
35. Tag helpers in asp.net core
Tag helpers are new in ASP.NET Core. They are server side components processed on the server to create and render HTML elements in Razor files. Tag Helpers are similar to HTML helpers.
To import inbuilt tag helpers, use below directive in _ViewImports.cshtml file
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
The wildcard * indicates that we want to import all the tag helpers
Microsoft.AspNetCore.Mvc.TagHelpers is the assemly that contains the built-in tag helpers
37. ASP.NET Core Image tag helper
When we visit a web page, most modern browsers cache the images of that web page. When we visit the page again, instead of downloading the same image again from the web server, the browser serves the image from the cache. In most cases, this is not a problem as images do not change that frequently. From a performance standpoint, wouldn't it be great to download the image only if it has changed on the server. If the image has not changed, use the image from the browser cache.Image Tag Helper can help us achieve this.
<img src="~/images/noimage.jpg" asp-append-version="true" />
This is called Cache busting behaviour
Based on the content of the image, a unique hash value is calculated and is appended to image URL. This unique string prompts the browser to reload the image from the server and not from the browser cache.
38.ASP.NET Core Environment Tag Helper
Environment tag helper supports rendering different content depending on the application environment. The application environment name is set using using ASPNETCORE_ENVIRONMENT variable.
<environment include="Development">
<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
</environment>
<environment include="Staging,Production">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
</environment>
Consider the below example:
<environment include="Development">
<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link rel="stylesheet"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
href="https://sstackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position"
asp-fallback-test-value="absolute"
asp-suppress-fallback-integrity="true" />
</environment>
----
If the application environment is "Development", non-minified bootstrap css file (bootstrap.css) is loaded from our application web server
If the application environment IS NOT "Development", minified bootstrap css file (bootstrap.min.css) is loaded from the CDN
39. Bootstrap navigation menu in asp.net core application
Practival example
40. Form tag helpers in asp.net core
<form asp-controller="home" asp-action="create" method="post">
</form>
This creates html like:
<form method="post" action="/home/create"></form>
Input Tag Helper - <input asp-for="Name">
Label Tag Helper - <label asp-for="Name"></label>
Select Tag Helper - select asp-for="Department" asp-items="Html.GetEnumSelectList<Dept>()"></select>
41. ASP.NET Core Model Binding
Model binding maps data in an HTTP request to controller action method parameters
The action parameters may be simple types such as integers, strings, etc or complex types like Customer, Employee, Order etc.
Model binding is great, because without it we have to write lot of custom code to map request data to action method parameters which is not only tedious but also error prone.
HTTP Request Data
To bind the request data to the controller action method parameters, model binding looks for data in the HTTP request in the following places in the order specified below.
Form values
Route values
Query strings
Model Binding Complex Types
Model Binding also works with complex types such as Customer, Order, Employee etc.
Interview Question: If we pass the model parameter value in both route data and Query String, the route data value gets prefererence (based on above order). Once got, the value will not be overwritten.
42. ASP.NET Core model validation
System.ComponentModel.DataAnnotations namespace
In the code side, check for ModelState.IsValid property
For HTML,
32 Routing in ASP.NET Core MVC
There are 2 routing techniques in ASP.NET Core MVC. Conventional Routing and Attribute Routing.
The incoming request URL is mapped to a controller action method. This mapping is done by the routing rules defined in our application.
-------
35. Tag helpers in asp.net core
Tag helpers are new in ASP.NET Core. They are server side components processed on the server to create and render HTML elements in Razor files. Tag Helpers are similar to HTML helpers.
To import inbuilt tag helpers, use below directive in _ViewImports.cshtml file
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
The wildcard * indicates that we want to import all the tag helpers
Microsoft.AspNetCore.Mvc.TagHelpers is the assemly that contains the built-in tag helpers
The Anchor Tag Helper enhances the standard HTML anchor (<a ... ></a>) tag by adding new attributes such as
asp-controller , asp-action , asp-route-{value}
The rendered anchor element's href attribute value is determined by the values of these asp- attributes.
36. Why use tag helpers
Tag helpers generate links based on the application routing templates. This means if we later change routing templates, the links generated by tag helpers will automatically reflect those changes made to the routing templates. The generated links just work.
If the defautl route chages to comsething like this:
app.UseMvc(routes =>
{
routes.MapRoute("default", "pragim/{controller=Home}/{action=Index}/{id?}");
});
The normal action link would fail since they would not be able to accomodate the new change. However, if we use the Tag Helpers, the link created are:
<a href="/pragim/home/details/1">View</a>
They just work.
37. ASP.NET Core Image tag helper
When we visit a web page, most modern browsers cache the images of that web page. When we visit the page again, instead of downloading the same image again from the web server, the browser serves the image from the cache. In most cases, this is not a problem as images do not change that frequently. From a performance standpoint, wouldn't it be great to download the image only if it has changed on the server. If the image has not changed, use the image from the browser cache.Image Tag Helper can help us achieve this.
<img src="~/images/noimage.jpg" asp-append-version="true" />
This is called Cache busting behaviour
Based on the content of the image, a unique hash value is calculated and is appended to image URL. This unique string prompts the browser to reload the image from the server and not from the browser cache.
38.ASP.NET Core Environment Tag Helper
Environment tag helper supports rendering different content depending on the application environment. The application environment name is set using using ASPNETCORE_ENVIRONMENT variable.
<environment include="Development">
<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
</environment>
<environment include="Staging,Production">
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
</environment>
Consider the below example:
<environment include="Development">
<link href="~/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link rel="stylesheet"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
href="https://sstackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position"
asp-fallback-test-value="absolute"
asp-suppress-fallback-integrity="true" />
</environment>
----
If the application environment is "Development", non-minified bootstrap css file (bootstrap.css) is loaded from our application web server
If the application environment IS NOT "Development", minified bootstrap css file (bootstrap.min.css) is loaded from the CDN
Practival example
40. Form tag helpers in asp.net core
<form asp-controller="home" asp-action="create" method="post">
</form>
This creates html like:
<form method="post" action="/home/create"></form>
Input Tag Helper - <input asp-for="Name">
Label Tag Helper - <label asp-for="Name"></label>
Select Tag Helper - select asp-for="Department" asp-items="Html.GetEnumSelectList<Dept>()"></select>
41. ASP.NET Core Model Binding
Model binding maps data in an HTTP request to controller action method parameters
The action parameters may be simple types such as integers, strings, etc or complex types like Customer, Employee, Order etc.
Model binding is great, because without it we have to write lot of custom code to map request data to action method parameters which is not only tedious but also error prone.
HTTP Request Data
To bind the request data to the controller action method parameters, model binding looks for data in the HTTP request in the following places in the order specified below.
Form values
Route values
Query strings
Model Binding Complex Types
Model Binding also works with complex types such as Customer, Order, Employee etc.
Interview Question: If we pass the model parameter value in both route data and Query String, the route data value gets prefererence (based on above order). Once got, the value will not be overwritten.
42. ASP.NET Core model validation
System.ComponentModel.DataAnnotations namespace
Required | Specifies the field is required |
Range | Specifies the minimum and maximum value allowed |
MinLength | Specifies the minimum length of a string |
MaxLength | Specifies the maximum length of a string |
Compare | Compares 2 properties of a model. For example compare Email and ConfirmEmail properties |
RegularExpression | Validates if the provided value matches the pattern specified by the regular expression |
For HTML,
<div class="form-group row">
<label asp-for="Name" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Name" class="form-control" placeholder="Name">
<span asp-validation-for="Name"></span>
</div>
</div>
43. Select list validation in asp.net core
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
[Required]
public Dept? Department { get; set; }
}
a. Make the enum as nullable (so that a even if we dont provide a value, it should not complain)
b. Add the required attribute (so that it is required even)
Generally, this comes in a scenario where we have a 'please select' kind of a entry at zero position.
44. AddSingleton vs AddScoped vs AddTransient
@inject is used when you want a service instance in the cshtml side
E.g. @inject IEmployeeRepository empRepository
Registering Services- 3 methods to register services with the dependency injection container. The method that we use determines the lifetime of the registered service.
1. AddSingleton() - As the name implies, AddSingleton() method creates a Singleton service. A Singleton service is created when it is first requested. This same instance is then used by all the subsequent requests. So in general, a Singleton service is created only one time per application and that single instance is used throughout the application life time.
2. AddTransient() - This method creates a Transient service. A new instance of a Transient service is created each time it is requested.
3. AddScoped() - This method creates a Scoped service. A new instance of a Scoped service is created once per request within the scope. For example, in a web application it creates 1 instance per each http request but uses the same instance in the other calls within that same web request.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}
Service Type | In scope of given http request | Across different http requests |
Scoped | Same Instance | New Instance |
Transient | New Instance | New Instance |
Singleton | Same Instance | Same Instance |
45. Introduction to entity framework core
Just an intro. Nothng useful.
46. Install entity framework core in visual studio
An ASP.NET Core Web application project that is created using ASP.NET Core 2.1 or higher has the following NuGet package installed - "Microsoft.AspNetCore.App". This package is called - metapackage. A metapackage has no content of its own but is a list of dependencies (other packages).
To install Entity Framework Core and to be able to use SQL server as the database for your application, you need to install the following nuget packages.
Microsoft.EntityFrameworkCore.SqlServer ---- depends on ----> Microsoft.EntityFrameworkCore.Relational ---- depends on ---->
Microsoft.EntityFrameworkCore
Just install the first one, and the rest will be installed automatically.
Check this link for official documentation on providers.
https://docs.microsoft.com/en-us/ef/core/providers/
One of the very important classes in Entity Framework Core is the DbContext class. This is the class that we use in our application code to interact with the underlying database. It is this class that manages the database connection and is used to retrieve and save data in the database.
a. The DbContext class includes a DbSet<TEntity> property for each entity in the model.
b. We will use this DbSet property Employees to query and save instances of the Employee class.
c. The LINQ queries against the DbSet<TEntity> will be translated into queries against the underlying database.
d. The DbContextOptions instance carries configuration information such as the connection string, database provider to use etc.
48. Using sql server with entity framework core
Difference between AddDbContext() and AddDbContextPool() methods
a. The difference between AddDbContext() and AddDbContextPool() methods is, AddDbContextPool() method provides DbContext pooling.
b. From a performance standpoint AddDbContextPool() method is better over AddDbContext() method.
c. AddDbContextPool() method is introduced in ASP.NET Core 2.0
Repository Pattern is an abstraction of the Data Access Layer. It hides the details of how exactly the data is saved or retrieved from the underlying data source. The details of how the data is stored and retrieved is in the respective repository.
public class SQLEmployeeRepository : IEmployeeRepository
{
private readonly AppDbContext context;
public SQLEmployeeRepository(AppDbContext context)
{
this.context = context;
}
///other DB methods
}
Which class to bind in the app is in Startup class in Startup.cs file.
public void ConfigureServices(IServiceCollection services)
{
// Rest of the code
services.AddScoped<IEmployeeRepository, SQLEmployeeRepository>();
}
We are using AddScoped() method because we want the instance to be alive and available for the entire scope of the given HTTP request. For another new HTTP request, a new instance of SQLEmployeeRepository class will be provided and it will be available throughout the entire scope of that HTTP request.
50. Entity framework core migrations
Migration is an entity framework core feature that keeps the database schema and our application model classes (also called entity class) in sync.
If you have not executed at-least the initial migration in your application you might get the following SqlException
SqlException: Cannot open database "EmployeeDB" requested by the login.
To work with migrations, we can either use the Package Manager Console (PMC) or the .NET core command-line interface (CLI)
Creating a Migration in Entity Framework Core
The following command creates the initial migration : Add-Migration InitialCreate
When the above command completes, you will see a file in the "Migrations" folder that contains the name InitialCreate.cs.
For updating the database, we use Update-Database command. To the Update-Database command we may pass the migration name we want to execute. If no migration is specified, the command by default executes the last migration.
After the migration is executed, when you navigate to the application we no longer get the following SqlException
In your application DbContext class, override OnModelCreating() method. In this example, HasData() method configures Employee entity to have the specified seed data.
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().HasData(
new Employee
{
Id = 1,
Name = "Mark",
Department = Dept.IT,
Email = "mark@pragimtech.com"
}
);
}
}
-- Now use the migrations to update your model and DB
-- may be also move the seeding part to a extension method
52 Keeping domain models and database schema in sync in asp.net core
As we develop our application and add new features, our application domain classes change. When the domain classes change, the corresponding changes have to be made to the underlying database schema. Otherwise the database schema goes out of sync and the application does not work as expected. We use migrations to keep the database schema in sync as the application domain classes change.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Dept? Department { get; set; }
public string PhotoPath { get; set; } --- new prop added
}
step a -> Add-Migration AddPhotoPathToEmployees --- this creates a file by the name --[TimeStap]_AddPhotoPathToEmployees.cs -
This class contains 2 methods - Up() and Down(). Up() method contains code to apply the changes made to the model class to the underlying database schema. Down() method contains code to undo the changes.
step b -> Update-Database
To apply the migration and update the database use Update-Database command. This command executes the code in Up() method and applies the changes to the underlying database objects.
[DbContextClassName]ModelSnapshot.cs - As the name implies this file contains the snapshot of your current model. This file is created when the first migration is added and updated with each subsequent migration. EF core migrations API uses this file to determine what has changed when adding the next migration.
__EFMigrationsHistory table -- It is created in the database, when the first migration is executed. This table is used to keep track of the migrations that are applied to the database. There will be an entry for every migration that is applied.
To remove a migration execute Remove-Migration command. It only removes one migration at a time and that too only the latest migration that is not yet applied to the database. If all the migrations are already applied, executing Remove-Migration command throws the exception saying 'migration_name' has already been applied to the DB.
Removing a migration that is already applied to the database
Let's say we have the following 3 migrations already applied to the database.
Migration_One
Migration_Two
Migration_Three
We want to remove both migration Migration_Two and Migration_Three. Since all these 3 migrations are already applied to the database, executing Remove-Migration command will throw an error.
To be able to remove a migration that is already applied to the database, we first have to undo the changes the migration made to the database. The way we do this is by executing Update-Database command with a migration name.
If we relate this to our example, we want to undo the changes done by Migration_Two and Migration_Three and bring the database state to the state it was in, when Migration_One was executed. To achieve this we execute Update-Database command with Migration_One name as -- Update-Database Migration_One
Executing the above command will undo the changes made by Migration_Two and Migration_Three. EF core will also remove the entries for these 2 migrations from __EFMigrationsHistory table.
However, the migration code files will still be there in the Migrations folder. To remove the code files use Remove-Migration command. Since we want to remove both Migration_Three and Migration_Two code files, we want to execute Remove-Migration command twice
53. File upload in asp.net core mvc
Create a prop in the model by the return type IFormFile. This interface gives a couple of different properties on the uplaoded file.
public IFormFile Photo { get; set; }
html-->
@* asp-for tag helper is set to "Photo" property. "Photo" property type is IFormFile
so at runtime asp.net core generates file upload control (input type=file)
*@
<div class="form-group row">
<label asp-for="Photo" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
<input asp-for="Photo" class="form-control custom-file-input">
<label class="custom-file-label">Choose File...</label>
</div>
</div>
</div>
In the details view html(where you show the image), use this html->
<img class="card-img-top" src="@photoPath" asp-append-version="true" />
asp-append-version is used for cache busting
61 - Logging in ASP.NET Core
FYI, We can run an asp.net core application from the Command Line or from Visual Studio like below:
c:\Projects\EmployeeManagement\EmployeeManagement>dotnet run
Add the below line:
"Logging": {
"LogLevel": { --- Log level is used to control how much log data is logged or displayed.
"Default": "Warning",
"Microsoft": "Warning" --- only add this line in your core project
}
}
When you add this line, and run the project (either from IIS or from the command line using the dotnet run command), we see lot of information logged to the console
ASP.Net core logging providers -A logging provider is the component that stores or displays logs. .Net Core can display logs in the following:
Console, Debug ,EventSource ,EventLog ,TraceSource ,AzureAppServicesFile ,AzureAppServicesBlob ,ApplicationInsights
Third Party providers are:
NLog,elmah,Serilog,Sentry,Gelf,JSNLog,KissLog.net,Loggr,Stackdriver
Q- How is this logging being done automatically?
Ans: 'CreateDefaultBuilder' in the startup class (when the application is being configured) be default adds 3 diff providers - Console, Debug, EventSource
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
})
62. Logging exceptions in ASP.NET Core
If there are exceptions, while users are using our application we need to log the exceptions somewhere.
Logging Exceptions in ASP.NET Core is a 2 step process
1. Inject an instance of ILogger where you need the logging functionality
private readonly ILogger<ErrorController> logger;
public ErrorController(ILogger<ErrorController> logger)
{
this.logger = logger;
}
2. LogError() method logs the exception under Error category.
logger.LogError($"The path {exceptionHandlerPathFeature.Path} " +
$"threw an exception {exceptionHandlerPathFeature.Error}");
You can also use LogWarning() to log the warnings
63. Logging to file in asp.net core using nlog
Using NLog in ASP.NET Core
Step 1 : Install NLog.Web.AspNetCore nuget package
Step 2 : Create nlog.config file in the root of your project. Here is the minimum configuration required:
Step 3 : Enable copy to bin folder
Right click on nlog.config file in the Solution Explorer and select Properties. In the Properties window set-> Copy to Output Directory = Copy if newer
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
// Enable NLog as one of the Logging Provider
logging.AddNLog(); -- Added this line only. Rest are already there in the ASP.Net core by default
})
.UseStartup<Startup>();
}
64. ASP.NET Core LogLevel configuration
LogLevel indicates the severity of the logged message.
Trace = 0 Debug = 1 Information = 2 Warning = 3 Error = 4 Critical = 5 None = 6
LogTrace(), LogDebug() ,LogInformation() ,LogWarning(), LogError(), LogCritical() are the different methods for the logging various logs.
LogLevel setting in appsettings.json file is used to control how much log data is logged or displayed.
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning"
}
}
}
Since we have set "Default": "Trace", we see everything from Trace level and higher. Since Trace is the lowest level we see all the logs.
Log filtering in ASP.NET Core
LOG CATEGORY is the fully qualified name of the class that logged the message. The log category is displayed as a string in the logged message so we can use it easily determine from which class the log came from. LOG CATEGORY is used to filter logs.
It is also possible to filter logs by Provider and by Category
Log Filtering by Log Category and by Logging Provider
{
"Logging": {
"Debug": { --- THis is logging provider debug (just like Console, Debug ,EventSource, etc)
"LogLevel": {
"Default": "Warning",-- This is a log category
"EmployeeManagement.Controllers.HomeController": "Warning", -- This is a log category
"EmployeeManagement.Models.SQLEmployeeRepository": "Warning",-- This is a log category
"Microsoft": "Warning" -- This is a log category
}
},
"LogLevel": {
"Default": "Trace",
"EmployeeManagement.Controllers.HomeController": "Trace",
"EmployeeManagement.Models.SQLEmployeeRepository": "Trace",
"Microsoft": "Trace"
}
}
}
No comments:
Post a Comment