Introduction
We know that in ASP.NET 5 the whole framework is rewritten. ASP.NET 5 is not dependent on the old bulky System.Web.dll. That means it’s independent from a particular hosting environment. Now (ASP.NET 5) the framework became very lean and pluggable. So what does it mean? It means, very limited features will ship with ASP.NET 5 and if the user needs more features they are able to easily plug in the framework. By default the MVC framework does not come with ASP.NET 5, if we want to use MVC we have to plug the MVC service on top of ASP.NET 5. The mechanism is very simple, you just have to add a couple of lines in Startup.cs and in the project.json file. If you open any scaffolding Startup.cs file, it will contains two methods and those are ConfigureService
and the Configure
method.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
We can call AddMvc()
and the UseMvc()
extension method from ConfigureService
and the Configure
function to hook MVC in application. In this article, we will dig deeper into the AddMvc()
function and discuss the MvcServiceCollectionExtensions
class which contains AddMvc()
and a few useful methods to hook and configure MVC in ASP.NET 5 applications.
The location of the MvcServiceCollectionExtensions
class is in the Microsoft.Framework.DependencyInjection
namespace
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcServiceCollectionExtensions
{
}
}
And the class contains following methods.
Where AddMvcServices()
and ConfigureDefaultServices()
are internal and provate simultaneously. If you just open the class in Visual Studio then you may not see those functions by default but it will visible to some de-assembler tool. Now we have seen that we used the AddMvc()
function to add MVC services in ASP.NET applications, let’s check the definition to the AddMvc()
function see know what really happens when we add the MVC framework in ASP.NET applications. Here is the definition of the AddMvc()
function.
public static IServiceCollection AddMvc(this [NotNull] IServiceCollection services)
{
ConfigureDefaultServices(services);
AddMvcServices(services);
return services;
}
We are seeing that, internally, the AddMvc()
extension method calls both ConfigureDefaultService()
and AddMvcServices()
functions which are internal and private function. So let’s check the definition of both functions. Here is the definition of the ConfigureDefaultServices()
function.
private static void ConfigureDefaultServices(IServiceCollection services)
{
OptionsServiceCollectionExtensions.AddOptions(services);
DataProtectionServiceCollectionExtensions.AddDataProtection(services);
RoutingServices.AddRouting(services);
CorsServiceCollectionExtensions.AddCors(services);
ServiceCollectionExtensions.AddAuthorization(services);
EncoderServiceCollectionExtensions.AddWebEncoders(services);
OptionsServiceCollectionExtensions.Configure<RouteOptions>(services, routeOptions => routeOptions.get_ConstraintMap().Add("exists", typeof(KnownRouteValueConstraint)), 0, "");
}
We are seeing that in this function some default services like routing, CORS, Authorization of the MVC Framework are getting added in the application. Those are minimal services to up and run MVC application with limited features. Then it calls the AddServices()
function to add other MVC features, too. It contains tons of MVC features.
internal static void AddMvcServices(IServiceCollection services)
{
ServiceCollectionExtensions.AddTransient<IConfigureOptions<MvcOptions>, MvcOptionsSetup>(services);
ServiceCollectionExtensions.AddTransient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>(services);
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IAssemblyProvider, DefaultAssemblyProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<MvcMarkerService, MvcMarkerService>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ITypeActivatorCache, DefaultTypeActivatorCache>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>)));
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IControllerTypeProvider, DefaultControllerTypeProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IControllerModelBuilder, DefaultControllerModelBuilder>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IActionModelBuilder, DefaultActionModelBuilder>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IControllerFactory, DefaultControllerFactory>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IControllerActivator, DefaultControllerActivator>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IActionInvokerFactory, ActionInvokerFactory>());
ServiceCollectionExtensions.AddTransient<IActionConstraintProvider, DefaultActionConstraintProvider>(services);
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IActionSelectorDecisionTreeProvider, ActionSelectorDecisionTreeProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IActionSelector, DefaultActionSelector>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IControllerActionArgumentBinder, DefaultControllerActionArgumentBinder>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IObjectModelValidator>(serviceProvider => new DefaultObjectValidator(ServiceProviderExtensions.GetRequiredService<IOptions<MvcOptions>>(serviceProvider).get_Options().get_ValidationExcludeFilters(), ServiceProviderExtensions.GetRequiredService<IModelMetadataProvider>(serviceProvider))));
ServiceCollectionExtensions.AddTransient<IActionDescriptorProvider, ControllerActionDescriptorProvider>(services);
ServiceCollectionExtensions.AddTransient<IActionInvokerProvider, ControllerActionInvokerProvider>(services);
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IActionDescriptorsCollectionProvider, DefaultActionDescriptorsCollectionProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IGlobalFilterProvider, DefaultGlobalFilterProvider>());
ServiceCollectionExtensions.AddTransient<IFilterProvider, DefaultFilterProvider>(services);
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<FormatFilter, FormatFilter>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<CorsAuthorizationFilter, CorsAuthorizationFilter>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IModelMetadataProvider, DefaultModelMetadataProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<ICompositeMetadataDetailsProvider>(serviceProvider => new DefaultCompositeMetadataDetailsProvider(ServiceProviderExtensions.GetRequiredService<IOptions<MvcOptions>>(serviceProvider).get_Options().get_ModelMetadataDetailsProviders())));
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<JsonOutputFormatter>(serviceProvider => new JsonOutputFormatter(ServiceProviderExtensions.GetRequiredService<IOptions<MvcOptions>>(serviceProvider).get_Options().get_SerializerSettings())));
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped<ICompositeViewEngine, CompositeViewEngine>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IViewLocationCache, DefaultViewLocationCache>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ICodeTreeCache>(serviceProvider => new DefaultCodeTreeCache(ServiceProviderExtensions.GetRequiredService<IOptions<RazorViewEngineOptions>>(serviceProvider).get_Options().get_FileProvider())));
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IMvcRazorHost, MvcRazorHost>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ICompilerCache, CompilerCache>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ICompilationService, RoslynCompilationService>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IRazorCompilationService, RazorCompilationService>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped<IViewStartProvider, ViewStartProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IRazorViewFactory, RazorViewFactory>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IRazorPageActivator, RazorPageActivator>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped<IRazorPageFactory, VirtualPathRazorPageFactory>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IHtmlHelper, HtmlHelper>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)));
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IJsonHelper, JsonHelper>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped<IUrlHelper, UrlHelper>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ITagHelperActivator, DefaultTagHelperActivator>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IMemoryCache, MemoryCache>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IHtmlGenerator, DefaultHtmlGenerator>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IViewComponentSelector, DefaultViewComponentSelector>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IViewComponentActivator, DefaultViewComponentActivator>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IViewComponentDescriptorCollectionProvider, DefaultViewComponentDescriptorCollectionProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Transient<IViewComponentHelper, DefaultViewComponentHelper>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IClaimUidExtractor, DefaultClaimUidExtractor>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<AntiForgery, AntiForgery>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IAntiForgeryAdditionalDataProvider, DefaultAntiForgeryAdditionalDataProvider>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<IApiDescriptionGroupCollectionProvider, ApiDescriptionGroupCollectionProvider>());
ServiceCollectionExtensions.AddTransient<IApiDescriptionProvider, DefaultApiDescriptionProvider>(services);
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Scoped<ITempDataDictionary, TempDataDictionary>());
ServiceCollectionExtensions.TryAdd(services, ServiceDescriptor.Singleton<ITempDataProvider, SessionStateTempDataProvider>());
}
And the it returns the same instance of IServiceCollection
. So now it’s clear that when we call the AddMvc()
function are all MVC related features get added in the ASP.NET 5 application. Now the question may come, if we want to alter any MVC feature? The MvcServiceCollectionExtensions
Class contains the ConfigureMvc()
function where we can alter any MVC features which we have already added in the application. In this example, we will try to alter something in the view engine and will understand the functionality of ConfigureMvc()
function. Here is the modified ConfigureServices()
function where we are removing view engine by default in the ConfigureMvc()
section.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigureMvc(f =>
{
f.ViewEngines.RemoveAt(0);
});
}
Which means there is no view engine in the current application to process view. Now let’s perform one HTTP request to a certain controller and we will encounter the below error.
I believe and verified all routing stuff, controller and views and in place and the error is due to removing the view engine in the ConfigureMvc()
section. Now only alter the existing behavior in which you can register a custom filter and services in same section. Here are a few properties from many where we can alter the default behavior.
Conclusion
In this article, we have learned MVC setting and defaults MVC services in ASP.NET 5 application. Those setting and behavior is purely demand oriented and application specific. Please keep in mind that only Adding MVC services will not enable MVC in applications, we need to call the UseMvc()
extension method in Configure()
.