This tutorial on ASP.NET Core MVC Configurations will reveal you a lot about the inside of this framework. This will give you a solid foundation for understanding the coming topics later on. I will start by creating a new project using empty template.
Page Contents
When you create a project using Empty Template you have to do the configurations by yourself. This includes:
And many more things which you will see in this tutorial.
Start with opening your Visual Studio and then select Create a new project from the file menu. You will see the option – ASP.NET Core Web Application, so select it.
Then click the ‘Create’ Button.
Now you will get another dialog box. Here you select Empty template, and also select the Framework, Version, Template and Authentication.
Make the follow settings (as shown by the below image):
This will create your ASP.NET Core MVC with Empty Template.
The name of the .csproj file which in your application will be configuration.csproj.
This file is hidden by Visual Studio and must be accessed by right clicking your project and select Edit Configuration.csproj.
The initial context of the Configuration.csproj file is shown below:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> </Project>
The csproj contains many settings which are used to build .NET Projects. You can add any package that your application needs to this file. When you any package to the csproj file then Visual Studio downloads that package. Similarly when you remove any package from csproj file then Visual Studio removes that package from your application.
Element | Description |
---|---|
Project | It is the root element, the Sdk attribute specifies that the application should be build with Microsoft.NET.Sdk.Web package. |
PropertyGroup | Used to group related properties. |
TargetFramework | Instructs .NET Core to use the specified version when building a project. |
ItemGroup | Used to group related items. |
Folder | It tells .NET Core to include the folder (here wwwroot) when publishing the project. |
PackageReference | It specifies dependency on the NuGet package. The Microsoft.AspNetCore.All is a package providing access to all individual packages which provides ASP.NET Core and MVC functionalities. |
Json.NET is a popular high-performance JSON package for .NET. It is used to serialize and deserialize JSON. To add Json.NET packages add the below ItemGroup inside the ‘Project node’ of the csproj file:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> </ItemGroup> </Project>
As soon as you save the csproj file, VS will download the Json.NET package and add it to your project.
Typing package names and there versions on the csproj file can be error prone. You can avoid this typing completely by adding packages through NuGet Package Manager.
NuGet Package Manager allows for the management of NuGet packages through an easy-to-use interface. Select Tools ➤ NuGet Package Manager ➤ Manage NuGet
Packages for Solution in your Visual Studio. This will opens NuGet Solution dialog box, there click the Browse tab and enter the name of package in the text box. When you see you searched package on the list, select it and then click the ‘Install’ button.
In the below image I have searched for Json.NET, and then selecting and installing it.
There is a shorter way too if you know the name of the package you require (and, ideally, the version). This is this way through Package Manger Console.
To open it follow the below procedure:
Select Tools ➤ NuGet Package Manager ➤ Packages Manager Console in your Visual Studio then enter the below given line (and press enter key) to install the Json.NET package.
PM> Install-Package Newtonsoft.Json
This command is given on Nuget for every package. Check this link to find the command for Json.NET package.
On the root folder of your application you will find the Program.cs which is called the Program Class. It has a Main() function that provides the entry point for running the application.
The default code of the Program Class is shown below:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Configuration { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } }
The Main method in the Program class calls a CreateHostBuilder() function, which configures the ASP.NET Core like setting up the hosting environment.
Inside the CreateHostBuilder() function, you will find it calling the CreateDefaultBuilder() function which configures the application with the Most Suitable Settings. By Most Suitable Settings I mean the settings which are suitable for most of the ASP.NET Core applications.
The UseStartup() function calls the Startup.cs class which is also kept on the application root folder. The Startup.cs class provides application specific configuration. In the next section you will learn more about Startup Class.
The Build() function builds the application and if no errors are found then will run your application on the browser.
Inside the CreateHostBuilder() function you can provide individual configuration settings. In the below code I have provided 2 individual settings – UseContentRoot & UseIISIntegration.
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>(); });
Some important settings are:
Name | Description |
---|---|
UseContentRoot() | Specifies the content root directory for the application. |
UseIISIntegration | Enables integration with IIS and IIS Express. |
UseKestrel() | Configures the Kestrel web server. |
Kestrel is an open-source, cross-platform web server for hosting ASP.NET applications on any platform. It is used automatically when running ASP.NET Core application with IIS.
You can use Kestrel by itself or with a reverse proxy server, such as IIS, Nginx, or Apache. A reverse proxy server receives HTTP requests from the Internet and forwards them to Kestrel after some preliminary handling.
In order to use Kestrel by itself, for running ASP.NET Core MVC application on any of the supported platforms, you click the arrow on the right of IIS Express button in your VS then select the option that says the name of your application. In this application it will be Configuration.
Once selected the name of your application you have to run your application (shortcut F5 key). Now your application will now run on Kestrel only.
You will find the Startup.cs file on your application’s root folder. This file is the Startup class. The Program Class calls the Startup Class using UseStartup() function. In the startup class you can provide a lot of application specific configuration which you will see in the coming sections.
If you open the Startup class you will see it like shown below:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace Configuration { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); }); } } }
The Startup Class contains 2 methods – ConfigureServices() and Configure().
In the ConfigureServices() method you can create one or more services that can be used throughout your application. A service can be anything that do a task and is available throughout the application. In the below section I will create a simple service to help you understand them in a better way.
In the Configure() method you can configure HTTP Request pipeline which is also know by the name middleware. I will also create some middlewares later on.
In the current code, when you run the application it will just sent the response text – Hello World! on the browser for all requests.
An ASP.NET Core Service can be anything in which does a particular task and is available all through the application. Examples are like:
I will create a small ASP.NET Core Service that provides the application with the total number of registered users.
Start by creating a folder in your application’s root folder and name it Services or anything you like. Inside this Services folder create a class and name it TotalUsers.cs and add the following code to it:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Configuation.Services { public class TotalUsers { public long TUsers() { Random rnd = new Random(); return rnd.Next(100, int.MaxValue); } } }
This class has one public method – Tusers() which returns the total number of users registered in the application. This method returns a random number between 100 and max value of Int. In a real application you are going to fetch this value from the database
The next step involves registering this class in the Startup.cs class so that ASP.NET Core can make this service available throughout the application.
So go the Startup.cs class and import the namespace – using Configuation.Services;.
Next add the following codes inside the ConfigureServices() method:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<TotalUsers>();
services.AddControllersWithViews();
}
The services.AddSingleton() will add the service which can now be shared all thought the application. The services.AddControllersWithViews() will add adds support for controllers, API-related features, and views in the application.
Next, inside the Configure() method you will find app.UseEndpoints() method (shown below).
app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); });
Replace it to:
app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); });
So the Startup class will now look like:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSingleton<TotalUsers>(); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } }
The service is now created and available through in the application. Let us understand how to use this service in a controller.
So create Controllers folder in the root of your application and right click on this newly created folder and select New ➤ Controller.
You get a new window which asks to select the controller type. So select MVC Controller – Empty.
Name this controller as HomeController and import the namespace – using Configuation.Services;.
Finally add the following code to it:
public class HomeController : Controller { private TotalUsers totalUsers; public HomeController(TotalUsers tu) { totalUsers = tu; } public string Index() { return "Total Users are: " + totalUsers.TUsers(); } }
The controller has a constructor which has our service class called TotalUsers in its parameter. When ASP.NET calls this controller it sees the constructor requires an object i.e. has a dependency for the service class called TotalUsers.
MVC then goes to the Startup class and finds the TotalUsers class been configured as a service. So it will now create an instance of the TotalUsers class (by its own) and pass it to the construction of the Home Controller.
Now see the Index action method of the controller, which uses the TotalUsers instance provided by MVC, and calls the TUsers() method to get the total number of registered users. It finally returns them as string to the View.
Next, create a new folder called Views on the root of the application. Inside this folder create another folder and name it Home.
Now create Index View inside the Views ➤ Home folder, and add the following code to it.
@model string
@Model
To test the service run your application and see the total number of users displayed on the browser.
Middleware in ASP.NET Core are components that sits on the HTTP Request Pipeline and thus are used to configure them. There can be one or more Middlewares sitting on the HTTP pipeline in a line.
When a new HTTP request arrives, it is send to the first Middleware which inspects it. This Middleware will then do 1 of the 2 things:
On handling the complete request, the response will be returned to the client along the same order, which allows all of the earlier Middleware to inspect or modify it.
There are 4 types of Middleware:
Let us create a small Middleware that will only generate some content and hence named as Content-Generating Middleware.
Create a new folder inside the application’s root folder and name it
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Configuation.Middlewares { public class ContentMiddleware { private RequestDelegate nextDelegate; public ContentMiddleware(RequestDelegate next) => nextDelegate = next; public async Task Invoke(HttpContext httpContext) { if (httpContext.Request.Path.ToString() == "/middleware") { await httpContext.Response.WriteAsync("This is from the content middleware"); } else { await nextDelegate.Invoke(httpContext); } } } }
Please note that the Middleware class doesn’t implement an interface or derive from a common base class. They have a constructor that takes a parameter of type RequestDelegate which is provided to it automatically by MVC. The RequestDelegate object represents the next middleware component in the line.
The Middleware also define an Invoke method. This method is called when .NET receives an HTTP request. The Invoke method has a parameter of type HttpContext which contains Information about the HTTP request and the response that will be returned to the client.
In my ContentMiddleware.cs class the Invoke method inspects the HTTP request and checks to see whether the request has been sent to the url /middleware. If it has, then it sends a simple text response – This is from the content middleware. If a different URL has been initiated, then the request is forwarded to the next Middleware in the line.
You have to register the Middleware inside the Configure method of the Startup class using the UseMiddleware() method like shown below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
app.UseMiddleware<ContentMiddleware>();
}
Now run the application and then go to the URL – https://localhost:44343/middleware. You will see the response from the Middleware as shown by the image below:
If the URL is not – https://localhost:44343/middleware then the Content Middleware will pass the request to the next Middleware. Note that here there is no Middleware left therefore the request is returned back.
Middleware can also receive Services just like Controllers. In the previous section I created a service called TotalUsers, you can use this service in your Middleware by providing it’s dependency in the class constructor. See the below updated code:
using System.Threading.Tasks; using Configuation.Services; using Microsoft.AspNetCore.Http; namespace Configuation.Middlewares { public class ContentMiddleware { private RequestDelegate nextDelegate; private TotalUsers totalUsers; public ContentMiddleware(RequestDelegate next, TotalUsers tu) { nextDelegate = next; totalUsers = tu; } public async Task Invoke(HttpContext httpContext) { if (httpContext.Request.Path.ToString() == "/middleware") { await httpContext.Response.WriteAsync("This is from the content middleware, Total Users: " + totalUsers.TUsers()); } else { await nextDelegate.Invoke(httpContext); } } } }
Run you application and go to the URL – https://localhost:44343/middleware.
Short-Circuiting Middleware don’t always forward request to the next Middleware in the line. That’s why they are called Short-Circuiting Middleware.
Let’s create this type of Middleware. Inside the Middlewares folder create a new class and name it ShortCircuitMiddleware, and add the below code to it:
using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Configuation.Middlewares { public class ShortCircuitMiddleware { private RequestDelegate nextDelegate; public ShortCircuitMiddleware(RequestDelegate next) => nextDelegate = next; public async Task Invoke(HttpContext httpContext) { if (httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"))) { httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } else { await nextDelegate.Invoke(httpContext); } } } }
Now go to the Configure method of the Startup class and register this middleware above the previous ‘ContentMiddleware’ Middleware, as shown below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // after UseRouting app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>(); }
The Middleware executes in the order in which they are registered in the Configure method. I want ShortCircuitMiddleware to execute before ContentMiddleware so I have placed it at first.
The ShortCircuitMiddleware Middleware will not forward the request received from Firefox browser and returns unauthorized status. For other browsers it forwards the request to the ContentMiddleware.
If you now run your application and open the URL – https://localhost:44343/middleware in Firefox browser. You will receive a blank page. For other browsers you will get the same response which you get previously.
The blank page you get in Firefox browser is shown below:
So far we have seen 2 types of Middleware that generates response. Now we will see Middleware that do not generate response instead edit requests. This type of Middleware is known as Request-Editing Middleware.
Create a class inside the Middlewares folder and name it RequestEditingMiddleware.cs. Add the given code to it:
using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Configuation.Middlewares { public class RequestEditingMiddleware { private RequestDelegate nextDelegate; public RequestEditingMiddleware(RequestDelegate next) => nextDelegate = next; public async Task Invoke(HttpContext httpContext) { httpContext.Items["Firefox"] = httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox")); await nextDelegate.Invoke(httpContext); } } }
The RequestEditingMiddleware.cs Class only edits the HTTP Request (and does not sends any response). It checks if the request is made from Firefox browser in that case adds a key called Firefox with Boolean value ‘true’ to the HttpContext dictionary. The below given code does this work:
httpContext.Items["Firefox"] = httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"));
Now edit the ShortCircuitMiddleware.cs class which you made earlier. Delete or comment out the line which checks the User-Agent.
//if (httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox")))
In place of it check the item named ‘Firefox’ in the HttpContext. See the below code:
if (httpContext.Items["Firefox"] as bool? == true)
The updated code of ShortCircuitMiddleware.cs Class is given below:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace Configuration.Middlewares { public class ShortCircuitMiddleware { private RequestDelegate nextDelegate; public ShortCircuitMiddleware(RequestDelegate next) => nextDelegate = next; public async Task Invoke(HttpContext httpContext) { //if (httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"))) if (httpContext.Items["Firefox"] as bool? == true) { httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } else { await nextDelegate.Invoke(httpContext); } } } }
This change is done because the Request-Editing Middleware is checking the User-Agent for firefox and adding it to the HttpContext’s items dictionary. So the value is being provided to the Short-Circuiting Middleware.
Finally Register the Request Editing Middleware on the Configure() method of Statup class:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseMiddleware<RequestEditingMiddleware>(); app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>(); app.UseMvcWithDefaultRoute(); }
I placed the Request-Editing Middleware at the start of the HTTP pipeline. This ensures that the request has already been modified before it is forwarded to other Middleware.
Run the application and upon the URL – https://localhost:44343/middleware in firefox. You will get a blank page due to unauthorized HTTP request condition.
As the name suggest the Response-Editing Middleware edits only the response generated by other Middleware.
Right now we are getting a blank page on the Firefox browser. Blank page is no good for real applications, we should also show some message. So with the use of Response-Editing Middleware I will provide text response which users will see only on the firefox browser.
Add a new Class inside the Middlewares folder and name it ResponseEditingMiddleware.cs. Add the below code to it:
using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Configuation.Middlewares { public class ResponseEditingMiddleware { private RequestDelegate nextDelegate; public ResponseEditingMiddleware(RequestDelegate next) { nextDelegate = next; } public async Task Invoke(HttpContext httpContext) { await nextDelegate.Invoke(httpContext); if (httpContext.Response.StatusCode == 401) { await httpContext.Response.WriteAsync("Firefox browser not authorized"); } else if (httpContext.Response.StatusCode == 404) { await httpContext.Response.WriteAsync("No Response Generated"); } } } }
In the above code if the HTTP status code in the response is 401 then I am adding text – Firefox browser not authorized to the response. Recall that the 401 un-authorized response is generated by Short-Circuiting Middleware.
Since the Response-Editing Middleware only edits the response of other Middleware it has to be placed before other Middleware in the HTTP pipeline. So register it below other Middleware in the Configure() method of Startup class:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseMiddleware<ResponseEditingMiddleware>(); app.UseMiddleware<RequestEditingMiddleware>(); app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>(); app.UseMvcWithDefaultRoute(); }
Now run your application and go to URL – https://localhost:44343/middleware in the Firefox browser. You will get the response text – Firefox browser not authorized. This is shown in the image below.
In the Response-Editing Middleware there is an else if block:
else if (httpContext.Response.StatusCode == 404)
{
await httpContext.Response.WriteAsync("No Response Generated");
}
This will execute when status code is 404. This status code is automatically generated when there is no resource found in the application for a url.
Open any random url which is not served by the application like – https://localhost:44343/tutorials. You will see No Response Generated message on your browser.
The Startup Class Configure() method has a parameter of type IApplicationBuilder Interface. This Interface allows the Middleware pipeline to be created.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//.....
}
An important use of IApplicationBuilder Interface is to configure the ASP.NET Core Routes.
If you open Startup file of your application and check the Configure method. There is a method called – app.UseRouting() which adds an Endpoint Routing middleware to the IApplicationBuilder.
Then you can use the Endpoint Routing like what we used in this application:
app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); });
Worth mentioning are 2 important methods for doing routes configuration.
The UseMvcWithDefaultRoute is used to set up the default routes in the application. Use it inside the Configure method as shown below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //... app.UseMvcWithDefaultRoute(); }
The UseMvc is used to configure custom routes in the application. Eg.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //... app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
The above code only shows one custom route. An application can have hundreds of routes set up.
The method UseMvcWithDefaultRoute is just a shortcut. When you use – app.UseMvcWithDefaultRoute(); you are actually just setting up the following route:
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
The Startup Class Configure() method has another parameter of type IWebHostEnvironment Interface. It provides information about the hosting environment.
Let’s see some important properties of IWebHostEnvironment Interface.
Name | Description |
---|---|
ApplicationName | Returns the name of the application. |
EnvironmentName | Returns the name of the environment. |
ContentRootPath | Returns the path that contains the application’s content & configuration files. |
WebRootPath | Returns the path that contains the application’s static content. This is usually ‘wwwroot’ folder. |
In ASP.NET Core there are 3 environments – Development, Staging & Production. Environments help in setting different configurations in the application.
To set up your environment in the application, go to the Solution Explorer and right click on your application name and select Properties.
In the properties page select the Debug option. There you will see the current hosting environment is set using an environment variable called ASPNETCORE_ENVIRONMENT. You can change its value to either Development, Staging & Production. When you are done save by pressing CTRL+S. Check the below image where I have illustrated this thing.
Within the Configure method, you can determine which hosting environment is being used in the following manner:
In the below code I made sure the Middleware are registered only if the environment is Production.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsProduction()) { app.UseMiddleware<ResponseEditingMiddleware>(); app.UseMiddleware<RequestEditingMiddleware>(); app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>(); app.UseMvcWithDefaultRoute(); } }
The WebRootPath property gives the application’s static content folder which is the wwwroot. You can use this property inside a Controller to get the absolute path of the files that are kept in this folder.
To do this, pass the IWebHostEnvironment as the parameter to the constructor of the Controller. The Dependency Injection feature of ASP.NET Core will automatically provide the IWebHostEnvironment value to the constructor. Then you can simply use the WebRootPath property to get the absolute path.
public class MediaController : Controller { private IWebHostEnvironment hostingEnvironment; public MediaController(IWebHostEnvironment environment) { hostingEnvironment = environment; } public ActionResult Index() { string absolutePath = Path.Combine(hostingEnvironment.WebRootPath, "file1.jpg"); return View(); } }
Exceptional Handling is not enabled in your application. You can check it by running your application and then go to some non-existing URL like https://localhost:44343/Game. You will see a message on the browser saying – No Response Generated.
This is an Exception but the message does not state anything regarding it’s cause. User must see some proper messages like 404 for non-existing page, 401 for un-authorized, 403 for forbidden. To do this you have to enable Exception Handling.
To enable Exception Handling in your application you need to put the below 2 lines of code inside the Configure() method of the Startup class:
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
Before you check how it works, make sure you comment out the line where the Response Editing Middleware is added in the startup class
//app.UseMiddleware<ResponseEditingMiddleware>();
Now re-run your application and re-visit the URL – https://localhost:44343/Game. You will see the full exception details:
The above Exception was caused by the non-existing action method i.e. a resource which is not found. In fact Exceptions can be cause by a number of ways, mainly due to wrong codes. I will show what happens when exception occurs inside an action method code.
Go to the Home Controller and add 2 action methods. The first is called Exception and it throws a NullReferenceException type of exception. The other is called Error and it is automatically called when some exception happens in the code.
These 2 action methods are given below:
public ViewResult Exception() { throw new System.NullReferenceException(); } public ViewResult Error() { return View(); }
Create a view called Error inside the Views ➤ Home folder and add the following code to it:
<h2>Some Problem</h2> We got some problem, please visit back after sometime.
Now re-run your application and visit the URL – https://localhost:44343/Home/Exception. You will see full Exception message with Stack Trace to explore the cause of the exception.
This full Exception message with Stack Trace is very helpful to developers but it should not be shown the common users of the site.
For this you use the method – IsDevelopment() to show full exception when website is running in the Development mode (localhost).
When the website is running in production you show a common error view for exceptions.
Update your Configure method code with that shown below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseStatusCodePages(); } else { app.UseExceptionHandler("/Home/Error"); } //... }
The app.UseExceptionHandler(“/Home/Error”) method shows the Error View if the website is not running in the development mode.
Set the environment variable – ASPNETCORE_ENVIRONMENT to ‘Production’ and run the application and visit the ‘/Home/Exception’ page. This time you will see the Error View as shown in the image below.
In order to make the application use images, JavaScript files, CSS stylesheets which are kept inside the wwwroot folder you have to add – app.UseStaticFiles() inside the configure method of the Startup class.
I called the UseStaticFiles code for all environments since it is needed every time. Put it just before the app.UseRouting() method.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //... app.UseStaticFiles(); app.UseRouting(); //... }
ASP.NET Core MVC has a JSON file by the name appsettings.json. In this file you can store any data like DB Connection String, logging settings, global variable etc.
To create this file, right click the your project name in the Solution Explorer and select Add ➤ New Item. You will get a dialog box up where you can search for the text ‘appsettings.json’, and this file will show up.
The below figure shows how to select the appsettings.json from the ‘Add New Item’ dialog box.
In the appsettings.json file I want to store which middleware to enable in the application. So add the following code to this file:
{ "Middleware": { "EnableContentMiddleware": true, "EnableShortCircuitMiddleware": true, "EnableRequestEditingMiddleware": true, "EnableResponseEditingMiddleware": false } }
This JSON file contains 4 variables – EnableContentMiddleware, EnableShortCircuitMiddleware, EnableRequestEditingMiddleware & EnableResponseEditingMiddleware. I have given each of them a bool value, and I will read their values in Startup class. Then based on the value I will register the Middleware i.e. if the value of the variable is true only then I will register the Middleware.
You can see the last variable – EnableResponseEditingMiddleware is provided value as false and others variables are provided value as true. So all the Middleware except the Response Editing Middleware will be registered.
Now finally on your Startup class add the namespace – using Microsoft.Extensions.Configuration
Then add a property of type IConfiguration and add the constructor that takes the parameter of type IConfiguration. The parameter’s value will be provided automatically by ASP.NET Core from the Dependency Injection feature.
See the below code:
public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; }
Finally change the code inside the Configure method as shown below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if ((Configuration.GetSection("Middleware")?.GetValue<bool>("EnableResponseEditingMiddleware")).Value) { app.UseMiddleware<ResponseEditingMiddleware>(); } if ((Configuration.GetSection("Middleware")?.GetValue<bool>("EnableRequestEditingMiddleware")).Value) { app.UseMiddleware<RequestEditingMiddleware>(); } if ((Configuration.GetSection("Middleware")?.GetValue<bool>("EnableShortCircuitMiddleware")).Value) { app.UseMiddleware<ShortCircuitMiddleware>(); } if ((Configuration.GetSection("Middleware")?.GetValue<bool>("EnableContentMiddleware")).Value) { app.UseMiddleware<ContentMiddleware>(); } }
In the above code I am reading the bool values of these 4 variables which are kept inside the ‘Middleware’ node. If the value is true then the corresponding Middleware is registered.
When you run the application, all except the Response Editing Middleware will be registered.
As stated earlier the appsettings.json stores the connection string for the database. During the course of application development the programmers will want to have not 1 but 2 appsetting.json files in their application.
One that will be used during development and which will contains the connection string (or other variables) to local database.
The other one will be used during production (i.e. when you publish the website and put it on hosting server), and this one will contain the connection string to the production database i.e. the live database.
I will show you how to do this.
First add your connection string to your live database on your appsettings.json file like shown below:
{ "ConnectionStrings": { "DefaultConnection": "Server=SQL6003.site4now.net;Database=DB_A3CE39_y11;User Id=DB_PCE39_y11_admin;[email protected];" } }
Now add a new appsetting.json file on your application root folder and give it the name – appsettings.development.json. Then add your local development database connection string as shown below.
{ "ConnectionStrings": { "DefaultConnection": "Server=vaio;Database=Goldentaurus;Trusted_Connection=True;" } }
This newly added appsettings.development.json file will remain hidden in the solutions explorer. To view this file right click the arrow (➤) before the appsettings.json file.
The below image explains this:
Now go to the Program.cs file and change the BuildWebHost method from:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
To:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); }) .UseIISIntegration() .UseStartup<Startup>(); });
Inside this method you will see a method ConfigureAppConfiguration() being called. It is used to register the appsettings.development.json file.
Now you can run your application and will find the appsettings.development.json file is used when the application runs in development (localhost), and the other appsettings.json file is used in production (live) environment.
To get the connection string, add to the ConfigureServices method of the Starup class, the following code:
services.AddDbContext<SomeClass>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
This code will provide the constructor of SomeClass.cs this Connection string value.
You can download the full codes of this tutorial from the below link:
Share this article -