I wonder if someone ran into the issue that I am having with trying to move ApplicationUser into Models project (where all other models reside including the ones related to Users table).
My test MVC 5 solution consists of a web project and two class libraries: one for data access layer (DAL) and the other for Models. I references AspNet.Identity.EntityFramework in all three projects.
In my DAL class I implement Repository pattern and a UnitOfWork. UnitOfWork extends IdentityDbContext<ApplicationUser>. ApplicationUser : IdentityUser is in Models class library.
In my web project UnitOfWork is instantiated using Autofac DI.
For regular controllers I defined a base class that inherits from Controller and takes IUnitOfWork as a parameter in the constructor. All controllers inherit from my custom base controller.
I ran into a problem with AccountController. It has two constructors: one with no parameters that seems to instantiate ApplicationDbContext, the other takes UserManager as a parameter.
The parameter-less constructor gives me most of the grief. I tried many things: make accountcontroller inherit from my custom base controller, then try to inherit it from the Controller class. At best I succeed in making my solution compile but when I test the app and fill out user Registration form I get 'Object is not instantiated' message. When I debug I see that the second constructor in AccountController gets called but UserManager is null there.
Any ideas? I would really appreciate somebody's brainy input into this.
Take a look at the SimpleSecurity Project. This project decouples ASP.NET Identity from the web application and puts ApplicationUser into an assembly separate from the web application. This project also has a version that uses SimpleMembership. For ASP.NET Identity look in the AspNetIdentity folder. The assembly for the security functions is in AspNetIdentity/SimpleSecurity.AspNetIdentity and the reference web application is in AspNetIdentity/SimpleSecurity.AspNetIdentity/RefApp.
Related
I am creating a project with visual studio 2015. This project is created from asp.net project template (MVC checkbox is checked).
Multiple files are automatically generated (for user management for example).
I have a file called IdentityModels.cs witch contain IdentityDbContext (for user tables).
I want to create other tables/entity for my application. Here is what i did: A created a second Context class, with inherits from DbContext.
But i am wondering if it is a good thing to have 2 DbContext for the same database.
Should i put everything in IdentityDbContext ? Or create 2 databases for my project (one for authentification and the other for my own tables) ?
Thanks
I suggest to leave the IdentityDBContext as is and create another data context in a separate class library project that represents your data access layer
When you run the migration you will specify the context name which be always the second one, once you get your identity tables created, you will not need the IdentityDBContext again for migration
When I make a change to the access modifier of a controller class it results in an error. If I make the accessibility of an action method non-public then it also results in an error (specifically a page not found error). Why is this the case?
By default if you not specify any access modifier for a class then it will default to internal in C#. Only code in the same assembly can access a class that is internal. So if your controller is internal, the code that creates a controller instance upon receiving a request would have to be in your assembly.
But controller creation code is present in the System.Web.Mvc assembly and by default DefaultControllerFactory is responsible for creating controllers. If your code is present in, for example, the MvcApplication1 assembly then DefaultControllerFActory can not find your controller classes without the public access modifier so it is not able to instantiate them.
If you want to build a tightly coupled ASP.NET MVC application (which it is not it designed for) then theoretically you could do it following way.
Get the MVC source code if available.
Then build your code in same assembly.
While developing web project using ASP.NET MVC, I came up against a coupling problem.
When I build custom controller factory (or dependency resolver if using MVC 3), I need this factory to know somehow where to get dependencies from. Here's my code:
//from Global.asax.cs
DependencyResolver.SetResolver(new StructureMapControllerFactory());
class StructureMapControllerFactory: IDependencyResolver {
Container repositories;
public StructureMapControllerFactory()
{
repositories = new RepositoriesContainer();
}
//... rest of the implementation
}
class RepositoriesContainer: Container
{
public RepositoriesContainer()
{
For<IAccountRepository>().Use<SqlAccountRepository>();
//...
}
}
StructureMapControllerFactory class is responsible for injecting dependencies into a controller. As I said, it needs to know where to find these dependencies (I mean concrete classes, like services and repositories implementations).
I have a separate class library called MySite.Data, where all the implementation details live. Contracts, like IAccountRepository, live in library MySite.Contracts. Now, if I reference this MySite.Data library directly from MVC project, there will be a dependency between my site and implementation of its data retrieval. The question is how can I remove it? What are best practices in this situation?
I'm sure it does have a bunch of workarounds, just I haven't found any yet.
Well, as I see it, you can't do exactly that. Your MVC project really really needs to know about concrete classes it is going to use.
You will anyway have to provide those container registrations somewhere and you'll get the dependency on the project/assembly where that type is defined. Shortly, you have to reference MySite.Data from MVC project. Like that:
MySite.Data knows nothing about MVC project
MVC project knows the concrete repositories types to provide correct container registrations.
You can make life simpler with StructureMap Registry objects but you need to include those Registries somewhere as well. Typically those are in the main project or some "StructureMap-adapter" project but you'd need to make reference anyway.
I'd advise that you:
Use MVC3 and drop your custom IControllerFactory if you only use it for DI into your Controllers.
Use StructureMap Registry objects to provide each and every IoC registration ever needed.
Use StructureMap Assembly scanning capabilities to provide components discovery.
Use something much more common as a DependencyResolver, i.e. not a StructureMapControllerFactory but a CommonServiceLocator with StructureMap adapter instead.
Try to abstract from StructureMap itself inside your main app.
And, of course, don't be afraid of making references inside the main project - they have nothing about coupling. It doesn't decrease maintainability. But the wrong architecture does, so be worried about that, not simple reference.
My app is set up this way
Web
Data
Services
POCO Entities
Controllers use services (so they should be injected)
Services use Repositories (which I assume should also be injected)
I have this already set up so that the Controllers receive the service they need through Ninject but I not sure how to get this done with the services =>repositories
any help with this?
You could use the ninject.web.mvc extension. It contains a sample application which illustrates how you could register the container in Global.asax.
Bob has several blogs about repository pattern with Ninject and NHibernate. It's pretty much the same for all other OR Mappers:
http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/
Simply set up your services' dependencies as well as the controller's dependencies. Ninject will walk the dependency chain and resolve all of them.
for example,
ProductController has dependency on IProductService
IProductService is implemented with ProductService that has a dependency on IProductRepository
IProductRepository is implemented with NHibernateProductRepository that has a dependency on ISession.
when your NinjectControllerFactory attempts to resolve ProductController, it sees the dependency on IProductService. it resolves that dependency as ProductService, and sees that it has a dependency on IProductRepository. and it will continue on down the chain until it can resolve completely an argument.
so the important part is to Bind ANY dependencies, not just those in a Controller.
I have a custom membership provider which works fine until I use unity in the web application.
public class CustomMemberProvider : MembershipProvider
I have done some googling and found the snippet below to place in the application_start() of the global file but I am not sure what I need to do to it to make it work for my custom provider. Basically when I make a call on validateUser() on my security controller it fails to resolve the dependencies.
_container.RegisterType<IFormsAuthenticationService, FormsAuthenticationService>()
.RegisterType<IMembershipService, AccountMembershipService>()
.RegisterInstance<MembershipProvider>(Membership.Provider);
I thought I could swap "AccountMembershipService" for "CustomMemberProvider" but that causes the Controller Type to be null in the standard "UnityControllerFactory".
Has anyone had the same problems?
thanks.
AccountMembershipService is probably the same service that VS generates. This service implements IMembershipService (a custom interface generated by the code). Simply swapping out AccountMembershipService for CustomMemberProvider is not going to be the same thing.
Essentially, your custom membership provider implements the abstract class "MembershipProvider" which is different than this "AccountMembershipService" which is a wrapper to SqlMembershipProvider.
You need to make a wrapper to your membership provider to implement a type. Also, I'm pretty sure Membership.Provider is going to take you to System.Web.Security.MembershipProvider and not your custom provider.