0

I'm trying to create a reusable base for future web applications made with asp net core. I created a library that contains a BaseDbContext that inherit from IdentityDbContext:

public class BaseDbContext : IdentityDbContext<ApplicationUser>
    {
        public BaseDbContext(DbContextOptions options) : base(options)
        {

        }   
    }

Inside this library there are some services for login and creation of Users.

Everytime that I will be creating a new WebApplication I will reference the library and I will create a new DbContext like this:

public class ProjectDbContext : BaseDbContext
{
    //some generics DBSET
    public ProjectDbContext (DbContextOptions<ProjectDbContext> options) : base(options)
    {
    }
}

And in the startup:

    services.AddDbContext<ProjectDbContext>(options =>
    {
        options.UseSqlServer(connection);
    });

Since the service for the login and creation of users require a reference of BaseDbContext, I created a IDbContextFactory inside the base project that will be implemented by the main project like this:

public class ProjectContextFactory : IDbContextFactory
{
    private readonly ProjectDbContext _projectDbContext;

    public ProjectDbContextFactory(ProjectDbContext remDbContext)
    {
        _remDbContext = remDbContext;
    }

    public BaseDbContext GetBaseDbContext()
    {
        return _projectDbContext;
    }
}

This factory will be used inside the base project to get a reference to the BaseDbContext.

Is this a good thing to do? Can this create some kind of problems?

Davide Quaglio
  • 751
  • 2
  • 11
  • 31
  • You don't need to add both contexts. By adding the ProjectDbContext, you automatically have added the BaseDbContext since you used inheritance. So just use the one DbContext – Steven Lemmens Sep 09 '19 at 13:24
  • Why register `BaseContext` in the DI container though? – DavidG Sep 09 '19 at 13:24
  • Oh yes sorry, missing a point.. One sec I'll modify the base question adding the info. SImply, there is a Service in the same project as BaseDbContext that use BaseDbContext – Davide Quaglio Sep 09 '19 at 13:25
  • Give a try with ScaffoldDBContext command https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding MS EF Core will automatically generate the class and model files – Vishal Sep 09 '19 at 13:39

1 Answers1

1

In general, no, this is not a good thing to do.

that will contains the entities that will be used for all web applications

If there's entities that are common to all projects, then those should be factored out completely. In other words, you'd have one project (your base project) with a context like UserContext, which will have your User and Credential entities, and then every other project would have its own separate context that deals with just what it needs. If the other application(s) need to access users, they'd either do so via an instance of UserContext or, better, through a service, such as an API.

That said, it sounds like you're rolling your own auth, which you should emphatically not do. Use Identity. And, if you need to share that between applications, you need a centralized auth provider, such as Identity Server.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Hi, thanks for the reply. Right now I'm using angular as Client and using Jwt Tokens for claims and authentication. Identity require, if I'm not mistaken, cookies to work and that is something that I didn't want to use. Also, I don't need to share credentials between different applications, but only share the logic, what I'm trying to achieve is a Template for every project that I need to create. Also I approve your first point of having a different context for the entities shared and using services to access them – Davide Quaglio Sep 09 '19 at 13:55
  • Identity can support virtually any authentication type. The only exception is OAuth/OIDC, simply because it doesn't have built in views and handlers for that out of the box. That's where something like Identity Server would come in. – Chris Pratt Sep 09 '19 at 13:58
  • I used inheritance because I wanted to be able to call one time "add-migration" and other commands for creating the Migrations – Davide Quaglio Sep 09 '19 at 14:00
  • You won't be able to do that. Each project would end up with its own copy of `User` and `Credential` tables, in addition to their own entities. So, each project would have to be migrated individually. Use a separate context as I recommended would allow you to migrate the user stuff just once, though, but then each project would be using the same data for that, which may or may not be what you're looking for. – Chris Pratt Sep 09 '19 at 14:04
  • Yeah every project would have a copy of them, if one day I were going to add a new field to user, I would like that this new field would be applied to every other project, the projects that will be using the new field will require a little tweak and the others will get the new field in the table, but it will never be used. Ohh, maybe you misunderstood something. The BaseProject has only the stuff for Credential and User, the other project, are each one for different customers(sport, medicine, etc) and each will have it's own db and server. I want only a template to start from for a new project – Davide Quaglio Sep 09 '19 at 14:11
  • 1
    That's even more reason to use Identity. It *is* your base. And, it's open-source, in use by tons of applications, and battle-hardened. Auth is hard to get right and easy to fail, and when you fail, it's a monumental cluster, since you're then normally exposing user data (including PII and other sensitive information). Especially, if this is going to be for paying clients, you better get this *right*, or get a damn good lawyer. – Chris Pratt Sep 09 '19 at 14:15
  • Ahaha that's ok, I'm not talking about Identity, since you already convinced me to start using it, but I was talking abount having the inheritance between the DbContexts. But just now I got why separating them is easier. I was only focused on the part that to update a single db instance for a single application, I had to run add-migration XXX without worrying about the changes made to the entities, I could care less if they were made on the BaseDbContext or in the DbContext, with one command I would get everything done. – Davide Quaglio Sep 09 '19 at 14:21
  • I Implemented everything and now I have a question. I have 2 Context, one with User, and the other with everything else, what is the best approach if I want to relate User with some other entity in the other DbContext? – Davide Quaglio Sep 11 '19 at 16:04
  • You can't, at least not in a traditional foreign key sense. Persist the user id as a column, and then use that user id to lookup the user from your context for that. – Chris Pratt Sep 11 '19 at 17:04
  • If I choose the inheritance path like in [this](https://stackoverflow.com/questions/19902756/asp-net-identity-dbcontext-confusion) post? – Davide Quaglio Sep 11 '19 at 18:19
  • If you mean making your application's context inherit from `IdentityDbContext`, then yes, you would be able to create true foreign key relationships with that. However, that's because all the entities would live in the same database with each other and be shared in the same context. It also means that you'd have a completely unique set of users for each application. If you need a shared set of users, you cannot do that. – Chris Pratt Sep 11 '19 at 18:21
  • No tha'ts exactly what I want. I changed the main thread with what I did to make it work. – Davide Quaglio Sep 11 '19 at 18:28