First of all, I would like to say that I needed to study this solution during the interval weeks in which the question was asked and now and quite some time later, because I really had no knowledge of how to do it, and even after I wrote the first version of the answer many things were incorrect and inaccurate. I insist so much on it to exemplify how far an anti-standard can go, in the name of the so-called good architectural practices in ASP.NET systems.
The first solution is not mine. It was elaborated brilliantly by José Roberto Araújo in link passed by Gustavo H. Pereira Silva. Without that, that answer would not be possible.
The original repository of the solution was this, but the author erased it. I made a Fork to study (this one still exists), I made some modifications, updated the packages and made tests to understand the things that, until at least last month, for me were magical and that surprised me a lot. Possibly I will update this answer a few times because a lot is not well documented and the learning turned out to be by empiricism.
A separation demonstration using Cross-cutting, Ioc and DI of ASP.NET Identity from the rest of the MVC Application (and why it doesn’t work)
Strictly speaking, this project is not exactly and totally decoupled from Class Library of the Infrastructure. This can be noticed when opening one of the Views using ASP.NET Identity:
~/Views/Account/Login.cshtml
@model WebAppSoC.Infrastructure.Crosscutting.Security.Model.Account.LoginViewModel
...
The correct thing here would be to have an interface to the View, and not the exposure of Viewmodel in itself, but it’s ok for our example.
All the magic starts with these three components. Webactivator is the input port for dependency injection itself, allowing the developer to configure how many classes of Startup
prefer to register the external components that may be used in dependency injection.
Unity MVC is the component that performs de facto dependency injection into the application. At the time I wrote the first version of the answer, I found that MVC components like Controllers, Models, and even Views were magically injected from Class Library for the ASP.NET MVC application. Actually, when registering Container of Unity MVC in the application, the application does not map alone the Controllers injected into the respective configuration routes of the original project. Note that the file that activates Unity MVC does not say any information regarding routes:
Webappidentitydemo/Jra.Infrastructure/Crosscutting/Dependency/Startup/Unitymvcactivator.Cs
using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Jra.Infrastructure.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Jra.Infrastructure.App_Start.UnityWebActivator), "Shutdown")]
namespace Jra.Infrastructure.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
}
This is where Microsoft.Web.Infrastructure comes in: there’s not much information about it, but the package description in Nuget says:
This package contains the Microsoft.Web.Infrastructure Assembly that Lets you dynamically Register HTTP modules at run time.
And here’s the secret: it’s this package that makes you Class Libraries be registered in ASP.NET MVC applications. The implemented standard is similar to Common Service Locator, but without creating dependency on the latter.
Note that there is no additional route log. The route file proves this:
~/App_Start/RouteConfig.cs
namespace WebAppIdentityDemo
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
The archive Global.asax.cs
also:
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace WebAppIdentityDemo
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
The archive packages.config
of the Web project attests to the total independence of the ASP.NET Identity Web project:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Antlr" version="3.5.0.2" targetFramework="net45" />
<package id="bootstrap" version="3.3.5" targetFramework="net45" />
<package id="jQuery" version="2.1.4" targetFramework="net45" />
<package id="jQuery.Validation" version="1.14.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net45" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Modernizr" version="2.8.3" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="Respond" version="1.4.2" targetFramework="net45" />
<package id="WebGrease" version="1.6.0" targetFramework="net45" />
</packages>
The most attentive developer will notice that the file packages.config
of the main solution does not have the following inputs:
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
That’s because every class you inherit System.Web.Mvc.Controller
is perceived by the route controller. This is the secret of packages like, for example, the Razorgenerator.Mvc (Packages.config here). Razorgenerator allows the developer to write Class Libraries containing Controllers and Views and can be incorporated into other ASP.NET MVC applications in the same way.
In all, there are only two mentions of Class Library Infrastructure in the Web Project:
- The reference to Class Library;
- The activation of Container in
Startup.cs
from the root directory.
This activation is done as follows:
using Microsoft.Owin;
using Owin;
using WebAppSoC.Infrastructure.Crosscutting.Security.Startup;
[assembly: OwinStartup("StartupConfiguration", typeof(WebAppIdentityDemo.Startup))]
namespace WebAppIdentityDemo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
new IdentityStartup().Configuration(app);
}
}
}
Why did I show you all this
The idea is to show that separation is possible, but not 100% independent. There is still a degree of coupling that cannot be eliminated.
About the question
The separation is simply illogical. ASP.NET Identity is strongly coupled to the Entity Framework in template pattern (using the package Microsoft.AspNet.Identity.Entityframework). It’s done this way because the idea is that (Models application) can be customized to incorporate more information into, for example, the user structure, roles, Claims, and so on.
Still, if separation is essential, the developer must incorporate, in the same layer, Entity Framework and ASP.NET Identity, or implement its own Userstore and Pulley, components necessary for the functioning of ASP.NET Identity without relying on the Entity Framework, which is a pretty useless idea without a good reason for it.
Completion
Do not use Cross-cutting. In this scope of application, it has no use. It only hinders your work and does not provide any gain for your application.
Hello, Follow ASP.NET MVC tutorial link with Identity and Pendenciaria injection. http://eduardopires.net.br/2014/10/tutorial-asp-net-mvc-5-ddd-ef-automapper-ioc-dicas-e-truques/
– Luã Govinda Mendes Souza
Actually separating an MVC project is totally wrong, because MVC is a form of DDD.
– Leonel Sanches da Silva
You can edit your question and put the code with the
namespaces
?– Leonel Sanches da Silva
Researching on the subject, I found this material. Quite interesting. http://www.jrobertoaraujo.net/2015/06/02/aplicando-crosscutting-ao-aspnet-identity/
– user27881
@Luãgovindamendessouza thanks for the mentions. There are two thoughts, one is layering to get various benefits, maintenance, testing, very large teams splitting code, domain exposure via services, N systems, etc... Another is to say that MVC solves everything, well, if the system is a schedule of contacts or something very simple ok. We should not kill ants with cannon balls. Before deciding your architecture analyze your need. About MVC being a form of DDD and or MVC being enough to develop a complex corporate system, sorry, it doesn’t exist.
– Eduardo Pires
@Eduardopires In the new versions of Sharepoint, the architecture is entire in ASP.NET MVC. Umbraco, CMS is also in ASP.NET MVC. A reasonable layer separation uses Ioc, Unity and DI. Another thing is to propose a separation using DDD and people actually think it’s the best standard when it’s not. In my view, it’s an anti-standard.
– Leonel Sanches da Silva