)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
Integrated Applications Programming Company
Home » Code Library » AccountController (Ia.Wa.Controllers)

Public general use code classes and xml files that we've compiled and used over the years:

    1: using System.Security.Claims;
    2: using Ia.Wa.Models.AccountViewModels;
    3: using IdentitySample.Services;
    4: using Microsoft.AspNetCore.Authorization;
    5: using Microsoft.AspNetCore.Identity;
    6: using Microsoft.AspNetCore.Mvc;
    7: using Microsoft.AspNetCore.Mvc.Rendering;
    8:  
    9: namespace Ia.Wa.Controllers
   10: {
   11:     ////////////////////////////////////////////////////////////////////////////
   12:  
   13:     /// <summary publish="true">
   14:     ///
   15:     /// </summary>
   16:     /// 
   17:     /// <remarks> 
   18:     /// Copyright � 2006-2025 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
   19:     ///
   20:     /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   21:     /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   22:     ///
   23:     /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   24:     /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   25:     /// 
   26:     /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
   27:     /// 
   28:     /// Copyright notice: This notice may not be removed or altered from any source distribution.
   29:     /// </remarks> 
   30:     [Authorize]
   31:     public class AccountController : Controller
   32:     {
   33:         private readonly UserManager<IdentityUser> _userManager;
   34:         private readonly SignInManager<IdentityUser> _signInManager;
   35:         private readonly IEmailSender _emailSender;
   36:         private readonly ISmsSender _smsSender;
   37:         private readonly ILogger _logger;
   38:  
   39:         public AccountController(
   40:             UserManager<IdentityUser> userManager,
   41:             SignInManager<IdentityUser> signInManager,
   42:             IEmailSender emailSender,
   43:             ISmsSender smsSender,
   44:             ILoggerFactory loggerFactory)
   45:         {
   46:             _userManager = userManager;
   47:             _signInManager = signInManager;
   48:             _emailSender = emailSender;
   49:             _smsSender = smsSender;
   50:             _logger = loggerFactory.CreateLogger<AccountController>();
   51:         }
   52:  
   53:         //
   54:         // GET: /Account
   55:         [HttpGet]
   56:         [AllowAnonymous]
   57:         [Route("identity/account")]
   58:         public IActionResult Index(string returnUrl = null)
   59:         {
   60:             ViewData["ReturnUrl"] = returnUrl;
   61:  
   62:             return View();
   63:         }
   64:  
   65:         //
   66:         // GET: /Account/Login
   67:         [HttpGet]
   68:         [AllowAnonymous]
   69:         [Route("identity/account/login")]
   70:         public IActionResult Login(string returnUrl = null)
   71:         {
   72:             ViewData["ReturnUrl"] = returnUrl;
   73:             return View();
   74:         }
   75:  
   76:         //
   77:         // POST: /Account/Login
   78:         [HttpPost]
   79:         [AllowAnonymous]
   80:         [ValidateAntiForgeryToken]
   81:         [Route("identity/account/login")]
   82:         public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
   83:         {
   84:             ViewData["ReturnUrl"] = returnUrl;
   85:             if (ModelState.IsValid)
   86:             {
   87:                 // This doesn't count login failures towards account lockout
   88:                 // To enable password failures to trigger account lockout, set lockoutOnFailure: true
   89:                 var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
   90:                 if (result.Succeeded)
   91:                 {
   92:                     _logger.LogInformation(1, "User logged in.");
   93:                     return RedirectToLocal(returnUrl);
   94:                 }
   95:                 if (result.RequiresTwoFactor)
   96:                 {
   97:                     return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
   98:                 }
   99:                 if (result.IsLockedOut)
  100:                 {
  101:                     _logger.LogWarning(2, "User account locked out.");
  102:                     return View("Lockout");
  103:                 }
  104:                 else
  105:                 {
  106:                     ModelState.AddModelError(string.Empty, "Invalid login attempt.");
  107:                     return View(model);
  108:                 }
  109:             }
  110:  
  111:             // If we got this far, something failed, redisplay form
  112:             return View(model);
  113:         }
  114:  
  115:         //
  116:         // GET: /Account/Register
  117:         [HttpGet]
  118:         [AllowAnonymous]
  119:         [Route("identity/account/register")]
  120:         public IActionResult Register(string returnUrl = null)
  121:         {
  122:             ViewData["ReturnUrl"] = returnUrl;
  123:             return View();
  124:         }
  125:  
  126:         //
  127:         // POST: /Account/Register
  128:         [HttpPost]
  129:         [AllowAnonymous]
  130:         [ValidateAntiForgeryToken]
  131:         [Route("identity/account/register")]
  132:         public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
  133:         {
  134:             ViewData["ReturnUrl"] = returnUrl;
  135:             if (ModelState.IsValid)
  136:             {
  137:                 var user = new IdentityUser { UserName = model.Email, Email = model.Email };
  138:                 var result = await _userManager.CreateAsync(user, model.Password);
  139:                 if (result.Succeeded)
  140:                 {
  141:                     // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
  142:                     // Send an email with this link
  143:                     //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
  144:                     //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
  145:                     //await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
  146:                     //    "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
  147:                     await _signInManager.SignInAsync(user, isPersistent: false);
  148:                     _logger.LogInformation(3, "User created a new account with password.");
  149:                     return RedirectToLocal(returnUrl);
  150:                 }
  151:                 AddErrors(result);
  152:             }
  153:  
  154:             // If we got this far, something failed, redisplay form
  155:             return View(model);
  156:         }
  157:  
  158:         //
  159:         // POST: /Account/LogOff
  160:         [HttpPost]
  161:         [ValidateAntiForgeryToken]
  162:         [Route("identity/account/logoff")]
  163:         public async Task<IActionResult> LogOff()
  164:         {
  165:             await _signInManager.SignOutAsync();
  166:             _logger.LogInformation(4, "User logged out.");
  167:             return RedirectToAction(nameof(HomeController.Index), "Home");
  168:         }
  169:  
  170:         //
  171:         // POST: /Account/ExternalLogin
  172:         [HttpPost]
  173:         [AllowAnonymous]
  174:         [ValidateAntiForgeryToken]
  175:         [Route("identity/account/external-login")]
  176:         public IActionResult ExternalLogin(string provider, string returnUrl = null)
  177:         {
  178:             // Request a redirect to the external login provider.
  179:             var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
  180:             var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
  181:             return Challenge(properties, provider);
  182:         }
  183:  
  184:         //
  185:         // GET: /Account/ExternalLoginCallback
  186:         [HttpGet]
  187:         [AllowAnonymous]
  188:         [Route("identity/account/external-login-callback")]
  189:         public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
  190:         {
  191:             if (remoteError != null)
  192:             {
  193:                 ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
  194:                 return View(nameof(Login));
  195:             }
  196:             var info = await _signInManager.GetExternalLoginInfoAsync();
  197:             if (info == null)
  198:             {
  199:                 return RedirectToAction(nameof(Login));
  200:             }
  201:  
  202:             // Sign in the user with this external login provider if the user already has a login.
  203:             var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
  204:             if (result.Succeeded)
  205:             {
  206:                 // Update any authentication tokens if login succeeded
  207:                 await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
  208:  
  209:                 _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
  210:                 return RedirectToLocal(returnUrl);
  211:             }
  212:             if (result.RequiresTwoFactor)
  213:             {
  214:                 return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
  215:             }
  216:             if (result.IsLockedOut)
  217:             {
  218:                 return View("Lockout");
  219:             }
  220:             else
  221:             {
  222:                 // If the user does not have an account, then ask the user to create an account.
  223:                 ViewData["ReturnUrl"] = returnUrl;
  224:                 ViewData["ProviderDisplayName"] = info.ProviderDisplayName;
  225:                 var email = info.Principal.FindFirstValue(ClaimTypes.Email);
  226:                 return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
  227:             }
  228:         }
  229:  
  230:         //
  231:         // POST: /Account/ExternalLoginConfirmation
  232:         [HttpPost]
  233:         [AllowAnonymous]
  234:         [ValidateAntiForgeryToken]
  235:         [Route("identity/account/external-login-confirmation")]
  236:         public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
  237:         {
  238:             if (ModelState.IsValid)
  239:             {
  240:                 // Get the information about the user from the external login provider
  241:                 var info = await _signInManager.GetExternalLoginInfoAsync();
  242:                 if (info == null)
  243:                 {
  244:                     return View("ExternalLoginFailure");
  245:                 }
  246:                 var user = new IdentityUser { UserName = model.Email, Email = model.Email };
  247:                 var result = await _userManager.CreateAsync(user);
  248:                 if (result.Succeeded)
  249:                 {
  250:                     result = await _userManager.AddLoginAsync(user, info);
  251:                     if (result.Succeeded)
  252:                     {
  253:                         await _signInManager.SignInAsync(user, isPersistent: false);
  254:                         _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
  255:  
  256:                         // Update any authentication tokens as well
  257:                         await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
  258:  
  259:                         return RedirectToLocal(returnUrl);
  260:                     }
  261:                 }
  262:                 AddErrors(result);
  263:             }
  264:  
  265:             ViewData["ReturnUrl"] = returnUrl;
  266:             return View(model);
  267:         }
  268:  
  269:         // GET: /Account/ConfirmEmail
  270:         [HttpGet]
  271:         [AllowAnonymous]
  272:         [Route("identity/account/confirm-email")]
  273:         public async Task<IActionResult> ConfirmEmail(string userId, string code)
  274:         {
  275:             if (userId == null || code == null)
  276:             {
  277:                 return View("Error");
  278:             }
  279:             var user = await _userManager.FindByIdAsync(userId);
  280:             if (user == null)
  281:             {
  282:                 return View("Error");
  283:             }
  284:             var result = await _userManager.ConfirmEmailAsync(user, code);
  285:             return View(result.Succeeded ? "ConfirmEmail" : "Error");
  286:         }
  287:  
  288:         //
  289:         // GET: /Account/ForgotPassword
  290:         [HttpGet]
  291:         [AllowAnonymous]
  292:         [Route("identity/account/forgot-password")]
  293:         public IActionResult ForgotPassword()
  294:         {
  295:             return View();
  296:         }
  297:  
  298:         //
  299:         // POST: /Account/ForgotPassword
  300:         [HttpPost]
  301:         [AllowAnonymous]
  302:         [ValidateAntiForgeryToken]
  303:         [Route("identity/account/forgot-password")]
  304:         public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
  305:         {
  306:             if (ModelState.IsValid)
  307:             {
  308:                 var user = await _userManager.FindByEmailAsync(model.Email);
  309:                 if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
  310:                 {
  311:                     // Don't reveal that the user does not exist or is not confirmed
  312:                     return View("ForgotPasswordConfirmation");
  313:                 }
  314:  
  315:                 // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
  316:                 // Send an email with this link
  317:                 //var code = await _userManager.GeneratePasswordResetTokenAsync(user);
  318:                 //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
  319:                 //await _emailSender.SendEmailAsync(model.Email, "Reset Password",
  320:                 //   "Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
  321:                 //return View("ForgotPasswordConfirmation");
  322:             }
  323:  
  324:             // If we got this far, something failed, redisplay form
  325:             return View(model);
  326:         }
  327:  
  328:         //
  329:         // GET: /Account/ForgotPasswordConfirmation
  330:         [HttpGet]
  331:         [AllowAnonymous]
  332:         [Route("identity/account/forgot-password-confirmation")]
  333:         public IActionResult ForgotPasswordConfirmation()
  334:         {
  335:             return View();
  336:         }
  337:  
  338:         //
  339:         // GET: /Account/ResetPassword
  340:         [HttpGet]
  341:         [AllowAnonymous]
  342:         [Route("identity/account/reset-password")]
  343:         public IActionResult ResetPassword(string code = null)
  344:         {
  345:             return code == null ? View("Error") : View();
  346:         }
  347:  
  348:         //
  349:         // POST: /Account/ResetPassword
  350:         [HttpPost]
  351:         [AllowAnonymous]
  352:         [ValidateAntiForgeryToken]
  353:         [Route("identity/account/reset-password")]
  354:         public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
  355:         {
  356:             if (!ModelState.IsValid)
  357:             {
  358:                 return View(model);
  359:             }
  360:             var user = await _userManager.FindByEmailAsync(model.Email);
  361:             if (user == null)
  362:             {
  363:                 // Don't reveal that the user does not exist
  364:                 return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
  365:             }
  366:             var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
  367:             if (result.Succeeded)
  368:             {
  369:                 return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
  370:             }
  371:             AddErrors(result);
  372:             return View();
  373:         }
  374:  
  375:         //
  376:         // GET: /Account/ResetPasswordConfirmation
  377:         [HttpGet]
  378:         [AllowAnonymous]
  379:         [Route("identity/account/reset-password-confirmation")]
  380:         public IActionResult ResetPasswordConfirmation()
  381:         {
  382:             return View();
  383:         }
  384:  
  385:         //
  386:         // GET: /Account/SendCode
  387:         [HttpGet]
  388:         [AllowAnonymous]
  389:         [Route("identity/account/send-code")]
  390:         public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
  391:         {
  392:             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
  393:             if (user == null)
  394:             {
  395:                 return View("Error");
  396:             }
  397:             var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
  398:             var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
  399:             return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
  400:         }
  401:  
  402:         //
  403:         // POST: /Account/SendCode
  404:         [HttpPost]
  405:         [AllowAnonymous]
  406:         [ValidateAntiForgeryToken]
  407:         [Route("identity/account/send-code")]
  408:         public async Task<IActionResult> SendCode(SendCodeViewModel model)
  409:         {
  410:             if (!ModelState.IsValid)
  411:             {
  412:                 return View();
  413:             }
  414:  
  415:             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
  416:             if (user == null)
  417:             {
  418:                 return View("Error");
  419:             }
  420:  
  421:             if (model.SelectedProvider == "Authenticator")
  422:             {
  423:                 return RedirectToAction(nameof(VerifyAuthenticatorCode), new { ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
  424:             }
  425:  
  426:             // Generate the token and send it
  427:             var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
  428:             if (string.IsNullOrWhiteSpace(code))
  429:             {
  430:                 return View("Error");
  431:             }
  432:  
  433:             var message = "Your security code is: " + code;
  434:             if (model.SelectedProvider == "Email")
  435:             {
  436:                 await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message);
  437:             }
  438:             else if (model.SelectedProvider == "Phone")
  439:             {
  440:                 await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message);
  441:             }
  442:  
  443:             return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
  444:         }
  445:  
  446:         //
  447:         // GET: /Account/VerifyCode
  448:         [HttpGet]
  449:         [AllowAnonymous]
  450:         [Route("identity/account/verify-code")]
  451:         public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
  452:         {
  453:             // Require that the user has already logged in via username/password or external login
  454:             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
  455:             if (user == null)
  456:             {
  457:                 return View("Error");
  458:             }
  459:             return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
  460:         }
  461:  
  462:         //
  463:         // POST: /Account/VerifyCode
  464:         [HttpPost]
  465:         [AllowAnonymous]
  466:         [ValidateAntiForgeryToken]
  467:         [Route("identity/account/verify-code")]
  468:         public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
  469:         {
  470:             if (!ModelState.IsValid)
  471:             {
  472:                 return View(model);
  473:             }
  474:  
  475:             // The following code protects for brute force attacks against the two factor codes.
  476:             // If a user enters incorrect codes for a specified amount of time then the user account
  477:             // will be locked out for a specified amount of time.
  478:             var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
  479:             if (result.Succeeded)
  480:             {
  481:                 return RedirectToLocal(model.ReturnUrl);
  482:             }
  483:             if (result.IsLockedOut)
  484:             {
  485:                 _logger.LogWarning(7, "User account locked out.");
  486:                 return View("Lockout");
  487:             }
  488:             else
  489:             {
  490:                 ModelState.AddModelError(string.Empty, "Invalid code.");
  491:                 return View(model);
  492:             }
  493:         }
  494:  
  495:         //
  496:         // GET: /Account/VerifyAuthenticatorCode
  497:         [HttpGet]
  498:         [AllowAnonymous]
  499:         [Route("identity/account/verify-authenticator-code")]
  500:         public async Task<IActionResult> VerifyAuthenticatorCode(bool rememberMe, string returnUrl = null)
  501:         {
  502:             // Require that the user has already logged in via username/password or external login
  503:             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
  504:             if (user == null)
  505:             {
  506:                 return View("Error");
  507:             }
  508:             return View(new VerifyAuthenticatorCodeViewModel { ReturnUrl = returnUrl, RememberMe = rememberMe });
  509:         }
  510:  
  511:         //
  512:         // POST: /Account/VerifyAuthenticatorCode
  513:         [HttpPost]
  514:         [AllowAnonymous]
  515:         [ValidateAntiForgeryToken]
  516:         [Route("identity/account/verify-authenticator-code")]
  517:         public async Task<IActionResult> VerifyAuthenticatorCode(VerifyAuthenticatorCodeViewModel model)
  518:         {
  519:             if (!ModelState.IsValid)
  520:             {
  521:                 return View(model);
  522:             }
  523:  
  524:             // The following code protects for brute force attacks against the two factor codes.
  525:             // If a user enters incorrect codes for a specified amount of time then the user account
  526:             // will be locked out for a specified amount of time.
  527:             var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.Code, model.RememberMe, model.RememberBrowser);
  528:             if (result.Succeeded)
  529:             {
  530:                 return RedirectToLocal(model.ReturnUrl);
  531:             }
  532:             if (result.IsLockedOut)
  533:             {
  534:                 _logger.LogWarning(7, "User account locked out.");
  535:                 return View("Lockout");
  536:             }
  537:             else
  538:             {
  539:                 ModelState.AddModelError(string.Empty, "Invalid code.");
  540:                 return View(model);
  541:             }
  542:         }
  543:  
  544:         //
  545:         // GET: /Account/UseRecoveryCode
  546:         [HttpGet]
  547:         [AllowAnonymous]
  548:         [Route("identity/account/use-recovery-code")]
  549:         public async Task<IActionResult> UseRecoveryCode(string returnUrl = null)
  550:         {
  551:             // Require that the user has already logged in via username/password or external login
  552:             var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
  553:             if (user == null)
  554:             {
  555:                 return View("Error");
  556:             }
  557:             return View(new UseRecoveryCodeViewModel { ReturnUrl = returnUrl });
  558:         }
  559:  
  560:         //
  561:         // POST: /Account/UseRecoveryCode
  562:         [HttpPost]
  563:         [AllowAnonymous]
  564:         [ValidateAntiForgeryToken]
  565:         [Route("identity/account/use-recovery-code")]
  566:         public async Task<IActionResult> UseRecoveryCode(UseRecoveryCodeViewModel model)
  567:         {
  568:             if (!ModelState.IsValid)
  569:             {
  570:                 return View(model);
  571:             }
  572:  
  573:             var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(model.Code);
  574:             if (result.Succeeded)
  575:             {
  576:                 return RedirectToLocal(model.ReturnUrl);
  577:             }
  578:             else
  579:             {
  580:                 ModelState.AddModelError(string.Empty, "Invalid code.");
  581:                 return View(model);
  582:             }
  583:         }
  584:  
  585:         #region Helpers
  586:  
  587:         private void AddErrors(IdentityResult result)
  588:         {
  589:             foreach (var error in result.Errors)
  590:             {
  591:                 ModelState.AddModelError(string.Empty, error.Description);
  592:             }
  593:         }
  594:  
  595:         private Task<IdentityUser> GetCurrentUserAsync()
  596:         {
  597:             return _userManager.GetUserAsync(HttpContext.User);
  598:         }
  599:  
  600:         private IActionResult RedirectToLocal(string returnUrl)
  601:         {
  602:             if (Url.IsLocalUrl(returnUrl))
  603:             {
  604:                 return Redirect(returnUrl);
  605:             }
  606:             else
  607:             {
  608:                 return RedirectToAction(nameof(HomeController.Index), "Home");
  609:             }
  610:         }
  611:  
  612:         #endregion
  613:     }
  614: }