I'm fairly new to the Entity Framework, and am working on a project that is making use of the Entity Framework 6, Identity 2, Web Api 2 and MVC 5.
In the initial workings of the project, I have created a BusinessConnectionsContext to represent the build of my business models. I left the ApplicationDbContext that gets created automatically to its own devices, up until now. I'm mostly focusing on Web Api 2.
In my solution, I have an assembly for my models, which includes the BusinessConnectionsContext and ApplicationDbContext, an assembly for the Web Api, and an assembly for the Web, using MVC5. Both the WebApi and Web assemblies will make use of the Models assembly.
I've come to a point where I need to link ApplicationDbContext users with the BusinessConnectionsContext, but I can't find any information about this. I get the feeling I'm, perhaps, doing it wrong.
Should all the models in the BusinessConnectionsContext be relocated into the ApplicationDbContext?
It seems a fairly hefty move. What would typically happen if you had otherwise unrelated contexts requiring links into identity in the one system?
The short answer is all the models should be located in the one context. Either stick with the ApplicationDbContext that is created by default, or make your own. So far, I've not seen anything that deals with an Identity model that might be shared between two contexts, and I don't expect that transactions would extend across multiple contexts either.
As for what happens when you have otherwise unrelated contexts requiring links into identity in the one system? I don't know. I could say that you also have the contexts and models in different name spaces, and only use one context at a time, especially when it comes to updates.
One thing, slightly unrelated to the question, was the issue of the ApplicationUserManager, a wrapper for IUserStore.
I had several projects using the one context, but because they all had different expectations of who was accessing the project (one for admin via web, one for users via web and another for special users via webapi), they all had their own ApplicationUserManager. At some point, I had decided to use Unity to make sure the one context was shared across all repositories and the unity of work. I also had to make sure this context was also used in the IOwinContext that was used by the ApplicationUserManager. Since I'm not an expert in such things, I wont go into detail here (I guess it would the answer for another question), but suffice to say, on the subject of context and identity shared between multiple projects, it's something to keep in mind.
Related
I have recently done some analysis of ASP.Net Boilerplate (https://aspnetboilerplate.com). I have noticed that the domain layer (MyProject.Core) has folders for the following (these are created by default):
Authorization
Confirguration
Editions
Features
Identity
Localization
MultiTenancy
etc
Why would you put all of this in the Domain Layer of an application? From what I can see; I believe most of this code should be found in the Application Layer (which could also be the service layer).
Good question, if you just look at the folder names. But I suppose you haven't investigated the source code in the folders much.
First of all, I don't say it's the best solution architecture. We are constantly improving it and we may have faults. Notice that our approach is a mix of best practices & pragmatic approach. I will try to explain it briefly.
You are talking about this project: https://github.com/aspnetboilerplate/module-zero-core-template/tree/master/aspnet-core/src/AbpCompanyName.AbpProjectName.Core So, let's investigate the folders:
Localization
It does not include any localization logic (it's done in framework level, in ABP. Thus, it's in infrastructure layer). It just defines localization texts.
While normally it can be easily moved to web layer (no direct dependency in Core project), we put it in the Core layer since we think it may be needed in another application too. Think that you have a Windows Service has only Reference to the .Core project and want to use localization texts, say to send email to a user in his own language. Notice that Windows Service should not have a reference to Web layer normally. So, we have a pragmatic approach here. We could add localization to another dll project, but that would make the solution more complicated.
Authorization
Mainly includes User, Role.. entities and UserManager and RoleManager domain classes. Similar to localization, it does not include actual authorization logic. It also includes some other classes but they do not make much. We thought putting these here would help us if we have more application layers. As you know every application can have it's own application layer as a best practice.
Confirguration
AppConfigurations is here to share 'configuration reading' code between different apps (Migrator and Web app). Again, this could be inside another "Shared Utils" library. But we wanted to keep solution structure balanced, so it reflects major layer and structures yet is not so complicated for intermediate level developers.
Editions
Just includes EditionManager class which is a domain service for Edition management.
Features
Just includes FeatureValueStore which is a repository-like adapter class. See it's code, it's already empty.
MultiTenancy
Includes Tenant entity and TenantManager class which are already parts of domain layer. Again, nothing here includes infrastructure-related multi-tenancy features (like data filtering or determining current tenant).
... and so on...
So, do not just see names and have idea, please check the project deeper. Some code can be moved to upper layers or an utils library, but I think general structure is good to start a DDD architected application.
What you see it is called Module Zero, it aims to implements all fundamental concepts of ASP.NET Boilerplate framework such as tenant management (multi-tenancy), role management, user management, session, authorization (permission management), setting management, language management, audit logging and so on.
Module-Zero defines entities and implements domain logic (domain layer) because it is part of the configuration context of your system.
I just spent some time resolving the strangest bug, and I can't figure out why it happened. Maybe someone can follow along and shed some light on why...?
tl;dr: lightweight MembershipContext fails due to some completely unrelated object not having and ID field, but only does so when running under MVC: all integration tests that make sure this stuff works correctly... they work correctly.
What I Have:
I have a solution with a number of projects. The pertinent ones are:
LPA.Domain (contains POCOs for business objects/behavior)
LPA.Data (contains EF6 stuff with FluentAPI config and references LPA.Domain)
LPA.Web (contains an MVC project, refs Data and Domain)
This is a very normal setup for us and the project has been in development for some time with no issues.
Within the Data project I have two DbContexts that are used. One, MembershipContext is used only during login and bypasses the user-based audit system to validate the user. The MembershipContext has only three entities: User, UserMembershipDetail and UserRole.
The second, CoreContext has all the normal stuff (including tracking the currently logged in user ID for audit purposes). This has many entities.
What I Did:
Now let's pretend I spend a few days doing some domain-level development. I add handful of classes, set up their db counterparts, build the models (in CoreContext, MembershipContext doesn't change), write integration tests for the models and unit tests for the domain work. All is well. I haven't touched MembershipContext at all.
Part of what I did was add a new class to LPA.Domain to deal with an object called Matter (legal matter). This was to mock up a single method I needed elsewhere, but was not set up in the db (yet). I added an Ignore() on the appropriate entity and will flesh it out later. No biggie, right? All still happening in the CoreContext
What Happened:
I get done with a few days of domain-level development, then go to fire up the LPA.Web project and hit a strange error when trying to log in. Some digging around tells me basically this:
When trying to get from Users in MembershipContext, it's throwing an exception saying that the LPA.Data.Matter EntityType has no key.
A couple confusing things about this:
LPA.Data.Matter is not an object. The Matter object resides in the LPA.Domain.Legal namespace. Presumably this is an internal thing with EF6 as it creates it's own object to deal with things. Ok, I can buy that...
MembershipContext makes no use of Matter at all. The three objects it does make use of have no downstream references (shallow or deep) to the Matter object.
Integration Testing to build/retrieve the MembershipContext.Users works fine! (Users being the offending Entity in the exception) I think this must indicate some different method between how the LPA.Web project is loading the LPA.Data.MembershipContext as opposed to how the test project is, but that doesn't make much sense to me...
This Matter object is used in testing for the domain project and the LPA.Data.CoreContext tests without issue, why does it fail on the Membership and only when using it through an MVC project?
How I Fixed It:
As noted, I added the Matter class as a quick helper on the domain but hadn't fleshed out the storage stuff yet. As such, I had no ID field on the object. The resolution was as simple as adding an ID field.
This resolves the problem, but does not in any way help me understand what went wrong.
For what it's worth, in the MVC project we use a custom user and role provider based on the ExtendedMembershipProvider, which uses a custom repository (that in turn uses the MembershipContext). The instantiation of the MembershipContext is identical between the test and the MVC projects. I can't imagine why they'd act differently.
It's as if something in the MVC project is forcing EF6 to read/validate every object in the Domain class to ensure their validity to a non-existing data model.
Does anyone have the slightest idea why this happened? I'm baffled, myself.
We are developing multiple applications for the same company.
The applications are distinct (so not suitable for a multi-tennant app) but there will be lots of shared models, a couple of shared controllers and ideally some shared views.
It is the first time I have had to do this, and wonder if I am approaching it correctly. Here is my plan:
Create a DB for the shared stuff, and another (per application) for application specific stuff
Each application will have 2 connections in web config
Create a DLL from the shared models and controllers. Put this in the /bin directory and reference it in the project. I want this to approximate the way a nuget package might work, and reference the
For each app create a SharedApplicationDBContext and a LocalApplicationDBContext, each accessing the respective DB.
Questions
Are the above steps the right ones to be taking?
Is there any way to include cshtml Views in a DLL?
Is it ok to include the Users controller / models in the DLL?
Are there any gotchas I should be aware of when sharing code like this over mutliple apps?
I know SO likes specific questions, and this is a bit vague, but I'm a bit out of my depth here and looking for some general guidance as to the right approach to take.
You've got the general idea, but it needs some tweaking:
Don't fool around with DLLs. If the projects exist in the same solution, then you might as well keep your class library there as well. In which case, you can just do a straight project reference. If you're dealing with multiple solutions then you package your class library as a nuget package and actually install it in each project. Creating a nuget package is easy enough, and you can either install from a local/network path or you can set up your own private nuget repo. This makes it stupidly easy to share resources, and you get the ability to publish updates and see at a glance which projects are running which versions of your class library.
Each app should only have the context that relates to its individual database. The shared database can also use a shared context, which would be contained in your class library. You should also house all your migrations related to this shared context in the same class library.
You can include views in a class library, but not as cshtml. They have to be compiled into the class library. You'll need RazorGenerator to accomplish this.
It's 100% okay to include the models related to users in your shared library. However, the controller is trickier. Unless you set up an SSO server that will alone be responsible for handling all authentication (a non-trivial task to say the least), each application will need it's own controller for authentication tasks. If all of the sites will reside on the same domain or subdomains thereof, you can easily share the auth cookie between them. However, if they will reside on entirely different domains, you can still share the same "users", by virtue of using the same database for each, but each site will require a separate login process (logging in at one does not log you in at another, even though the same credentials would work for both). The only way around that is, again, SSO.
For what concerns the views, you can include them in a DLL, please read here
For the models it's ok to have them in a different project.
For the controllers you can do it but you must let MVC know where the controllers will be located and you can do it by writing a custom ControllerFactory, please read more here.
I've been working on a Web API solution that's separated on various projects, one of each is the API itself which contains the controllers and Views but all the Business Logic is done in all the other projects (being one of them responsible for all database iteration).
Now I want to apply Authentication using Identity which I wasn't familiar with but was able to understand a lot better thanks to this series of articles and so was able to get it to work on a test solution.
My question here is, how should I organize the different parts of the Identity implementation? Should I...
Make everything directly on the API project?
Create a separate project for all the Identity Implementation except for the controllers?
Use it some other way that you will suggest?
*If you suggest using different project, will I be able to pass the owin context between the projects? how?
I am using the latest Entity Framework with a code-first approach to create a data access assembly that can then be used by multiple projects. Many threads on stackoverflow seem to suggest creating one context per request in an MVC web app.
But I also want to use the same assembly from WinForms or console applications - what kind of approach should one use in regards to context instancing if it is to be shared between such different programs?
One context per logical operation as said by John Saunders sounds good, guess I just have to use it differently in different types of applications (such as put it in the request object for web pages and maybe pass around an instance for console apps).