Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You can test your controllers and much of your custom provider by refactoring your custom membership code into a two layers: a data access repository that only interacts with the database, and a service layer that uses repository components to provide the Membership API. The service layer is where you would validate arguments, hold and enforce parameters like EnablePasswordReset and translate any database exceptions or status codes into a form suitable for controller consumption.</p> <p>When you specify each layer with its own interface, consumers can write to that interface regardless of how its implemented. When your app is running your provider is of course talking to the database through these interfaces but for testing you can mock the repository or service interfaces. You can test your service layer by mocking the repository level without have to mess with the database or the web.config file, and you can test your controllers by mocking the service layer. If you don't want to refactor the whole provider, you can still test your controllers if you only create the service interface and have your controllers use it.</p> <p>To be specific, if a little verbose, your repository and service interfaces might look something like:</p> <pre><code>namespace Domain.Abstract { public interface IRepository { string ConnectionString { get; } } } namespace Domain.Abstract { public interface IUserRepository : IRepository { MembershipUser CreateUser(Guid userId, string userName, string password, PasswordFormat passwordFormat, string passwordSalt, string email, string passwordQuestion, string passwordAnswer, bool isApproved, DateTime currentTimeUtc, bool uniqueEmail); MembershipUser GetUser(Guid userId, bool updateLastActivity, DateTime currentTimeUtc); PasswordData GetPasswordData(Guid userId, bool updateLastLoginActivity, DateTime currentTimeUtc); void UpdatePasswordStatus(Guid userId, bool isAuthenticated, int maxInvalidPasswordAttempts, int passwordAttemptWindow, DateTime currentTimeUtc, bool updateLastLoginActivity, DateTime lastLoginDate, DateTime lastActivityDate); //.... } } namespace Domain.Abstract { public interface IUserService { bool EnablePasswordRetrieval { get; } bool EnablePasswordReset { get; } bool RequiresQuestionAndAnswer { get; } bool RequiresUniqueEmail { get; } //.... MembershipUser CreateUser(string applicationName, string userName, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved); MembershipUser GetUser(Guid userId, bool userIsOnline); bool ValidateUser(Guid userId, string password); //... } } namespace Domain.Concrete { public class UserService : IUserService { private IUserRepository _userRepository; public UserService(IUserRepository userRepository) { _userRepository = userRepository; } //... public bool ValidateUser(Guid userId, string password) { // validate applicationName and password here bool ret = false; try { PasswordData passwordData; ret = CheckPassword(userId, true, true, DateTime.UtcNow, out passwordData); } catch (ObjectLockedException e) { throw new RulesException("userName", Resource.User_AccountLockOut); } return ret; } private bool CheckPassword(Guid userId, string password, bool updateLastLoginActivityDate, bool failIfNotApproved, DateTime currentTimeUtc, out PasswordData passwordData) { passwordData = _userRepository.GetPasswordData(userId, updateLastLoginActivityDate, currentTimeUtc); if (!passwordData.IsApproved &amp;&amp; failIfNotApproved) return false; string encodedPassword = EncodePassword(password, passwordData.PasswordFormat, passwordData.PasswordSalt); bool isAuthenticated = passwordData.Password.Equals(encodedPassword); if (isAuthenticated &amp;&amp; passwordData.FailedPasswordAttemptCount == 0 &amp;&amp; passwordData.FailedPasswordAnswerAttemptCount == 0) return true; _userRepository.UpdatePasswordStatus(userId, isAuthenticated, _maxInvalidPasswordAttempts, _passwordAttemptWindow, currentTimeUtc, updateLastLoginActivityDate, isAuthenticated ? currentTimeUtc : passwordData.LastLoginDate, isAuthenticated ? currentTimeUtc : passwordData.LastActivityDate); return isAuthenticated; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload