Accessing a repository in AccountController through constructor - c#

I am using the MVC AccountController that implements the ASP.NET Membership Provder.
I have a repository with all my database access in which I have added a Countries property that returns a list of countries. I want to add a country dropdown to the Register page so I need to be able to get this data from my repository and pass it to the View.
I have been using contructor injection in my other controllers but I dont know how to apply this to the existing AccountController.
// This constructor is used by the MVC framework to instantiate the controller using
// the default forms authentication and membership providers.
public AccountController()
: this(null, null)
{
}
// This constructor is not used by the MVC framework but is instead provided for ease
// of unit testing this type. See the comments at the end of this file for more
// information.
public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
{
FormsAuth = formsAuth ?? new FormsAuthenticationService();
MembershipService = service ?? new AccountMembershipService();
}
Can I change the existing AccountController constructor to access my repository?

Register the services in your IoC engine and then remove the default constructor.

If you have already registered your repository with ninject, you should be able to just add a third parameter to the constructor of the controller. I saw your earlier comment about ninject, but I'm not using NinjectModule. If you're using MVC 3, would suggest that you take a look at nuget (http://nuget.codeplex.com) and download the Ninject.MVC3 packge which adds a AppStartNinjectMvc3 class to your project where you can register services with the kernel.Bind methods:
kernel.Bind<IThingRepository>().To<SqlThingRepository>();
Hope this helps.

If your using MVC2 you should take a look at http://mvcstarter.codeplex.com/ it's also using Ninject. Like #Johan said you simply have to put the parameter and bind it in the global.asax.cs.
Hope it helps!

Related

IdentityServer 4, Create Panel to CRUD Clients

Currently I Have configured Identityserver4 as separated project + My WebAPI and store in DB Credentials in IdentityServer.
Now i have problem how to make CRUD(In my frontend API) to IdentityServer(I want from my API add Clients to IdentityServer)
How to make property?
From IdentityServer4.EntityFramework and IdentityServer4.EntityFramework.Storage, you have access to IConfigurationDbContext (once you've added the required services in ConfigureServices using e.g. AddConfigurationStore). Because this is registered as part of the Dependency Injection system, you can take a dependency on it in one of your controllers. e.g.:
public class ClientsController : ControllerBase
{
private readonly IConfigurationDbContext _configurationDbContext;
public ClientsController(IConfigurationDbContext configurationDbContext)
{
_configurationDbContext = configurationDbContext;
}
// ...
}
IConfigurationDbContext is an abstraction of a standard DbContext, with the following DbSet<T> properties:
Clients
IdentityResources
ApiResources
It also includes both SaveChanges and SaveChangesAsync - Everything one might expect from a DbContext. Because of all of this, you can CRUD each of these entities just like any other Entity Framework Core driven database.
One final thing to note is that there are both Models (in IdentityServer4.Storage) and Entities (in IdentityServer4.EntityFramework.Storage). There are also a few extension methods for mapping between these (e.g. ClientMappers.ToEntity).
Given all of this, you can create a Model inside of your controller (or perhaps somewhere much better encapsulated than directly there). Here's a basic example for creating a new Client:
var clientModel = new Client
{
ClientId = "",
ClientName = "",
// ...
};
_configurationDbContext.Clients.Add(clientModel.ToEntity());
await _configurationDbContext.SaveChangesAsync();
The Client class here comes from IdentityServer4.Models and is then converted to an Entity using a ToEntity extension method I hinted at above. Working with a Model and converting to an Entity is simpler than trying to manipulate an Entity directly - If you're interested, you can see the mapping that takes place here.
This works in the same way for ApiResources, IdentityResources, etc. Use the source code links I've provided if you want to find out more about those specifically, but the information I've provided here should have you covered.
In order to use IdentityServer4 and IdentityServer4.EntityFramework in your API project, you can just add the two references to your API project. After that, you can configure the DI in the same way (using AddIdentityServer in ConfigureServices), but you don't need to add the middleware (using UseIdentityServer in Configure). You can even just use AddIdentityServer().AddConfigurationStore(...) to set up the relevant services, as you don't need a signing key, etc.
One way you can do this is by bootstrapping the ID4 Quickstart (tutorial located here):
http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html
Other option is to use their quickstart seeds located here to speed this up:
https://github.com/IdentityServer/IdentityServer4.Samples
Now if you want to implement restfull login there are constraints around it (i wanted to find out as well) check out this question:
IdentityServer 4 Restfull Login/Logout

Asp.net MVC boilerplate dependency injection not working

I'm playing with the Asp.Net MVC 6 boilerplate project. I'm trying to configure the dependency injection for one of my services. It seems like the built in IoC container is ignoring my binding.
Startup.cs
public void ConfigureServices(IServiceCollection services){
/*boilerplate's default bindings*/
services.AddTransient<IDummy, Dummy>(p => new Dummy()
{
name = "from injection"
});
}
HomeController.cs
public IActionResult Index(IDummy dummy){
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}
Exception:
ArgumentException: Type
'Presentation.WebUI.Controllers.IDummy' does not have a
default constructor
Could you please tell me what is am I doing wrong?
That exception is because the framework cannot bind action arguments to interfaces.
You are trying to do the injection on the Action when the framework by default uses constructor injection.
Reference: Dependency Injection and Controllers
Constructor Injection
ASP.NET Core’s built-in support for constructor-based dependency
injection extends to MVC controllers. By simply adding a service type
to your controller as a constructor parameter, ASP.NET Core will
attempt to resolve that type using its built in service container.
public class HomeController : Controller {
IDummy dummy;
public HomeController(IDummy dummy) {
this.dummy = dummy
}
public IActionResult Index(){
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}
}
ASP.NET Core MVC controllers should request their dependencies
explicitly via their constructors. In some instances, individual
controller actions may require a service, and it may not make sense to
request at the controller level. In this case, you can also choose to
inject a service as a parameter on the action method.
Action Injection with FromServices
Sometimes you don’t need a service for more than one action within
your controller. In this case, it may make sense to inject the service
as a parameter to the action method. This is done by marking the
parameter with the attribute [FromServices] as shown here:
public IActionResult Index([FromServices] IDummy dummy) {
var test = dummy.name;
return this.View(HomeControllerAction.Index);
}

StructureMap and HTTP request-scoped services - why is my service created twice in a single scope?

I have an ASP.NET MVC application using StructureMap.
I have created a service called SecurityContext which has a static Current property. A simplified version looks like this:
public class SecurityContext : ISecurityContext
{
public bool MyProperty { get; private set; }
public static SecurityContext Current
{
get
{
return new SecurityContext() { MyProperty = true };
}
}
}
I've hooked this up in my StructureMap registry as follows:
For<ISecurityContext>().Use(() => SecurityContext.Current);
My understanding of this Linq expression overload of the Use method is that the returned concrete object is the same for the entire HTTP request scope.
However, I've set up a test case where my context interface is injected in two places, once in the controller's constructor and again using the SetterProperty attribute in the base class my view inherits from.
When debugging I observe the Current static method being hit twice so clearly my assumptions are wrong. Can anyone correct what I'm doing here? The reason I want this request-scoped is because I'm loading certain data into my context class from the database so I don't want this to happen multiple times for a given page load.
Thanks in advance.
The default lifecycle for a configuration is Transient, thus each request for an ISecurityContext will create a new instance of SecurityContext. What I think you want is to use the legacy HttpContext lifecycle.
Include the StructureMap.Web nuget package. Then change your configuration to the following:
For<ISecurityContext>()
.Use(() => SecurityContext.Current)
.LifeCycleIs<HttpContextLifecycle>();
More information on lifecyles can be found here.
The HttpContextLifecycle is obsolete, however I do not know if or when it will be removed. The StructureMap team does recommend against using this older ASP.Net lifecycle. They state in the documentation that most modern web frameworks use a nested container per request to accomplish the same scoping. Information about nested containers can be found here.
I don't know if the version of ASP.Net MVC you are using is considered a modern web framework. I doubt it is because ASP.Net Core 1.0 is the really the first in the ASP.Net line to fully embrace the use of DI. However, I will defer to #jeremydmiller on this one.

Custom Membership provider with dependency injection - how to test

This is similar to Dependency Injection with Custom Membership Provider, but the responses there don't solve the issue for me.
I have a custom membership provider which has a dependency to a repository class. ASP.NET will always instantiate this using the parameter-less constructor, so to resolve the dependency to the repository I have a kind of service locator method ... my ctor looks like this:
public CustomMembershipProvider()
{
_userRepository = AppStart_NinjectMVC3.Resolve<IUserRepository>();
}
And that Resolve method looks like this..
public static T Resolve<T>() where T : class
{
return _kernel.Get<T>();
}
This works fine when I run the web app, because _kernel is correctly setup. However, I need to test the methods on my membership provider.. So when my test code tries to invoke the methods on membership provider it will instantiate a new membership provider class with the paramter-less ctor, which errors because _kernel is not setup.
What I want to do is somehow inject my FakeUserRepository class instead, but how can I achieve that?
I think I have a work round for this...
I've added a ctor to the membership provider which accepts a repository instance, and then I've manually instantiated my membership provider in my test class like this:
var prov = new CableSenseMembershipProvider(new FakeUserRepository());
var config = new NameValueCollection();
config.Add("applicationName", "ddd");
config.Add("name", "CustomMembershipProvider");
config.Add("requiresQuestionAndAnswer", "false");
config.Add("requiresUniqueEmail", "false");
prov.Initialize(config["name"], config);
Once I've dont this I can then invoke that instance and not worry about the parameter-less ctor being called.
As an aside, you still need to add the membership section to your test project app.config or it wont work - which is somewhat confusing!
Why not extract everything out of your custom membership provider into an implementation class and instantiate that class via the service locator then pass all your calls through to that? The implementation class can then be unit-testable and the ugly Membership stuff can be 'right by inspection'.

Using a parameterless controller constructor with Ninject?

I'm using Ninject for dependency injection in my application. Here's an example of one of my controllers:
public class DepartmentsController : Controller
{
private IDepartmentsRepository departmentsRepository;
public DepartmentsController(IDepartmentsRepository departmentsRepository)
{
this.departmentsRepository = departmentsRepository;
}
...
}
I'm also trying to follow this tutorial to use ELMAH in an MVC application. The idea is to use a custom controller factory to handle errors from every controller. You then set the controller factory to the custom one in the global.asax.cs file.
The only problem is that it is expecting a parameterless constructor in each controller, which I can't do (that I know of) with dependency injection with Ninject.
How can I get around this?
If you are using MVC3, you should ignore the part about the Controller Factory and use Global Filters to apply the custom attribute to each controller.
If you aren't using v3 yet and you can modify their code to inherit from the Ninject Controller factory.

Categories

Resources