4

I'm trying to integrate the recently released ASP.NET Identity 2.0.0 into a 3-layer MVC application. I'm not sure I'm going in the correct direction. I can see two approaches to take.

In the first approach, I've gone with integrating Identity into each logical layer. Having some technical issues integrating but still developing.

In the second approach, go with a a self-contained encapsulated assembly dedicated for security.

I've gone with approach 1 at the moment, but questioning it all. Also, any other approaches to take?


Approach 1

Web
Startup.cs
/App_Start/Startup.Auth
/Controllers/Account
/Controllers/Manage
/Controllers/RolesAdmin
/Controllers/UserAdmin
/ViewModels
/Views

Business Logic
/Service/AccountService
/Service/ApplicationRoleManager
/Service/ApplicationUserManager
/Service/EmailService
/Service/SmsService
/Service/SignInHelper

Data
ApplicationDbContext
ApplicationUser

So, I've simply taken Identity and plugged it into each layer I see that fits. I've put most of the log in the Business Logic layer, as it doesn't belong in the Web and there no 'real' database code for it to belong in the Data layer.

Side-issue: I'm a bit uncomfortable that in the Web/App_Start/Startup.Auth, I have to instantiate the Busness Logic object to call

app.CreatePerOwinContext(ApplicationDbContext.Create);

in the Data layer. I've yet to think about this more. This is another issue (but I see it is related to the architecture I've chosen).


Approach 2

Creating an assembly purely for Security which contains no layers, i.e. simply plug in Identity 2.0.0 into this one assembly. And my application can reference this. It goes against the layers though. But it encapsulates security. Given security objects can (or should) be resident throughout the application lifetime, this doesn't seem like a bad idea at all. Haven't thought about about scalability though.

OpcodePete
  • 887
  • 1
  • 14
  • 28

1 Answers1

3

I have taken approach 1, and when creating the context I have a helper class that I attempt to get the context from HttpContext.Current.["DbActiveContext"] and use it if it exists, if not create then new one, and use a single context for the entire application. So you do not end up with one context for aspnet idenity and another one for the rest of the app. It looks like you are trying to use a repository pattern in the first approach, if that is the case, then your model for your identity should be in the DB layer, and for full repository pattern, you should be using dependency injection when creating your objects, by doing so, you will not have a dependency until the object is created at run time.

namespace Data.Common
{
    public class ConnectionHelper : IConnectionHelper
    {
        private ApplicationDbContext _context;

        public ApplicationDbContext Context
        {
            get
            {
                 if (_context == null && HttpContext.Current.Items["DbActiveContext"] != null)
                {
                    _context = (ApplicationDbContext)HttpContext.Current.Items["DbActiveContext"];
                }
                else if (_context == null && HttpContext.Current.Items["DbActiveContext"] == null)
                {
                    _context = new ApplicationDbContext();
                    HttpContext.Current.Items.Add("DbActiveContext", _context);
                }
                return _context;
            }
            set { _context = value; }
        }
    }
}

Also if you want to use the usermanager in the service layer with DI you can do something like:

 public UserController()
         : this(
             new ApplicationUserManager(new UserStore<ApplicationUser>(new ConnectionHelper().Context)),
             new UserService())
    {

    }

With the UserService signature like:

public class UserService
{
    private readonly IRepository<ApplicationUser> _user;
    private readonly UserManager<ApplicationUser> _userManager;

    public UserService(IRepository<ApplicationUser> user,
        UserManager<ApplicationUser> userManager)
    {
        _user = user;
        _userManager = userManager;

    }

    public UserService()
        : this(
            new Repository<ApplicationUser>(new ConnectionHelper()),
            new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new   ConnectionHelper().Context)))
    {

    }

I hope this helps you!

Kelso Sharp
  • 972
  • 8
  • 12
  • Hi Kelso, this is a great answer. But for someone like me learning MVC and Identity 2.0 (and still getting my head around it), it raises a bunch more questions. Would you have a sample public project with such code? That would help so much. – OpcodePete May 27 '14 at 07:28
  • I don't have a project that would be very helpful in terms of learning Identity 2.0, but if there are questions you have I am more than happy to help. – Kelso Sharp May 28 '14 at 18:24
  • Will keep you posted :) Reviewing Enterprise Design Patterns at the moment, and will soon attempt to implement Identity 2.0 in the layers (i.e. approach 1). Your answer above has helped alot. – OpcodePete May 29 '14 at 03:48
  • @ThomasVeil I'm also stuck with the same issue. Do you have any working example of this? – Dipen Dedania Jan 24 '17 at 04:36
  • 1
    @DipenDedania Sorry no example available at the moment as I haven't touched this code in almost 3 years. But I can definitely say I went with approach 1 where I integrated ASP.NET Identity in each layer. One or two things didn't fit in cleanly in the layers. But I intend to re-visit this later this year and will publish what I've done. – OpcodePete Jan 24 '17 at 22:58
  • @ThomasVeil Thanks! – Dipen Dedania Jan 25 '17 at 05:19
  • Something that I remember that might help, is that in windows 8 and 8.1 HttpContext.Current is always null, I am not sure if this was intentional or if it was a bug, But it was only an issue with windows 8 as far as I am aware – Kelso Sharp Jan 26 '17 at 18:40