How to configure ASP.NET Identity ApplicationUserManager with StructureMap - asp.net-mvc

I am using asp.net identity in my project and using structuremap as DI framework. the problem is when i use constructor injection then ApplicationUserManager not configured all of it's members e.g TokenProvider, ...
this is my ApplicationUserManager class:
public class ApplicationUserManager : UserManager<User, long>
{
public ApplicationUserManager(IUserStore<User, long> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new CustomUserStore(context.Get<InsuranceManagementContext>()));
// Configure the application user manager
manager.UserValidator = new UserValidator<User, long>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
manager.PasswordValidator = new PasswordValidator
{
RequireDigit = true,
RequiredLength = 8,
RequireLowercase = false,
RequireNonLetterOrDigit = true,
RequireUppercase = false
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<User, long>(dataProtectionProvider.Create("TEST"));
}
return manager;
}
}
this is Startup.Auth class:
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(InsuranceManagementContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromHours(2.0),
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
});
}
}
and its my AccountController:
public class AccountController : BaseController
{
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public AccountController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
}
my question is how can i configure my ApplicationUserManager with structuremap?
if i set it as the below code it works but i don't know it is a good solution or not:
ObjectFactory.Initialize(x =>
{
...
x.For<ApplicationUserManager>().Use(() => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>());
...
});
please hint me if there is a better solution and if it is ok then what is the best lifetime for it? HttpContextScope, Singleton, ...?

Before you create the StructureMap configuration for this, it helps to know how you would create it manually, i.e., if you actually "new up" everything yourself.
UserManager has a dependency on IUserStore, and its EntityFramework implementation (UserStore) has a dependency on DbContext.
Doing everything manually would look like this:
var dbContext = new IdentityDbContext("Your ConnectionString Name");
var userStore = new UserStore<IdentityUser>(dbContext);
var userManager = new UserManager<IdentityUser>(userStore);
(Replace IdentityUser with your custom user, if you are using one)
You can then configure UserManager like this:
userManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6
};
The most complicated part about configuring userManager is related to the UserTokenProvider (that uses the data protection api), if you would do it manually it would look like this:
var dataProtectionProvider = new DpapiDataProtectionProvider("Application name");
var dataProtector = dataProtectionProvider.Create("Purpose");
userManager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtector);
Here's an example of a StructureMap registry (you can extrapolate from this example and adapt it to your own needs):
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IUserStore<IdentityUser>>()
.Use<UserStore<IdentityUser>>()
.Ctor<DbContext>()
.Is<IdentityDbContext>(cfg => cfg.SelectConstructor(() => new IdentityDbContext("connection string")).Ctor<string>().Is("IdentitySetupWithStructureMap"));
ForConcreteType<UserManager<IdentityUser>>()
.Configure
.SetProperty(userManager => userManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6
})
.SetProperty(userManager => userManager.UserValidator = new UserValidator<IdentityUser>(userManager));
}
I wrote a blog post about this, it explains the process that lead to this configuration, there's also a link to an example on github of an MVC project where, using this configuration, you can create, list and delete users.

Related

How do i register UserManager with OWIN context?

When I create MVC 5 application in Visual Studio 2013, and choose Individual accounts as authentication then scaffolding automatically configures ASP Net Identity. It creates several classes along with ApplicationDbContext and ApplicationUserManager. It also registers these classes with OWIN context as below to use single instance per request.
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
}
basically it registers static Create method of each class. This static method is responsible for creating instance of that class.
Quesion
1>If I don't want to use static create method, is the approach below correct?.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
public ApplicationDbContext(string connString)
: base(connString)
{
}
}
public void ConfigureAuth(IAppBuilder app)
{
var conString = ConfigurationManager.ConnectionStrings["Myconnection"].ConnectionString
app.CreatePerOwinContext(()=>new ApplicationDbContext(conString));
}
2> How do I register ApplicationUserManager without using the static Create method. (It must set UserValidator,PasswordValidator, UserTokenProvider etc)
Should I set Validators and UserTokenProvider in ApplicationUserManager's constructor? Like below
public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
public ApplicationUserManager(ApplicationUserStore store)
: base(store)
{
base.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
base.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
base.EmailService = new EmailService();
//?????????How do I get options.DataProtectionProvider ??????
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
base.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
3>In approach above How do I register ApplicationUserManager with OWIN context so that it create single instance per request? 'ApplicationUserManager also requires ApplicationUserStore and ApplicationDbContext..how do I pass those to ApplicationUserManager's constructor?

MVC 5.2 Cookie Sign In OWIN and Injecting Authenticated User Information

I am in a bit of a pickle with my MVC Application due to the way I have coded up (currently) the implementations of my application services and the way they are configured for dependency injection.
I'm looking to separate the layers of the application by following SOLID principles.
The problem is that in some of these services, the constructor requires an instance of IUserContext. IUserContext contains the various information about the logged in user and will be passed around a few different layers.
public class ProjectDataLoader : DataLoaderBase, IProjectDataLoader
{
public ProjectDataLoader(IMyDbContext dbContext, IUserContext userContext)
: base (dbContext, userContext)
{
}
...
public IEnumerable<ProjectViewModel> Find(string filter = "")
{
...
}
}
And an implementation of IUserContext:
public class AspNetUserContext : IUserContext
{
...
}
I could pass IUserContext on every method call but I feel it belongs in the constructor. But that is not the question here.
When I sign in from the login page via AccountController, MyAppSignInManager.SignInOrTwoFactor gets called via the OWIN pipeline. At this point I was creating a new instance of AspNetUserContext in the session:
HttpContext.Current.Session["UserContext"] = aspNetUserContext;
Now I have custom SignInManager implementation:
public class MyAppSignInManager : SignInManager<MyAppUser, string>
{
...
}
I have a custom IUserStore implementation:
public class MyAppUserStore : IUserPasswordStore<MyAppUser>,
IUserStore<MyAppUser>
{
...
}
All of the above have been hooked up for Dependency Injection with Simple Injector my choice of container.
public static class DependencyConfig
{
public static Container Initialize(IAppBuilder app)
{
Container container = GetInitializeContainer(app);
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
return container;
}
private static Container GetInitializeContainer(IAppBuilder app)
{
var container = new Container();
RegisterCommon(container);
RegisterRepositories(container);
RegisterDataLoaders(container);
RegisterAppServices(container);
RegisterMvc(app, container);
return container;
}
private static void RegisterCommon(Container container)
{
container.Register<IUserContext>(() =>
{
IUserContext context = null;
if (HttpContext.Current.Session == null)
context = new AspNetUserContext(Guid.Empty, Guid.Empty);
else
context = (IUserContext)HttpContext.Current.Session["UserContext"];
return context;
}, Lifestyle.Transient);
}
private static void RegisterRepositories(Container container)
{
container.RegisterPerWebRequest<IUserRepository>(() =>
new UserRepository(container.GetInstance<IMyApp4Context>()));
container.Register<IMyApp4Context>(() => new MyApp4Context(),
Lifestyle.Transient);
}
private static void RegisterDataLoaders(Container container)
{
container.Register<IProjectDataLoader, ProjectDataLoader>();
container.Register<ContractDataLoader>();
container.Register<DrawingDataLoader>();
container.Register<WeldDataLoader>();
}
private static void RegisterAppServices(Container container)
{
}
private static void RegisterMvc(IAppBuilder app, Container container)
{
container.RegisterSingle(app);
container.RegisterPerWebRequest<MyAppUserManager>();
container.RegisterPerWebRequest<SignInManager<MyAppUser, string>,
MyAppAppSignInManager>();
container.RegisterPerWebRequest(() =>
{
if (HttpContext.Current != null &&
HttpContext.Current.Items["owin.Environment"] == null &&
container.IsVerifying())
{
return new OwinContext().Authentication;
}
return HttpContext.Current.GetOwinContext().Authentication;
});
container.RegisterPerWebRequest<IUserStore<MyAppUser>>(() =>
new MyAppUserStore(container.GetInstance<IUserRepository>()));
app.UseOwinContextInjector(container);
container.RegisterMvcControllers(
Assembly.GetExecutingAssembly());
}
private static void InitializeUserManager(MyAppUserManager manager, IAppBuilder app)
{
manager.UserValidator =
new UserValidator<MyAppUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.PasswordValidator = new PasswordValidator()
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
IDataProtectionProvider dataProtectionProvider =
app.GetDataProtectionProvider();
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<MyAppUser>(
dataProtectionProvider.Create(purposes: new string[] { "ASP.NET Identity" }));
}
}
}
And also:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app, Container container)
{
app.CreatePerOwinContext(() => container.GetInstance<MyAppUserManager>());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(value: "/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyAppUserManager, MyAppUser>(
validateInterval: TimeSpan.FromMinutes(value: 30),
regenerateIdentity: (manager, user) =>
{
return user.GenerateUserIdentityAsync(manager);
})
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
}
Then these are to be used in the controllers:
public class ProjectController : MyBaseContextController
{
public ProjectController(IProjectDataLoader loader)
: base(context)
{
...
}
}
My initial question was going to be how can I get MyAppUser after the cookie authentication has taken place. Maybe asking this is still valid.
The better question is to ask what I am trying to accomplish. Essentially what I want is to inject IUserContext into my services. This needs to be injected into the constructor of the various service implementations registered in my DI container. However, this instance won't be available until a user has logged in/authenticated.
NOTE: All of the user information is stored in SQL and I use Entity Framework to access all of this.
So given that once a user has authenticated by logging in via the login page via the MyAppSignInManager.SignInOrTwoFactor method and also by a cookie, how can I make my AspNetUserContext (IUserContext) instance available to my DI container?
NOTE: I just want to get the user information from the database once - rather that every call to the controllers where it is required.
"I just want to get the user information from the database once."
You should consider storing your required user data in claims.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(value: "/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyAppUserManager, MyAppUser>(
validateInterval: TimeSpan.FromMinutes(value: 30),
regenerateIdentity: (manager, user) =>
{
return user.GenerateUserIdentityAsync(manager);
})
}
})
The GenerateUserIdentityAsync method adds the core identity claims but you can override this and store custom claims that your services need. Then instead of passing in a IUserContext to your service you could pass in an IClaimsIdentity.
This would mean you don't have to query the database all the time to get the data you need. The claims would be automatically updated after the 30 minute interval as specified in your code.
Hope this helps.

Autofac in Asp.net MVC, WebApi, SignalR, Owin yet again

How to register in a good way one Autofac dependency resolver or resolvers if one not possible for Asp.net MVC, WebApi, SignalR working together with Owin? There are guidelines for each of them. But as stated below it does not seem to work. Here is the code which is somewhat bad as it uses different dependency resolves, someones static and they seem to have one reason to exists (so looks like code duplication).
public class Startup
{
// This two static resolvers does not look nice
public static IDependencyResolver SignalRDependencyResolver { get; private set; }
public static System.Web.Http.Dependencies.IDependencyResolver WebApiDependencyResolver { get; private set; }
public void Configuration(IAppBuilder app)
{
var httpConfiguration = new HttpConfiguration();
var container = BuildAutofacContainer();
var hubConfiguration =
new HubConfiguration
{
Resolver = new AutofacDependencyResolver(container),
EnableDetailedErrors = true
};
// The resolver to be used as here. Seems to be replaced by SignalR further?
// 1. http://stackoverflow.com/questions/20139127/signalr-sending-data-using-globalhost-connectionmanager-not-working/20202040#20202040
// 2. http://stackoverflow.com/questions/20561196/signalr-calling-client-method-from-outside-hub-using-globalhost-connectionmanage
SignalRDependencyResolver = hubConfiguration.Resolver;
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
WebApiDependencyResolver = new AutofacWebApiDependencyResolver(container);
// Why the following does not work (throws that needs parameterless constructor) ?
// so the static resolver used
// see http://docs.autofac.org/en/latest/integration/webapi.html#owin-integration
// httpConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(httpConfiguration);
app.UseAutofacMvc();
app.UseWebApi(httpConfiguration);
app.MapSignalR("/signalr", hubConfiguration);
// AspNetIdentity hook:
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
private static IContainer BuildAutofacContainer()
{
var builder = new ContainerBuilder();
// and http://autofac.readthedocs.org/en/latest/integration/mvc.html#using-plugin-assemblies
builder.RegisterModule<AutofacDalModule>();
builder.RegisterModule<AutofacDomainModule>();
builder.RegisterType<OperatorHubInternal>().As<IOperatorHubInternal>().SingleInstance();
RegistrationExtensions.RegisterControllers(builder, typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly).InstancePerRequest();
builder.RegisterHubs(Assembly.GetExecutingAssembly());
var mvcContainer = builder.Build();
return mvcContainer;
}
}

ASP.NET Identity: use GeneratePasswordResetToken on Azure website

I have my web application deployed on Microsoft Azure. However when I want to generate a PasswordResetToken with:
var token = await _userManager.GeneratePasswordResetTokenAsync(user.Id);
I get the following error:
System.Security.Cryptography.CryptographicException: The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.
How do I get this to work on Azure?
Or is there an other way to reset a password without knowing the old password?
This is my UserManager class. Mabey there is an error in it.
public class ApplicationUserManager : UserManager<ApplicationIdentityUser>
{
private static IUnitOfWork _unitOfWork;
private readonly IRepository<ApplicationIdentityUser> _userRepository;
public ApplicationUserManager(IUserStore<ApplicationIdentityUser> store, IRepository<ApplicationIdentityUser> userRepository)
: base(store)
{
if (userRepository == null) throw new ArgumentNullException("userRepository");
_userRepository = userRepository;
if (bool.Parse(ConfigurationManager.AppSettings["RunningInAzure"]))
UserTokenProvider = new EmailTokenProvider<ApplicationIdentityUser, string>();
else
{
var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("TopRijden");
UserTokenProvider = new DataProtectorTokenProvider<ApplicationIdentityUser, string>(provider.Create("Password Reset"));
}
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
if (options == null) throw new ArgumentNullException("options");
if (context == null) throw new ArgumentNullException("context");
try
{
_unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
var userRepository = ObjectFactory.GetInstance<IRepository<ApplicationIdentityUser>>();
var manager = new ApplicationUserManager(new UserStore<ApplicationIdentityUser>(_unitOfWork.Session), userRepository);
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationIdentityUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug in here.
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationIdentityUser>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationIdentityUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is: {0}"
});
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationIdentityUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
catch (Exception ex)
{
ex.Process(MethodBase.GetCurrentMethod().DeclaringType, MethodBase.GetCurrentMethod().Name);
return null;
}
}
}
}
I found a working solution for my own problem based on the answer of trailmax.
In stead of the EmailTokenProvider I use the TotpSecurityStampBasedTokenProvider
public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
{
// other setup
this.UserTokenProvider = new TotpSecurityStampBasedTokenProvider<ApplicationUser, string>();
}
For more information about TotpSecurityStampBasedTokenProvider:
http://msdn.microsoft.com/en-us/library/dn613297(v=vs.108).aspx
Use EmailTokenProvider in UserManager
public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
{
// other setup
this.UserTokenProvider = new EmailTokenProvider<ApplicationUser, string>();
}
I've blogged about it recently.

Moq Roles.AddUserToRole test

I am writing unit tests for a project in ASP.NET MVC 1.0 using Moq and MvcContrib TestHelper classes. I have run into a problem.
When I come to Roles.AddUserToRole in my AccountController, I get a System.NotSupportedException. The Roles class is static and Moq cannot mock a static class.
What can I do?
You could use a pattern like DI (Dependency Injection). In your case, I would pass a RoleProvider to the AccountController, which would be the default RoleProvider by default, and a mock object in your tests. Something like:
public class AccountController
{
private MembershipProvider _provider;
private RoleProvider roleProvider;
public AccountController()
: this(null, null)
{
}
public AccountController(MembershipProvider provider, RoleProvider roleProvider)
{
_provider = provider ?? Membership.Provider;
this.roleProvider = roleProvider ?? System.Web.Security.Roles.Provider;
}
}
The MVC runtime will call the default constructor, which in turn will initialize the AccountController with the default role provider. In your unit test, you can directly call the overloaded constructor, and pass a MockRoleProvider (or use Moq to create it for you):
[Test]
public void AccountControllerTest()
{
AccountController controller = new AccountController(new MockMembershipProvider(), new MockRoleProvider());
}
EDIT: And here's how I mocked the entire HttpContext, including the principal user.
To get a Moq version of the HttpContext:
public static HttpContextBase GetHttpContext(IPrincipal principal)
{
var httpContext = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = principal;
httpContext.Setup(ctx => ctx.Request).Returns(request.Object);
httpContext.Setup(ctx => ctx.Response).Returns(response.Object);
httpContext.Setup(ctx => ctx.Session).Returns(session.Object);
httpContext.Setup(ctx => ctx.Server).Returns(server.Object);
httpContext.Setup(ctx => ctx.User).Returns(user);
return httpContext.Object;
}
A mock implementation of Principal:
public class MockPrincipal : IPrincipal
{
private IIdentity _identity;
private readonly string[] _roles;
public MockPrincipal(IIdentity identity, string[] roles)
{
_identity = identity;
_roles = roles;
}
public IIdentity Identity
{
get { return _identity; }
set { this._identity = value; }
}
public bool IsInRole(string role)
{
if (_roles == null)
return false;
return _roles.Contains(role);
}
}
A MockIdentity:
public class MockIdentity : IIdentity
{
private readonly string _name;
public MockIdentity(string userName) {
_name = userName;
}
public override string AuthenticationType
{
get { throw new System.NotImplementedException(); }
}
public override bool IsAuthenticated
{
get { return !String.IsNullOrEmpty(_name); }
}
public override string Name
{
get { return _name; }
}
}
And the magic call:
MockIdentity identity = new MockIdentity("JohnDoe");
var httpContext = MoqHelpers.GetHttpContext(new MockPrincipal(identity, null));
Note that I edited the code above to leave out some custom stuff, but I'm quite sure this should still work.
Now I run into another problem when I try to test the ChangePassword() method in ASP.NET MVC.
try
{
if (MembershipService.ChangePassword(User.Identity.Name, currentPassword, newPassword))
{
if (!TempData.ContainsKey("ChangePassword_success"))
{
TempData.Add("ChangePassword_success", true);
}
return PartialView("ChangePassword");
}
Now I get that User is null, when I reach this line. In my testclass I have:
mockMembershipService.Setup(cp => cp.ChangePassword("johndoe", currentPassword, newPassword)).Returns(true);
I thought that this would work, but it doesn't care for that I send "johndoe". And If I were to mock IPrincipal, the User property is readonly.
TypeMock Isolator does mocking of statics etc. But I second (and +1'd) Razzie's answer.
I have done what you coded, but I still get that User is null when it reaches:
mockMembershipService.Setup(cp => cp.ChangePassword("johndoe", currentPassword, newPassword)).Returns(true);
In my Testclass I have:
//Arrange (Set up a scenario)
var mockMembershipService = new Mock<IMembershipService>();
MockIdentity identity = new MockIdentity("JohnDoe");
var httpContext = MoqHelpers.GetHttpContext(new MockPrincipal(identity, null));
var controller = new AccountController(null, mockMembershipService.Object, null, null, null);
string currentPassword = "qwerty";
string newPassword = "123456";
string confirmPassword = "123456";
// Expectations
mockMembershipService.Setup(pw => pw.MinPasswordLength).Returns(6);
mockMembershipService.Setup(cp => cp.ChangePassword("johndoe", currentPassword, newPassword)).Returns(true);
Do I call my cp.ChangePassword with wrong parameters? And should MVCContrib Testhelpers classes be able to mock Http context and so on? I just can't find info for how to setup User.Identity.Name with MVCContrib.
I have used this from a tutorial to test something (mock) session:
var builder = new TestControllerBuilder();
var controller = new AccountController(mockFormsAuthentication.Object, mockMembershipService.Object, mockUserRepository.Object, null, mockBandRepository.Object);
builder.InitializeController(controller);
EDIT: I have come a little further:
MockIdentity identity = new MockIdentity("JohnDoe");
var httpContext = MoqHelpers.GetHttpContext(new MockPrincipal(identity, null));
var controller = new AccountController(null, mockMembershipService.Object, null, null, null);
controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
but my now I can't get my cp.ChangePassword in the expectation to return true:
mockMembershipService.Setup(cp => cp.ChangePassword("johndoe", currentPassword, newPassword)).Returns(true);
I am sending "johndoe" string, because, it requires a string as a parameter for User.Identity.Name, but it doesn't return true.

Resources