public async Task<ActionResult> Register(RegisterViewModel model)
        {
            var timeout = this.GetTimeoutToken();

            var validationContext = new ValidationContext();
            model.Validate(validationContext);
            if (validationContext.HasErrors)
            {
                this.AddModelStateError(validationContext);
                return await this.View(model, timeout);
            }

            var account = new Account
            {
                IdentityType = IdentityType.EmailAddress,
                IdentityValue = model.EmailAddress.Trim().ToLowerInvariant(),
                CreationTime = Clock.UtcNow,
                Name = model.Name.Trim(),
                PasswordHash = BCrypt.Net.BCrypt.HashPassword(model.Password),
            };

            try
            {
                await this.accountStore.Insert(account, this.GetTimeoutToken());
                await this.CreateNewSession(account, false, timeout);
                return this.RedirectToAction("Index", "Home");
            }
            catch (DuplicateKeyException)
            {
                validationContext.AddError(nameof(model.EmailAddress), "This email address is already in use.");
                this.AddModelStateError(validationContext);
                return await this.View(model, timeout);
            }
        }
        public async Task<ActionResult> Login(LoginViewModel model)
        {
            var timeout = this.GetTimeoutToken();

            var validationContext = new ValidationContext();
            model.Validate(validationContext);
            if (validationContext.HasErrors)
            {
                this.AddModelStateError(validationContext);
                return await this.View(model, timeout);
            }

            var account = new Account
            {
                IdentityType = IdentityType.EmailAddress,
                IdentityValue = model.EmailAddress.Trim().ToLowerInvariant(),
            };

            account = await this.accountStore.Get(account.PartitionKey, account.RowKey, timeout);
            if (account == null || BCrypt.Net.BCrypt.Verify(model.Password, account.PasswordHash) == false)
            {
                validationContext.AddError("Cannot find a matching account and password. Please try again!");
                this.AddModelStateError(validationContext);
                return await this.View(model, timeout);
            }

            await this.CreateNewSession(account, model.RememberMe, timeout);
            return this.RedirectToAction("Index", "Home");
        }
        private async Task CreateNewSession(Account account, bool rememberMe, CancellationToken cancellationToken)
        {
            var session = new Session
            {
                AccountId = account.AccountId,
                AccountName = account.Name,
                AccountIdentity = account.IdentityValue,
                CreationTime = Clock.UtcNow,
                ExpirationTime = DateTime.MaxValue,
                SessionId = Guid.NewGuid().ToString(),
            };

            await this.sessionStore.Insert(session, cancellationToken);

            var cookie = new HttpCookie(SessionIdKey, session.SessionId)
            {
                Expires = Clock.UtcNow + (rememberMe ? TimeSpan.FromDays(7) : TimeSpan.FromHours(2)),
            };

            this.Response.SetCookie(cookie);
        }