ASP.NET Identity and mapping Many to Many (Fluent API)

Asked

Viewed 1,043 times

4

I recently created a Solution with the DDD architecture, putting ASP.NET Identity in a transverse layer (CrossCutting), I saw that many people use Identity this way and decided to try it.

However, I had a circular reference problem. To create an Associative table (Many To Many) I need to create a Collection<> in the right entity, and one in the left entity, and create the Map in my EntityTypeConfiguration<>.

There’s the problem, as my project Identity is separate, and my Entity is in the project Domain so I can’t create a Collection<ApplicationUser> in my domain, since who has the reference of Domain is my project Identity.

Also remembering that I can not use interface because the Migration does not understand Interface.

Can someone help me with that?

  • 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/

  • Actually separating an MVC project is totally wrong, because MVC is a form of DDD.

  • You can edit your question and put the code with the namespaces?

  • 1

    Researching on the subject, I found this material. Quite interesting. http://www.jrobertoaraujo.net/2015/06/02/aplicando-crosscutting-ao-aspnet-identity/

  • @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.

  • 2

    @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.

Show 1 more comment

2 answers

6

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.

Webactivator, Unity Mvc and Microsoft.Web.Infrastructure

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.

0

From what I understand, you are working with two EF contexts in the same database. A context for Identity and another for the rest of the application.

I also use this approach, since the function of the Identity is to take care of Authentication and Authorization of users. I isolate the context of Identity and I restrict its use solely to that.

So if you need to relate the user to another entity and this entity has no relation to Authentication or User Authorization. You must create a class that represents your user in your project Domain without reference to the Identity. And map this table within the context that deals with the entire application. And in this context you can make the relationship of users with the other entity.

That is, you will have two different objects (one in the project Domain and another in the project Identity) which represent the same table in the database. If there is a change in this table, you will need to change the two objects. It will take more care with the maintenance of this project, but you solve the problem of dependence on Identity.

  • This is a dangerous solution, but I admit it works. It is not recommended to map two structures separately only to be able to count on a layer separation, whose usefulness is debatable.

  • Why should we break contexts by interests, isolate the context of Identity provides scale the same mechanism for different systems that use the same access medium. Breaking EF contexts is a widely recommended strategy. Quoting Eduardo Pires in a comment of the article: http://eduardopires.net.br/2015/02/customizando-names-tabelas-campos-asp-net-identity/

  • 3

    Eduardo Pires is the same person who makes a tutorial separating by layers and the people who follow come here to ask questions. Sorry, it’s not argument.

  • I study the tutorials and come here to help ask questions. But this is already another subject. The separation of the code in layers has its usefulness. Especially when we think not only in the construction of a system, but also in the maintenance of it.

  • Imagine an application made without any layer separation, which was created using EF for data access and all the controllers of the application instantiate the context directly. If one day the EF is discontinued and a better ORM appears, the programmer who has to evolve this system will have much more work to adapt this system to the new ORM. If you had done a layer separation by responsibility and used dependency injection, this work would be extremely focused on creating the new layer data access. It would have work too, but much more organized, focused and measurable.

  • Sorry again. I’ll disagree with you. The separation of the code no help at all to maintain an ASP.NET MVC application. This is an ancient practice of 3-layer architectures, where it was necessary to separate one domain from the application and make it visible to others. The EF is a complete repository: if you need to remove it, you can do it in one command only and install another of your preference that the alternative solution fits perfectly to the application. This is why we can say that MVC implements the DDD.

  • Ok. What about all the EF references you’ve added to your controllers? Going to change one by one in your hand?

  • If I didn’t know how to refactor code, yes. But I can extract an interface from DbContext and implement a repository based on, for example, Dapper. How about?

  • It’s already improved. Now if you need to use this repository that uses the interface you extracted from Dbcontext in other projects. How would you do? Ctrl+C + Ctrl+V?

  • What other projects? What is their function? Are they modules? Are they systems that access the first system? Your idea is to copy-and-paste a DLL into another system or consume the system information into another?

  • We are talking about repository. I need to use the same abstraction done in Dbcontext in another project so that my Controllers do not depend on EF.

  • It doesn’t make sense that you said it. If you want to use the abstraction of one project in another, serving the entire database is already wrong. There are various concepts and addictions that are used for 3-layer architectures, and that people simply implement without question. The correct thing would be for the MVC application to serve the data to the other application otherwise, either by a closed DLL, or by a REST API interface, and so on.

  • I’m just talking about the interfaces, not the classes that implement it.

  • Man, as long as the thought keeps plastering, there’s no way out of place. The MVC was made to eliminate prolixity and rework, which is precisely what a "well-meaning" proposal of layered separation tries to bring back. The tutorials I saw are 3 hours long. With this time it is possible to model, generate and test various aspects of a MVC system without worrying so much about interfaces and "responsible design". This same question is generated by an addiction of practice. If there was understanding of the new concepts, it would possibly not exist.

  • 1

    Actually, developing an application using a single project is much faster and works very well for small and low complexity projects. When working with larger and more complex applications, if we do not think about a "responsible design" we can have big headaches in the future. As I’ve seen happen in some of the companies I’ve worked for.

Show 10 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.