Is there a better way to use Structuremap to inject dependencies into a custom RoleProvider? - asp.net-mvc-3

I found http://www.devproconnections.com/content1/catpath/database-development/topic/a-perfect-storm-linq-to-sql-dependency-injection-and-asp-net-providers/page/2 and had similar code as from the webpage:
public class CustomProvider : MembershipProvider, IMembershipProvider
{
private IUserRepository _userRepo;
// this .ctor is used via unit tests (as a seam)
public CustomProvider(IUserRepository repo)
{
this._userRepo = repo;
}
// requisite parameter-less constructor:
public CustomProvider()
{
// do NOTHING here
}
public override bool ValidateUser(string username, string password)
{
// HACK:
IUserRepository repo = this._userRepo ?? ObjectFactory.GetInstance<IUserRepository>();
SiteUser user = repo.GetUserByEmailAddress(username.ToLower());
if (user == null)
return false;
if (!user.Active || !user.Verified)
return false;
if (user.PassPhrase.IsNullOrEmpty())
return false;
// do other verification... etc
}
}
Except mine is a custom RoleProvider. Is calling the ObjectFactory.GetInstance an accepted way to inject dependencies into a RoleProvider? I tried to setup a property to inject the dependency, but I could not get that to work. I'm sure my StructureMap registry is wrong. But hard to find out the right way when the documentation is out of date.
So for an ASP.NET MVC3 app, is calling the ObjectFactory ok in a custom RoleProvider? Or should I attempt to inject to a property?
If a property, how? I have For<RoleProvider>().Use(ctx => Roles.Provider); currently. But I'm not sure id the Use should be an Add, nor am I sure on the syntax to inject a dependency into a property.
Still Need help
I'm having an awful time trying to make miniprofiler not throw Null ref exceptions when I merely move the StructureMap ObjectFactory to a property for init. The goal is to allow roles to be cached. I get the same error as these questions mini-profiler nullreferenceexception Help Configure mvc mini profiler with Linq to Sql
I've updated to the latest MVCMiniProfiler and tried it's MVC package. Seems that profiling isn't enabled before the custom RoleProvider is init or the properties are initialized. If I set the field straight from the overridden GetRolesForUser method, everything is fine. If I make that field a backer to a public property, I get NULL exceptions in ProfiledDbCommand. Why?

The Microsoft "provider" pattern does not work well with dependency injection, because of its reliance on statics and singletons. If you have to use a Provider, just do the service location via ObjectFactory.GetInstance and move on.

Related

Web Api 2 with OWIN OAuth Bearer tokens

I'm in the process of building a web api in visual studio 2013 and want to authenticate using OWIN middleware and bearer tokens. However I already have a database and don't want to use Microsoft's new Identity framework as the majority of tables and columns that it auto generates I simply don't need.
Can anyone point me in the right direction of how to apply this type of authentication without having to use the Microsoft Identity framework?
My suggestion would be to use the framework but extend it to use your objects and infrastructure. I am currently in the middle of doing this and landed on this question. Here's how I've tackled it so far:
Step 1: Your own CustomUserObject
Write/Use your own "ApplicationUser" object. In the template project, you want to modify the "IdentityModels" file. It has ApplicationUser object defined in there. Assuming you already have all the properties from your existing app, you will need to add GenerateUserIdentityAsync() method but change the type of the parameter to UserManager manager). After the change, your method signature looks like this:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<CustomUserObject> manager)
Step 2: Define your own IUserStore<> implementation
Add a new class CustomUserStore that implements IUserStore, like so:
public class CustomUserStore : IUserStore<CustomUserObject>
{
private readonly IUserManagerService _userManagerService;
public CustomUserStore(IUserManagerService userManagerService)
{
_userManagerService = userManagerService
}
//implementation code for all of the IUserStore methods here using
//userManagerService or your existing services/classes
}
I am using Unity to inject IUserManagementService's implementation above.
I have made use of the comprehensive UserManager class that comes with the Microsoft Identity framework but extended the framework to use my API for authentication and authorization. You could write your own UserManager but I found that it is pretty tedious and there is no reason why UserManager could work for most cases of Securing an app.
Step 3: Changes in the IdentityConfig.cs file
Change the class definition to make ApplicationUserManager class inherit from UserManager
You'll need to do the samething in the constructor of this class as well; i.e. have IUserStore. Modify the Create static method's first line to make use of the new store and a wrapper class that provides as a means to be a "DbContext" like so:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get<UserManagementServiceWrapper>()));
//modify the relevant lines after this to suit your needs
...
}
My UserManagementServiceWrapper looks like this (please note that I'm not too happy that it inherits from a concrete UserManagementService class that provides the methods to connect to the service that provides user data, I'm still building this out):
public class UserManagementServiceWrapper : UserManagementService, IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}
Step 4: Change the ApplicationDbContext class to return a UserManagementServiceWrapper instance
public class ApplicationDbContext : UserManagementServiceWrapper
{
public static UserManagementServiceWrapper Create()
{
return new UserManagementServiceWrapper();
}
}
And that is pretty much it. You still have to write the implementation for CustomUserStore object but everything should work.
Please note this is not boilerplate code and no where near "code review ready", as I said, I'm still digging deeper into this and building it out to use custom stores, data access objects, services etc. I thought you'll get a good start with some of the things that took me a couple of hours to figure out. I will blog about this when I have a good solution.
Hope this helps.
I prob. dont understand the question entirely but it looks like you are trying to do without the whole owin pipeline?
If not then..
You need to implement few interfaces related to users and roles described as below.
http://www.asp.net/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity
Have a look at the following post from Scott Allen
http://odetocode.com/blogs/scott/archive/2013/11/25/asp-net-core-identity.aspx
This way you can use your own tables, DAL and services to create UserManager and RoleManager objects.
Edit: Samples over here should give you some pointers.
Edit2: Custom User Store Example.
IRepository is the object which takes care of CRUD.
public class CustomUserStore : IUserStore<User>,....
{
private readonly IRepository _repository;
public CustomUserStore(IRepository repository)
{
if (repository == null)
throw new ArgumentNullException("repository");
_repository = repository;
}
public Task CreateAsync(User user)
{
if (user == null) throw new ArgumentException("user");
_repository.User.Add(user);
return _repository.CommitAsync();
}
...

Injection using NInject in ISiteMapNodeVisibilityProvider

I have a small problem which, hopefully, you will help me put behind.
I am using a MvcSiteMapProvider, and I want to define visibility for each node using access to a DB via a service interface.
public class AreaSiteMapNodeVisibilityProvider : MvcSiteMapProvider.Extensibility.ISiteMapNodeVisibilityProvider
{
[Inject]
public ISecurityService _SecurityService {get;set;}
public AreaSiteMapNodeVisibilityProvider()
{
}
public bool IsVisible(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata)
{
MvcSiteMapNode thisNode = node as MvcSiteMapNode;
return _SecurityService.CalculateNodeVisibility(thisNode,context.Cache["someValueIHaveStoredHere"])
}
}
However, my _SecurityService member is always null. Any suggestions? I accept any type of directions, including getting rid of my injection and going another way.
Your ISecurityService is null, because in this case, Ninject is not managing the creation of MvcSiteMapProvider (in MVC app, Ninject resolves dependencies wired from controller root, because it manages the creation of controllers - it overrides the default method for creation controllers).
Options to resolve your issue:
1)
Use Ninject as service locator. Not recommended!, as it is widely considered to be an anti-pattern (but it depends...).
var app = HttpContext.ApplicationInstance as NinjectHttpApplication;
var service = app.Kernel.Get<ISecurityService>();
2) Read R. Gloor's answer on similar question: MVC3, Ninject, MvcSiteMapProvider - How to inject dependency to overridden method and do it his way.
Make sure that
The siteMapNodeVisibilityProvider is NOT configured in the web.config
There is a binding for ISiteMapNodeVisibilityProvider

Windsor transient lifestyle

I have some very odd behaviour in my Windsor Container.
I have configured my container like this.
Container = new WindsorContainer();
Container.Kernel.ComponentModelCreated += KernelComponentModelCreated;
Container.Install(FromAssembly.This());
private static void KernelComponentModelCreated(ComponentModel model)
{
if (model.LifestyleType == LifestyleType.Undefined)
model.LifestyleType = LifestyleType.Transient;
}
So I was supposing all my components where I don't specify the lifestyle would get a transient lifestyle and it seemed to don't give any issues until now.
I start multiple asynchronous task which all resolve some components. (So you would expect every task gets a new instance of the component)
However now I know the tasks don't get new instances, because my tasks fail because of crossthreading issues with the component. (so it is being used in multiple tasks)
When I replace the Container.Resolve(somecomponent); With just creating the new component in place everything works like it should.
var contextProvider = MvcApplication.Container.Resolve<IDbContextProvider>();
replaced with
var contextProvider = new DbContextProvider();
So my question is what am I missing here.
The tasks are started in transient configured MVC3 controllers, because of explicitly configured.
The DbContextProvider is resolved in all repositories also configured transient, because of above code.
Another thing I found in the documentation is. You have to release transient components. I implemented all components with IDisposable. But because of auto contructor injection in my controllers I am not completely sure if I have to release them manually and if so how can I do this. (Yes I know I have to call the Release method on the container)
UPDATE
Code below is responsible for releasing and resolving my controllers:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
Is there some example available for testing if all dependencies are resolved and released the way they should be? (LifeStyle tests)
I'm not sure if this is what is causing your issues, but you should modify ComponentModel in an implementation of IContributeComponentModelConstruction only.
Check out the documentation of the component model construction contributors for help on how to effectively change the default lifestyle of the container.
Regarding disposal of IDisposables - if you release your controller like you should everything will just work with Windsor :)

Unit testing custom MembershipProvider.ValidateUser, using code in Global.asax

I have a unit test to check my AccountController.LogIn method. A redirect result is returned to indicate successs, otherwise a viewresult is returned.
The test always fails as the return type is always viewresult, even though the test should return success as the credentials are valid, however I can't identify where the problem is.
My TestMethod:
CustomerRepositoryTest.cs
[TestMethod]
public void Can_Login_With_Valid_Credentials()
{
// Arrange
Mock<IAddressRepository> mockAddressRepository = new Mock<IAddressRepository>();
Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
Mock<IOrderRepository> mockOrderRepository = new Mock<IOrderRepository>();
LoginViewModel model = new LoginViewModel
{
Email = "me#5.com",
Password = "password"
};
AccountController target = new AccountController(mockCustomerRepository.Object, mockAddressRepository.Object, mockOrderRepository.Object);
// Act
ActionResult result = target.LogIn(model);
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectResult));
Assert.AreEqual("", ((RedirectResult)result).Url);
}
When I run the test, it fails in My AccountController Login method when I call ValidateUser
AccountController.cs
if (Membership.ValidateUser(LoginModel.Email, LoginModel.Password))
{
...
return RedirectToRoute(new
{
controller = "Account",
action = "Details"
});
}
else
{
return View();
}
My custom MembershipProvider ValidateUser looks like this:
AccountMembershipProvider.cs
public class AccountMembershipProvider : MembershipProvider
{
[Inject]
public ICustomerRepository repository { get; set; }
public override bool ValidateUser(string username, string password)
{
var cust = repository.GetAllCustomers().SingleOrDefault..
When I run the application normally i.e. not testing, the login works fine. In the application I inject the CustomerRepository into the custom membership provider in Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
private IKernel _kernel = new StandardKernel(new MyNinjectModules());
internal class MyNinjectModules : NinjectModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>();
}
}
protected void Application_Start()
{
_kernel.Inject(Membership.Provider);
...
Is it the case that the Global.asax code isn't run while unit testing? and so my custom provider isn't being injected, hence the fail?
UPDATE
I mocked my Provider class and passed the mocked CustomerRepository object to it.
Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
provider.Object.repository = mockCustomerRepository.Object;
I then created a setup for the method I'm trying to test:
mockCustomerRepository.Setup(m => m.IsValidLogin("me#5.com", "password")).Returns(true);
But unfortunately I'm still getting a fail every time. To answer the question about whether I need a real or mocked object for the test - I'm not fussy, I just want to get it working at the moment!
UPDATE 2
I made those changes, and while it's still failing, it has allowed me to identify the specific problem. While debugging the test, I discovered that when I call the overridden
Membership.ValidateUser(LoginModel.Email, LoginModel.Password)
The Membership.Provider is of type SqlMembershipProvider (which is presumably the default type) and consequently validation fails.
If I cast the provider to my custom provider...
((AccountMembershipProvider)Membership.Provider).ValidateUser(LoginModel.Email, LoginModel.Password)
I get an InvalidCastException when running the test. So it seems that my mocked AccountMembershipProvider isn't being used for the test and instead the default provider is being used.
I think you have identified this already in the comment:
// set your mock provider in your AccountController
However I'm not sure what you mean exactly - I don't have a property on my AccountController to assign the provider to, and i'm not injecting it into the constructor.
Your original question:
"Is it the case that the Global.asax code isn't run while unit testing? and so my custom provider isn't being injected, hence the fail?"
My answer:
Yes.
The global.asax file is used by ASP.Net and ISS at run-time. It is compiled when the server receives it's first request.
When you are testing, you aren't in the context of a ASP.Net web-application running in ISS, but rather in program running in a test session. This means your global.asax won't get called.
More importantly, when you call:
Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
Ninject won't get called the fill the import. Moq will create a mock based on the interface. No real object will be created.
Since you did not define any Setup methods, ie:
mockCustomerRepository.Setup(mock => mock.MyAuthenticateMethod()).Returns(true);
You are passing around a mock with no defined behaviour. By default these will return false. Which probably explains why you are always getting a viewresult.
What you need to do is define setup methods for the methods you need to mock.
These are the methods of CustomerRepository that will get called you when call:
target.LogIn(model);
Also note that your AccountMembershipProvider won't get it's CustomerRepository injected since NInject won't be used. If you are testing the AccountController and it's not static (Moq doesn't work with static) you should consider mocking the AccountMembershipProvider. If you can't, then you would need to supply your mocked instance of CustomerRepository to AccountMembershipProvider.repository in your tests.
Another solution, instead of creating a Moq mock, you could also manually create (with new) a real instance of CustomerRepository in your test.
You could have Ninject do it, but at this point why? You can create it yourself and you know what specific type to create.
It all boils down to if you need a mock or a real instance of the object for this test.
Update:
If your provider is mocked, there is no need to set the repository on it. When you are calling a mock, the real object won't get called.
What you need to do is something like this:
Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
// set your mock provider in your AccountController
provider.Setup(m => m.ValidateUser("me#5.com", "password")).Returns(true);
Update 2:
I think you are pretty close to making your test work. Without seeing all of your code (test and class under test) I can't really give you anymore help. I also feel I answered your original question, but if you are still stuck you might get more help by asking a new question relating to the problem you are currently tackling.
In your code you only create controller, but not run initialization for membership. I recommend you to create your own UserService with method ValidateUser and other you need instead of static class Membership usage.

ASP.NET MVC 3: Validating model when information external to the model is required

What's a good way to validate a model when information external to the model is required in order for the validation to take place? For example, consider the following model:
public class Rating {
public string Comment { get; set; }
public int RatingLevel { get; set; }
}
The system administrator can then set the RatingLevels for which a comment is required. These settings are available through a settings service.
So, in order to fully validate the model I need information external to it, in this case the settings service.
I've considered the following so far:
Inject the service into the model. The DefaultModelBinder uses System.Activator to create the object so it doesn't go through the normal dependency resolver and I can't inject the service into the model without creating a new model binder (besides which, that doesn't feel like the correct way to go about it).
Inject the service into an annotation. I'm not yet sure this is possible but will investigate further soon. It still feels clumsy.
Use a custom model binder. Apparently I can implement OnPropertyValidating to do custom property validation. This seems the most preferable so far though I'm not yet sure how to do it.
Which method, above or not, is best suited to this type of validation problem?
Option 1 doesn't fit. The only way it would work would be to pull in the dependency via the service locator anti-pattern.
Option 2 doesn't work. Although I couldn't see how this was possible because of the C# attribute requirements, it is possible. See the following for references:
Resolving IoC Container Services for Validation Attributes in ASP.NET MVC
NInjectDataAnnotationsModelValidatorProvider
Option 3: I didn't know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.
First, you create your custom ModelValidatorProvider:
public class CustomModelValidatorProvider : ModelValidatorProvider
{
public CustomModelValidatorProvider(/* Your dependencies */) {}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata.ModelType == typeof(YourModel))
{
yield return new YourModelValidator(...);
}
}
}
ASP.NET MVC's IDependencyResolver will attempt to resolve the above provider, so as long as it's registered with your IoC container you won't need to do anything else. And then the ModelValidator:
public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator
{
public EntryRatingViewModelValidatorMvcAdapter(
ModelMetadata argMetadata,
ControllerContext argContext)
: base(argMetadata, argContext)
{
_validator = validator;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (/* error condition */)
{
yield return new ModelValidationResult
{
MemberName = "Model.Member",
Message = "Rating is required."
};
}
}
}
As the provider is retrieved through the IDependencyResolver and the provider has full control over the returned ModelValidators I was easily able to inject the dependencies and perform necessary validation.
You could try fluent validation. It supports asp.net mvc and DI so you can inject external services into your validators.
Assuming that you want both client and server-side validation of the model based upon the values returned from the service, I would opt for 2., Inject the service into an annotation.
I give some sample code in my response to this question about adding validators to a model. The only additional step in your case is that you will need to inject your service into your class inheriting from DataAnnotationsModelValidatorProvider.
What about just simply using IValidateableObject and in that method determine if validation is appropriate or not and setting the errors there?
How do I use IValidatableObject?

Resources