Archive for the ‘ASP.NET’ Category

In the last post we found that the Startup class in ASP.NET Core works based on convention. The runtime inspects the class through reflection and invokes the appropriate methods i.e. Configure and ConfigureServices (optional). If class is not properly implemented e.g. say Configure method is not present then there should be a runtime exception. When I removed the Configure method from the Startup class I got the following error:

Unhandled Exception: System.InvalidOperationException: A public method named ‘ConfigureProduction’ or ‘Configure’ could not be found in the ‘startuptest.Startup’ type.

The above message is quite as expected but it was not clear to me why runtime was looking for a method named ConfigureProduction?

There seems to be something missing in the documentation and something else going on inside. So the best way to clear this confusion is to have a look into the ASP.NET Core codebase in github. The core logic for loading the Startup class is implemented in StartupLoader class as shown below.

image

Note, the last parameter environmentName. Does this ring a bell ? “ConfigureProduction”… Production…Environment.

Let’s drill down further. Let’s concentrate on the FindConfigureDelegate method which is used to identify the Configure method of the Startup class. This method in turn invokes “FindMethod” and we need to get into the logic of “FindMethod” to understand this better.

image

The code snippet of FindMethod is shown below.

image

The steps in selecting the right method are:

a) Look for method with name Configure{EnvironmentName}. If found, then check for overloads.In case there are overloads then throw InvalidOperationException.

b) If there are no method with name Configure{EnvironmentName} , then look for method with name Configure.If found, then check for overloads.In case there are overloads then throw InvalidOperationException.

c) If there are no methods found with name Configure{EnvironmentName} or Configure then throw InvalidOperationException.

Step c) above explains the exception message we started with “Unhandled Exception: System.InvalidOperationException: A public method named ‘ConfigureProduction’ or ‘Configure’ could not be found in the ‘startuptest.Startup’ type.

The only missing piece in the puzzle is now the environment name. ASP.NET Core environment name is stored in the environment variable “ASPNETCORE_ENVIRONMENT”. The runtime reads from this variable and sets the IHostingEnvironment.EnvironmentName property. The framework supported values for this variable are “Development” , “Staging” and “Production” , however it can accept other values as well.

We can set this variable from the command line as

set ASPNETCORE_ENVIRONMENT=Development2

Now running the code without any Configure method in the Startup class will lead to the following exception message.

Unhandled Exception: System.InvalidOperationException: A public method named ‘ConfigureDevelopment2‘ or ‘Configure’ could not be found in the ‘startuptest.Startup’ type.

In the last post we have discussed on how the ASP.NET Core request processing pipeline works. As a next step, let’s take a closer look into how the ASP.NET Core application gets started and initialized.When we create a new ASP.NET Core application e.g. say a MVC application, we can see two files which gets added by default, Program.cs and Startup.cs as shown in the figure below:

image

The Program and the Startup class control startup and the configuration of the application runtime. The ASP.NET core application is just a console application and like any other.NET console application and needs a Main method as the entry point of the application.

The Program class contains the implementation of this static void Main method which is used to create an instance of IWebHost and run the same. IWebHost is one of the key components of the application which contains the application configuration and the ASP.NET Core Web server.

The Main method performs the initialization of the IWebHost instance and starts it as shown in the figure below:

image

The IWebHostBuilder is used to configure the ASP.NET Core Development Server (default is Kestrel) , Logging , IIS Integration (if required) , Content Root etc.We will take a deeper look into the IWebHost / IWebHostBuilder later.

Now let’s take a look into the Startup class which gets wired into the IWebHost instance as highlighted below:

image

UseStartup is a generic extension method on IWebHostBuilder as shown below. But the interesting point to be noted here is the generic type parameter has no constraints TStartup can be any class.

image

This is quite interesting as I am more used to having an interface driven strongly typed parameters in this kind of situations. It’s quite obvious that this Startup class needs to work in tandem with the IWebHost based on certain conventions. Now let’s take a look at the code that is in the Startup class by default.

image

a) The Configure method is a must have for the Startup class. This is invoked by the runtime host, which creates an instance of IApplicationBuilder and passes it as an agrument.This IApplicationBuilder is used to configure the middleware pipeline by adding suitable components. The other parameter IHostingEnvironment can be omitted if not required. We will get into further details of the IApplicationBuilder interface while exploring the ASP.NET Core middleware pipeline.

b) The ConfigureServices method is optional.This can be implemented to add additional services to the IServiceCollection.We will get into further details of the IServiceCollection interface while exploring the ASP.NET Core Dependency Injection.

Now comes the question, is it a good design, making the startup class work by convention rather than having any strongly typed interface. I think it’s fine. It helps to keep things simple. This is the startup code so we can take up the additional overhead of reflection in inspecting the method definitions and then invoking it. Also, the chances of type mismatch or method mismatch is not there because its the startup code used to configure and initialize the application and should not have a widely varying behavior at runtime. This is also more flexible as we can different other parameters in the methods to suit our needs.

Next comes the question why we have two classes for the application initialization, Program and Startup? The segregation of responsibilities is very clear, the Program class contains initialization code that is used to set up the infrastructure that will rarely change over the lifetime of the project (like ASP.NET Core Web Server, Logging etc.) whereas Startup contains the initialization of features that are required to customize the application’s behavior.

ASP.NET Web Forms were launched as part of .NET Framework 1.0 in 2002. It was a logical evolution from ASP, moving away from interpreted web pages with dependency on a scripting engine, towards type safe and compiled web pages model with more well structured code. ASP.NET Web Forms offered developers with a event based programming model, which helped to create web applications quickly. But over time, we found certain limitations of this framework in developing and maintaining large web applications.This was mostly due to lesser control on the generated HTML , poor testability and an artificial/complex stateful model as opposed to the stateless nature of the web.

ASP.NET MVC was released around 2009 which was based on the Model-View-Controller architectural pattern leading to clean separation of concerns, improved testability and more tighter control on HTML. This was more in line with other popular frameworks of the time like Ruby-On-Rails etc.

However , both ASP.NET Web Forms and ASP.NET MVC were built on the same underlying framework and relied heavily on features provided by System.Web.dll. This assembly is a part of the .NET Framework and explicitly coupled with Windows Web Server i.e. Internet Information Services., IIS. Also, the heavy dependency on this assembly made changes to ASP.NET complex and release cycles slow.

The key goals of ASP.NET Core was to make the framework cross platform and the overall architecture more modular. So, clean separation of the web server from the web application was key. The figure below shows the key components of the ASP.NET Core request processing pipeline and how this separation is achieved.

image Every ASP.NET Core application runs within an in-process HTTP Server implementation. This HTTP Server receives the raw HTTP request and converts it to an internal representation by creating a HttpContext object. This object is then used by the web application for further processing.Kestrel is a cross platform web server built on libuv , asynchronous request processing library. This is the default HTTP Server implementation for all ASP.NET Core applications.

Kestrel is a very basic HTTP server and does not have advanced features like

  • Windows Authentication
  • Port sharing
  • Http Access Logs
  • Process Activation
  • Response Caching etc.

This is why its recommended to use the ASP.NET Core Web Server with a reverse proxy. A reverse proxy is a web server exposed directly to the Internet and responsible for forwarding the requests to the appropriate web servers serving the requests. A web server like IIS , Nginx or Apache can be easily configured as a reverse proxy working in conjunction with the ASP.NET Core Web Server.

This model of having a separate reverse proxy and a web server might sound bit cumbersome. But this helps in making the web application framework independent of the operating system and web servers like IIS, Nginx or Apache. This results in a clean separation of concerns with a lightweight HTTP server handling requests / generating responses while the reverse proxy doing rest of the heavy lifting like security related hardening , application start-up etc.

An ASP.NET Core web application cannot be directly hosted in IIS / Nginx / Apache without a server like Kestrel or any custom ASP.NET Core Http Server implementation. This is because ASP.NET Core is designed to run independent of this servers, ASP.NET Core is not meant to adapt to these servers but these servers needs to be configured to act as a reverse proxy and forward request to the ASP.NET Core Web Server.

IIS works as a reverse proxy , forwarding requests to ASP.NET Core using the ASP.NET Core Module ( ANCM). This is a native IIS module which hooks in the request pipeline ,activates the ASP.NET Core process and forwards the request to the ASP.NET Core Web Server. The IIS worker process ( w3wp.exe) and ASP.NET Core runs as two separate processes , ANCM is responsible for restarting in case the ASP.NET Core application crashes.

There is another option for ASP.NET Core Web Server, HTTP.sys.This is Windows only HTTP Server implementation based on HTTP.sys kernel mode driver. However it has some advanced built in features compared to Kestrel like support for Windows Authentication , Port sharing , response caching etc.HTTP.sys kernel driver is a very advanced technology and IIS itself runs on top of it. So this HTTP Server is protected against security attacks etc. and is suitable for running without a reverse proxy for internet facing applications. For intranet applications also this can be good choice given its support for Windows Authentication.

ASP.NET 4.5 has introduced model binding and strongly typed templates for ASP.NET server controls.This simplifies the way a plain .NET object can be bound as a datasource of a server control like a GridView.Let’s get started off with a simple example of how model binding works.

(more…)

This week I came across a problem related to structuring an ASP.NET MVC Web application one development team was facing. What they were trying to do was quite simple: to create a folder structure each having their own subfolders for View/Controller/Scripts/CSS etc. The application resources like JS/CSS etc. were not getting rendered properly. The issue was due to Web.config file lying under the subfolder, which when moved to the Views folder under that subfolder things went fine. The purpose of this post is not to discuss about the details of that problem and it’s solution.But to discuss about how we can easily structure our ASP.NET MVC Web application as per different modules, which is an obvious need for any large application.

ASP.NET MVC follows the paradigm of “Convention Over Configuration” and default folder structure and naming conventions works fine for a smaller application. But for relatively bigger one there is a need to customize.The framework also provides enough provisions for the same.You can have your own controller factory to have custom ways to creating the controller classes and custom view engine for locating the rendering the views. But if the requirement is to structure the application to different subfolders as per modules or subsites  I think the use of “Area” in ASP.NET MVC will be helpful to create a streamlined application.

You can add an Area to a ASP.NET MVC project in VS as shown below.

area1

area2

Here I have added an area named “Sales”. As shown in the figure below a folder named “Areas” is created with a subfolder “Sales”. Under “Sales” we can see the following

  • The standard folder of Models/Views/Controllers
    • A Web.config under the Views folder. This contains the necessary entries for the RazorViewEngine to function properly
  • A class named SalesAreaRegistration.

area3

The code (auto generated) for the SalesAreaRegistration class is shown below:

public class SalesAreaRegistration : AreaRegistration 
{ 
    public override string AreaName 
    { 
        get 
        { 
            return "Sales"; 
        } 
    }

    public override void RegisterArea(AreaRegistrationContext context) 
    { 
        context.MapRoute( 
            "Sales_default", 
            "Sales/{controller}/{action}/{id}", 
            new { action = "Index", id = UrlParameter.Optional } 
        ); 
    } 
} 

System.Web.Mvc.AreaRegistration is the abstract base class use registering the areas into the ASP.NET MVC Web Application. The method void RegisterArea(AreaRegistrationContext context) needs to be overriden to register the area by providing the route mappings. The class System.Web.Mvc.AreaRegistrationContext encapsulates the necessary information (like Routes) required to register the area.

In Global.asax.cs Application_Start event we need to RegisterAllAreas() method as shown below:

AreaRegistration.RegisterAllAreas();  

The RegisterAllAreas method looks for all types deriving from AreaRegistration and invokes their RegisterArea method to register the Areas.

Now with the necessary infrastructure code in place I have added a HomeController and Index page for the “Sales” area as shown below.

 

area4

Now I am trying to run the application and got the following error: [NOTE: This has nothing to do with areas but because I have two controllers with same type name i.e. HomeController]

Multiple types were found that match the controller named ‘Home’. This can happen if the route that services this request (‘{controller}/{action}/{id}’) does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the ‘MapRoute’ method that takes a ‘namespaces’ parameter.

The request for ‘Home’ has found the following matching controllers:

AreasDemo.Controllers.HomeController

AreasDemo.Areas.Sales.Controllers.HomeController

I have to change the Route Registration for the HomeController to avoid conflicts and provide the namespace information as shown below:

public static void RegisterRoutes(RouteCollection routes) 
{ 
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute( 
                "Default", // Route name 
                "{controller}/{action}/{id}", // URL with parameters 
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },// Parameter defaults 
                new String[] { "AreasDemo.Controllers" } 
            ); 
}

Now I will add a link to the Sales area by modifying the _Layout.cshtml as shown below:

 
<li>@Html.ActionLink("Sales", "Index", "Home", new { area="Sales"},null)</li>

Here I am navigating to the area “Sales” from the main application so I have to provide area information with routeValues. The following overload is being used in the code above:

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes);

For navigating within the “Sales” area however routeValues will not be required.

ASP.NET MVC 4 (right now in Beta) has introduced the ASP.NET Web API , a MVC compliant framework for developing and hosting HTTP services which can be accessed from a variety of clients.In this post we will take how the ASP.NET Web API request processing pipeline works and HTTP request is passed between different processing stages. ASP.NET Web API can be hosted in IIS like a normal ASP.NET Web application and it can be also self hosted within a simple console application.For the sake of simplicity we will use a self hosted application here.

(more…)