You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by dp...@apache.org on 2017/06/22 20:47:52 UTC

[04/10] logging-log4net git commit: Add test web app for asp extension

Add test web app for asp extension


Project: http://git-wip-us.apache.org/repos/asf/logging-log4net/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4net/commit/5e667994
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4net/tree/5e667994
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4net/diff/5e667994

Branch: refs/heads/pr/old/32
Commit: 5e667994dd8bed50087b1948d4550d5f6e95aaac
Parents: 85d581e
Author: Peter Jas <ne...@yahoo.com>
Authored: Sun Aug 21 00:51:56 2016 +0000
Committer: Dominik Psenner <dp...@apache.org>
Committed: Thu Jun 22 22:11:35 2017 +0200

----------------------------------------------------------------------
 .../log4net.Extensions.Logging.Test/.bowerrc    |   3 +
 .../log4net.Extensions.Logging.Test/.gitignore  | 234 ++++++++++
 .../Controllers/AccountController.cs            | 468 +++++++++++++++++++
 .../Controllers/HomeController.cs               |  35 ++
 .../Controllers/ManageController.cs             | 347 ++++++++++++++
 .../Data/ApplicationDbContext.cs                |  26 ++
 ...00000000000_CreateIdentitySchema.Designer.cs | 212 +++++++++
 .../00000000000000_CreateIdentitySchema.cs      | 215 +++++++++
 .../ApplicationDbContextModelSnapshot.cs        | 211 +++++++++
 .../ExternalLoginConfirmationViewModel.cs       |  15 +
 .../ForgotPasswordViewModel.cs                  |  15 +
 .../Models/AccountViewModels/LoginViewModel.cs  |  22 +
 .../AccountViewModels/RegisterViewModel.cs      |  27 ++
 .../AccountViewModels/ResetPasswordViewModel.cs |  27 ++
 .../AccountViewModels/SendCodeViewModel.cs      |  19 +
 .../AccountViewModels/VerifyCodeViewModel.cs    |  25 +
 .../Models/ApplicationUser.cs                   |  13 +
 .../ManageViewModels/AddPhoneNumberViewModel.cs |  16 +
 .../ManageViewModels/ChangePasswordViewModel.cs |  27 ++
 .../ConfigureTwoFactorViewModel.cs              |  15 +
 .../Models/ManageViewModels/FactorViewModel.cs  |  12 +
 .../Models/ManageViewModels/IndexViewModel.cs   |  21 +
 .../ManageViewModels/ManageLoginsViewModel.cs   |  16 +
 .../ManageViewModels/RemoveLoginViewModel.cs    |  14 +
 .../ManageViewModels/SetPasswordViewModel.cs    |  22 +
 .../VerifyPhoneNumberViewModel.cs               |  19 +
 .../log4net.Extensions.Logging.Test/Program.cs  |  24 +
 .../log4net.Extensions.Logging.Test/README.md   |  39 ++
 .../Services/IEmailSender.cs                    |  12 +
 .../Services/ISmsSender.cs                      |  12 +
 .../Services/MessageServices.cs                 |  25 +
 .../Settings/logconfig.xml                      |   6 +
 .../log4net.Extensions.Logging.Test/Startup.cs  |  92 ++++
 .../Views/Account/ConfirmEmail.cshtml           |  10 +
 .../Account/ExternalLoginConfirmation.cshtml    |  35 ++
 .../Views/Account/ExternalLoginFailure.cshtml   |   8 +
 .../Views/Account/ForgotPassword.cshtml         |  31 ++
 .../Account/ForgotPasswordConfirmation.cshtml   |   8 +
 .../Views/Account/Lockout.cshtml                |   8 +
 .../Views/Account/Login.cshtml                  |  92 ++++
 .../Views/Account/Register.cshtml               |  42 ++
 .../Views/Account/ResetPassword.cshtml          |  43 ++
 .../Account/ResetPasswordConfirmation.cshtml    |   8 +
 .../Views/Account/SendCode.cshtml               |  21 +
 .../Views/Account/VerifyCode.cshtml             |  38 ++
 .../Views/Home/About.cshtml                     |   7 +
 .../Views/Home/Contact.cshtml                   |  17 +
 .../Views/Home/Index.cshtml                     | 109 +++++
 .../Views/Manage/AddPhoneNumber.cshtml          |  27 ++
 .../Views/Manage/ChangePassword.cshtml          |  42 ++
 .../Views/Manage/Index.cshtml                   |  71 +++
 .../Views/Manage/ManageLogins.cshtml            |  54 +++
 .../Views/Manage/SetPassword.cshtml             |  38 ++
 .../Views/Manage/VerifyPhoneNumber.cshtml       |  30 ++
 .../Views/Shared/Error.cshtml                   |  14 +
 .../Views/Shared/_Layout.cshtml                 |  68 +++
 .../Views/Shared/_LoginPartial.cshtml           |  26 ++
 .../Shared/_ValidationScriptsPartial.cshtml     |  14 +
 .../Views/_ViewImports.cshtml                   |   6 +
 .../Views/_ViewStart.cshtml                     |   3 +
 .../appsettings.json                            |  13 +
 .../log4net.Extensions.Logging.Test/bower.json  |  10 +
 .../log4net.Extensions.Logging.Test/gulpfile.js |  45 ++
 .../package.json                                |  12 +
 .../project.json                                | 108 +++++
 .../log4net.Extensions.Logging.Test/web.config  |  14 +
 .../wwwroot/css/site.css                        |  44 ++
 .../wwwroot/css/site.min.css                    |   1 +
 .../wwwroot/favicon.ico                         | Bin 0 -> 32038 bytes
 .../wwwroot/images/banner1.svg                  |   1 +
 .../wwwroot/images/banner2.svg                  |   1 +
 .../wwwroot/images/banner3.svg                  |   1 +
 .../wwwroot/images/banner4.svg                  |   1 +
 .../wwwroot/js/site.js                          |   1 +
 .../wwwroot/js/site.min.js                      |   0
 75 files changed, 3408 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.bowerrc
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.bowerrc b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.bowerrc
new file mode 100644
index 0000000..6406626
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "wwwroot/lib"
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.gitignore
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.gitignore b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.gitignore
new file mode 100644
index 0000000..0ca27f0
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/.gitignore
@@ -0,0 +1,234 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Microsoft Azure ApplicationInsights config file
+ApplicationInsights.config
+
+# Windows Store app package directory
+AppPackages/
+BundleArtifacts/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+
+# FAKE - F# Make
+.fake/

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/AccountController.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/AccountController.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/AccountController.cs
new file mode 100644
index 0000000..035638a
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/AccountController.cs
@@ -0,0 +1,468 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.Extensions.Logging;
+using WebApplication.Models;
+using WebApplication.Models.AccountViewModels;
+using WebApplication.Services;
+
+namespace WebApplication.Controllers
+{
+    [Authorize]
+    public class AccountController : Controller
+    {
+        private readonly UserManager<ApplicationUser> _userManager;
+        private readonly SignInManager<ApplicationUser> _signInManager;
+        private readonly IEmailSender _emailSender;
+        private readonly ISmsSender _smsSender;
+        private readonly ILogger _logger;
+
+        public AccountController(
+            UserManager<ApplicationUser> userManager,
+            SignInManager<ApplicationUser> signInManager,
+            IEmailSender emailSender,
+            ISmsSender smsSender,
+            ILoggerFactory loggerFactory)
+        {
+            _userManager = userManager;
+            _signInManager = signInManager;
+            _emailSender = emailSender;
+            _smsSender = smsSender;
+            _logger = loggerFactory.CreateLogger<AccountController>();
+        }
+
+        //
+        // GET: /Account/Login
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult Login(string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            return View();
+        }
+
+        //
+        // POST: /Account/Login
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            if (ModelState.IsValid)
+            {
+                // This doesn't count login failures towards account lockout
+                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
+                var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
+                if (result.Succeeded)
+                {
+                    _logger.LogInformation(1, "User logged in.");
+                    return RedirectToLocal(returnUrl);
+                }
+                if (result.RequiresTwoFactor)
+                {
+                    return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
+                }
+                if (result.IsLockedOut)
+                {
+                    _logger.LogWarning(2, "User account locked out.");
+                    return View("Lockout");
+                }
+                else
+                {
+                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
+                    return View(model);
+                }
+            }
+
+            // If we got this far, something failed, redisplay form
+            return View(model);
+        }
+
+        //
+        // GET: /Account/Register
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult Register(string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            return View();
+        }
+
+        //
+        // POST: /Account/Register
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            if (ModelState.IsValid)
+            {
+                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
+                var result = await _userManager.CreateAsync(user, model.Password);
+                if (result.Succeeded)
+                {
+                    // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
+                    // Send an email with this link
+                    //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
+                    //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
+                    //await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
+                    //    $"Please confirm your account by clicking this link: <a href='{callbackUrl}'>link</a>");
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    _logger.LogInformation(3, "User created a new account with password.");
+                    return RedirectToLocal(returnUrl);
+                }
+                AddErrors(result);
+            }
+
+            // If we got this far, something failed, redisplay form
+            return View(model);
+        }
+
+        //
+        // POST: /Account/LogOff
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> LogOff()
+        {
+            await _signInManager.SignOutAsync();
+            _logger.LogInformation(4, "User logged out.");
+            return RedirectToAction(nameof(HomeController.Index), "Home");
+        }
+
+        //
+        // POST: /Account/ExternalLogin
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public IActionResult ExternalLogin(string provider, string returnUrl = null)
+        {
+            // Request a redirect to the external login provider.
+            var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
+            var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
+            return Challenge(properties, provider);
+        }
+
+        //
+        // GET: /Account/ExternalLoginCallback
+        [HttpGet]
+        [AllowAnonymous]
+        public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
+        {
+            if (remoteError != null)
+            {
+                ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
+                return View(nameof(Login));
+            }
+            var info = await _signInManager.GetExternalLoginInfoAsync();
+            if (info == null)
+            {
+                return RedirectToAction(nameof(Login));
+            }
+
+            // Sign in the user with this external login provider if the user already has a login.
+            var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
+            if (result.Succeeded)
+            {
+                _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
+                return RedirectToLocal(returnUrl);
+            }
+            if (result.RequiresTwoFactor)
+            {
+                return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
+            }
+            if (result.IsLockedOut)
+            {
+                return View("Lockout");
+            }
+            else
+            {
+                // If the user does not have an account, then ask the user to create an account.
+                ViewData["ReturnUrl"] = returnUrl;
+                ViewData["LoginProvider"] = info.LoginProvider;
+                var email = info.Principal.FindFirstValue(ClaimTypes.Email);
+                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
+            }
+        }
+
+        //
+        // POST: /Account/ExternalLoginConfirmation
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
+        {
+            if (ModelState.IsValid)
+            {
+                // Get the information about the user from the external login provider
+                var info = await _signInManager.GetExternalLoginInfoAsync();
+                if (info == null)
+                {
+                    return View("ExternalLoginFailure");
+                }
+                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
+                var result = await _userManager.CreateAsync(user);
+                if (result.Succeeded)
+                {
+                    result = await _userManager.AddLoginAsync(user, info);
+                    if (result.Succeeded)
+                    {
+                        await _signInManager.SignInAsync(user, isPersistent: false);
+                        _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
+                        return RedirectToLocal(returnUrl);
+                    }
+                }
+                AddErrors(result);
+            }
+
+            ViewData["ReturnUrl"] = returnUrl;
+            return View(model);
+        }
+
+        // GET: /Account/ConfirmEmail
+        [HttpGet]
+        [AllowAnonymous]
+        public async Task<IActionResult> ConfirmEmail(string userId, string code)
+        {
+            if (userId == null || code == null)
+            {
+                return View("Error");
+            }
+            var user = await _userManager.FindByIdAsync(userId);
+            if (user == null)
+            {
+                return View("Error");
+            }
+            var result = await _userManager.ConfirmEmailAsync(user, code);
+            return View(result.Succeeded ? "ConfirmEmail" : "Error");
+        }
+
+        //
+        // GET: /Account/ForgotPassword
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult ForgotPassword()
+        {
+            return View();
+        }
+
+        //
+        // POST: /Account/ForgotPassword
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
+        {
+            if (ModelState.IsValid)
+            {
+                var user = await _userManager.FindByNameAsync(model.Email);
+                if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
+                {
+                    // Don't reveal that the user does not exist or is not confirmed
+                    return View("ForgotPasswordConfirmation");
+                }
+
+                // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
+                // Send an email with this link
+                //var code = await _userManager.GeneratePasswordResetTokenAsync(user);
+                //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
+                //await _emailSender.SendEmailAsync(model.Email, "Reset Password",
+                //   $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
+                //return View("ForgotPasswordConfirmation");
+            }
+
+            // If we got this far, something failed, redisplay form
+            return View(model);
+        }
+
+        //
+        // GET: /Account/ForgotPasswordConfirmation
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult ForgotPasswordConfirmation()
+        {
+            return View();
+        }
+
+        //
+        // GET: /Account/ResetPassword
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult ResetPassword(string code = null)
+        {
+            return code == null ? View("Error") : View();
+        }
+
+        //
+        // POST: /Account/ResetPassword
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+            var user = await _userManager.FindByNameAsync(model.Email);
+            if (user == null)
+            {
+                // Don't reveal that the user does not exist
+                return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
+            }
+            var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
+            if (result.Succeeded)
+            {
+                return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
+            }
+            AddErrors(result);
+            return View();
+        }
+
+        //
+        // GET: /Account/ResetPasswordConfirmation
+        [HttpGet]
+        [AllowAnonymous]
+        public IActionResult ResetPasswordConfirmation()
+        {
+            return View();
+        }
+
+        //
+        // GET: /Account/SendCode
+        [HttpGet]
+        [AllowAnonymous]
+        public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
+        {
+            var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
+            if (user == null)
+            {
+                return View("Error");
+            }
+            var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
+            var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
+            return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
+        }
+
+        //
+        // POST: /Account/SendCode
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> SendCode(SendCodeViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View();
+            }
+
+            var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
+            if (user == null)
+            {
+                return View("Error");
+            }
+
+            // Generate the token and send it
+            var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
+            if (string.IsNullOrWhiteSpace(code))
+            {
+                return View("Error");
+            }
+
+            var message = "Your security code is: " + code;
+            if (model.SelectedProvider == "Email")
+            {
+                await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message);
+            }
+            else if (model.SelectedProvider == "Phone")
+            {
+                await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message);
+            }
+
+            return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
+        }
+
+        //
+        // GET: /Account/VerifyCode
+        [HttpGet]
+        [AllowAnonymous]
+        public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
+        {
+            // Require that the user has already logged in via username/password or external login
+            var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
+            if (user == null)
+            {
+                return View("Error");
+            }
+            return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
+        }
+
+        //
+        // POST: /Account/VerifyCode
+        [HttpPost]
+        [AllowAnonymous]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+
+            // The following code protects for brute force attacks against the two factor codes.
+            // If a user enters incorrect codes for a specified amount of time then the user account
+            // will be locked out for a specified amount of time.
+            var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
+            if (result.Succeeded)
+            {
+                return RedirectToLocal(model.ReturnUrl);
+            }
+            if (result.IsLockedOut)
+            {
+                _logger.LogWarning(7, "User account locked out.");
+                return View("Lockout");
+            }
+            else
+            {
+                ModelState.AddModelError(string.Empty, "Invalid code.");
+                return View(model);
+            }
+        }
+
+        #region Helpers
+
+        private void AddErrors(IdentityResult result)
+        {
+            foreach (var error in result.Errors)
+            {
+                ModelState.AddModelError(string.Empty, error.Description);
+            }
+        }
+
+        private Task<ApplicationUser> GetCurrentUserAsync()
+        {
+            return _userManager.GetUserAsync(HttpContext.User);
+        }
+
+        private IActionResult RedirectToLocal(string returnUrl)
+        {
+            if (Url.IsLocalUrl(returnUrl))
+            {
+                return Redirect(returnUrl);
+            }
+            else
+            {
+                return RedirectToAction(nameof(HomeController.Index), "Home");
+            }
+        }
+
+        #endregion
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/HomeController.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/HomeController.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/HomeController.cs
new file mode 100644
index 0000000..4b21d0c
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/HomeController.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebApplication.Controllers
+{
+    public class HomeController : Controller
+    {
+        public IActionResult Index()
+        {
+            return View();
+        }
+
+        public IActionResult About()
+        {
+            ViewData["Message"] = "Your application description page.";
+
+            return View();
+        }
+
+        public IActionResult Contact()
+        {
+            ViewData["Message"] = "Your contact page.";
+
+            return View();
+        }
+
+        public IActionResult Error()
+        {
+            return View();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/ManageController.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/ManageController.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/ManageController.cs
new file mode 100644
index 0000000..8d04fe5
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Controllers/ManageController.cs
@@ -0,0 +1,347 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using WebApplication.Models;
+using WebApplication.Models.ManageViewModels;
+using WebApplication.Services;
+
+namespace WebApplication.Controllers
+{
+    [Authorize]
+    public class ManageController : Controller
+    {
+        private readonly UserManager<ApplicationUser> _userManager;
+        private readonly SignInManager<ApplicationUser> _signInManager;
+        private readonly IEmailSender _emailSender;
+        private readonly ISmsSender _smsSender;
+        private readonly ILogger _logger;
+
+        public ManageController(
+        UserManager<ApplicationUser> userManager,
+        SignInManager<ApplicationUser> signInManager,
+        IEmailSender emailSender,
+        ISmsSender smsSender,
+        ILoggerFactory loggerFactory)
+        {
+            _userManager = userManager;
+            _signInManager = signInManager;
+            _emailSender = emailSender;
+            _smsSender = smsSender;
+            _logger = loggerFactory.CreateLogger<ManageController>();
+        }
+
+        //
+        // GET: /Manage/Index
+        [HttpGet]
+        public async Task<IActionResult> Index(ManageMessageId? message = null)
+        {
+            ViewData["StatusMessage"] =
+                message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
+                : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
+                : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
+                : message == ManageMessageId.Error ? "An error has occurred."
+                : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
+                : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
+                : "";
+
+            var user = await GetCurrentUserAsync();
+            var model = new IndexViewModel
+            {
+                HasPassword = await _userManager.HasPasswordAsync(user),
+                PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
+                TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
+                Logins = await _userManager.GetLoginsAsync(user),
+                BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user)
+            };
+            return View(model);
+        }
+
+        //
+        // POST: /Manage/RemoveLogin
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
+        {
+            ManageMessageId? message = ManageMessageId.Error;
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
+                if (result.Succeeded)
+                {
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    message = ManageMessageId.RemoveLoginSuccess;
+                }
+            }
+            return RedirectToAction(nameof(ManageLogins), new { Message = message });
+        }
+
+        //
+        // GET: /Manage/AddPhoneNumber
+        public IActionResult AddPhoneNumber()
+        {
+            return View();
+        }
+
+        //
+        // POST: /Manage/AddPhoneNumber
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+            // Generate the token and send it
+            var user = await GetCurrentUserAsync();
+            var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
+            await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
+            return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
+        }
+
+        //
+        // POST: /Manage/EnableTwoFactorAuthentication
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> EnableTwoFactorAuthentication()
+        {
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                await _userManager.SetTwoFactorEnabledAsync(user, true);
+                await _signInManager.SignInAsync(user, isPersistent: false);
+                _logger.LogInformation(1, "User enabled two-factor authentication.");
+            }
+            return RedirectToAction(nameof(Index), "Manage");
+        }
+
+        //
+        // POST: /Manage/DisableTwoFactorAuthentication
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DisableTwoFactorAuthentication()
+        {
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                await _userManager.SetTwoFactorEnabledAsync(user, false);
+                await _signInManager.SignInAsync(user, isPersistent: false);
+                _logger.LogInformation(2, "User disabled two-factor authentication.");
+            }
+            return RedirectToAction(nameof(Index), "Manage");
+        }
+
+        //
+        // GET: /Manage/VerifyPhoneNumber
+        [HttpGet]
+        public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
+        {
+            var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber);
+            // Send an SMS to verify the phone number
+            return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
+        }
+
+        //
+        // POST: /Manage/VerifyPhoneNumber
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
+                if (result.Succeeded)
+                {
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
+                }
+            }
+            // If we got this far, something failed, redisplay the form
+            ModelState.AddModelError(string.Empty, "Failed to verify phone number");
+            return View(model);
+        }
+
+        //
+        // POST: /Manage/RemovePhoneNumber
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> RemovePhoneNumber()
+        {
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                var result = await _userManager.SetPhoneNumberAsync(user, null);
+                if (result.Succeeded)
+                {
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
+                }
+            }
+            return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
+        }
+
+        //
+        // GET: /Manage/ChangePassword
+        [HttpGet]
+        public IActionResult ChangePassword()
+        {
+            return View();
+        }
+
+        //
+        // POST: /Manage/ChangePassword
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
+                if (result.Succeeded)
+                {
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    _logger.LogInformation(3, "User changed their password successfully.");
+                    return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
+                }
+                AddErrors(result);
+                return View(model);
+            }
+            return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
+        }
+
+        //
+        // GET: /Manage/SetPassword
+        [HttpGet]
+        public IActionResult SetPassword()
+        {
+            return View();
+        }
+
+        //
+        // POST: /Manage/SetPassword
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(model);
+            }
+
+            var user = await GetCurrentUserAsync();
+            if (user != null)
+            {
+                var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
+                if (result.Succeeded)
+                {
+                    await _signInManager.SignInAsync(user, isPersistent: false);
+                    return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
+                }
+                AddErrors(result);
+                return View(model);
+            }
+            return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
+        }
+
+        //GET: /Manage/ManageLogins
+        [HttpGet]
+        public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
+        {
+            ViewData["StatusMessage"] =
+                message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
+                : message == ManageMessageId.AddLoginSuccess ? "The external login was added."
+                : message == ManageMessageId.Error ? "An error has occurred."
+                : "";
+            var user = await GetCurrentUserAsync();
+            if (user == null)
+            {
+                return View("Error");
+            }
+            var userLogins = await _userManager.GetLoginsAsync(user);
+            var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
+            ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
+            return View(new ManageLoginsViewModel
+            {
+                CurrentLogins = userLogins,
+                OtherLogins = otherLogins
+            });
+        }
+
+        //
+        // POST: /Manage/LinkLogin
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public IActionResult LinkLogin(string provider)
+        {
+            // Request a redirect to the external login provider to link a login for the current user
+            var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
+            var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
+            return Challenge(properties, provider);
+        }
+
+        //
+        // GET: /Manage/LinkLoginCallback
+        [HttpGet]
+        public async Task<ActionResult> LinkLoginCallback()
+        {
+            var user = await GetCurrentUserAsync();
+            if (user == null)
+            {
+                return View("Error");
+            }
+            var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
+            if (info == null)
+            {
+                return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
+            }
+            var result = await _userManager.AddLoginAsync(user, info);
+            var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
+            return RedirectToAction(nameof(ManageLogins), new { Message = message });
+        }
+
+        #region Helpers
+
+        private void AddErrors(IdentityResult result)
+        {
+            foreach (var error in result.Errors)
+            {
+                ModelState.AddModelError(string.Empty, error.Description);
+            }
+        }
+
+        public enum ManageMessageId
+        {
+            AddPhoneSuccess,
+            AddLoginSuccess,
+            ChangePasswordSuccess,
+            SetTwoFactorSuccess,
+            SetPasswordSuccess,
+            RemoveLoginSuccess,
+            RemovePhoneSuccess,
+            Error
+        }
+
+        private Task<ApplicationUser> GetCurrentUserAsync()
+        {
+            return _userManager.GetUserAsync(HttpContext.User);
+        }
+
+        #endregion
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/ApplicationDbContext.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/ApplicationDbContext.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/ApplicationDbContext.cs
new file mode 100644
index 0000000..336e6d4
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/ApplicationDbContext.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using WebApplication.Models;
+
+namespace WebApplication.Data
+{
+    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
+    {
+        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
+            : base(options)
+        {
+        }
+
+        protected override void OnModelCreating(ModelBuilder builder)
+        {
+            base.OnModelCreating(builder);
+            // Customize the ASP.NET Identity model and override the defaults if needed.
+            // For example, you can rename the ASP.NET Identity table names and more.
+            // Add your customizations after calling base.OnModelCreating(builder);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
new file mode 100644
index 0000000..bb12d2b
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
@@ -0,0 +1,212 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using WebApplication.Data;
+
+namespace WebApplication.Data.Migrations
+{
+    [DbContext(typeof(ApplicationDbContext))]
+    [Migration("00000000000000_CreateIdentitySchema")]
+    partial class CreateIdentitySchema
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                 .HasAnnotation("ProductVersion", "1.0.0-rc2-20901");
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
+                {
+                    b.Property<string>("Id");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken();
+
+                    b.Property<string>("Name")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("NormalizedName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .HasName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("ClaimType");
+
+                    b.Property<string>("ClaimValue");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired();
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("ClaimType");
+
+                    b.Property<string>("ClaimValue");
+
+                    b.Property<string>("UserId")
+                        .IsRequired();
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider");
+
+                    b.Property<string>("ProviderKey");
+
+                    b.Property<string>("ProviderDisplayName");
+
+                    b.Property<string>("UserId")
+                        .IsRequired();
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId");
+
+                    b.Property<string>("RoleId");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserRoles");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId");
+
+                    b.Property<string>("LoginProvider");
+
+                    b.Property<string>("Name");
+
+                    b.Property<string>("Value");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens");
+                });
+
+            modelBuilder.Entity("WebApplication.Models.ApplicationUser", b =>
+                {
+                    b.Property<string>("Id");
+
+                    b.Property<int>("AccessFailedCount");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken();
+
+                    b.Property<string>("Email")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<bool>("EmailConfirmed");
+
+                    b.Property<bool>("LockoutEnabled");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("PasswordHash");
+
+                    b.Property<string>("PhoneNumber");
+
+                    b.Property<bool>("PhoneNumberConfirmed");
+
+                    b.Property<string>("SecurityStamp");
+
+                    b.Property<bool>("TwoFactorEnabled");
+
+                    b.Property<string>("UserName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .HasName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.cs
new file mode 100644
index 0000000..e6f038f
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/00000000000000_CreateIdentitySchema.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace WebApplication.Data.Migrations
+{
+    public partial class CreateIdentitySchema : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "AspNetRoles",
+                columns: table => new
+                {
+                    Id = table.Column<string>(nullable: false),
+                    ConcurrencyStamp = table.Column<string>(nullable: true),
+                    Name = table.Column<string>(nullable: true),
+                    NormalizedName = table.Column<string>(nullable: true)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetRoles", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetUserTokens",
+                columns: table => new
+                {
+                    UserId = table.Column<string>(nullable: false),
+                    LoginProvider = table.Column<string>(nullable: false),
+                    Name = table.Column<string>(nullable: false),
+                    Value = table.Column<string>(nullable: true)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetUsers",
+                columns: table => new
+                {
+                    Id = table.Column<string>(nullable: false),
+                    AccessFailedCount = table.Column<int>(nullable: false),
+                    ConcurrencyStamp = table.Column<string>(nullable: true),
+                    Email = table.Column<string>(nullable: true),
+                    EmailConfirmed = table.Column<bool>(nullable: false),
+                    LockoutEnabled = table.Column<bool>(nullable: false),
+                    LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
+                    NormalizedEmail = table.Column<string>(nullable: true),
+                    NormalizedUserName = table.Column<string>(nullable: true),
+                    PasswordHash = table.Column<string>(nullable: true),
+                    PhoneNumber = table.Column<string>(nullable: true),
+                    PhoneNumberConfirmed = table.Column<bool>(nullable: false),
+                    SecurityStamp = table.Column<string>(nullable: true),
+                    TwoFactorEnabled = table.Column<bool>(nullable: false),
+                    UserName = table.Column<string>(nullable: true)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetUsers", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetRoleClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("Autoincrement", true),
+                    ClaimType = table.Column<string>(nullable: true),
+                    ClaimValue = table.Column<string>(nullable: true),
+                    RoleId = table.Column<string>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
+                        column: x => x.RoleId,
+                        principalTable: "AspNetRoles",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetUserClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("Autoincrement", true),
+                    ClaimType = table.Column<string>(nullable: true),
+                    ClaimValue = table.Column<string>(nullable: true),
+                    UserId = table.Column<string>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_AspNetUserClaims_AspNetUsers_UserId",
+                        column: x => x.UserId,
+                        principalTable: "AspNetUsers",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetUserLogins",
+                columns: table => new
+                {
+                    LoginProvider = table.Column<string>(nullable: false),
+                    ProviderKey = table.Column<string>(nullable: false),
+                    ProviderDisplayName = table.Column<string>(nullable: true),
+                    UserId = table.Column<string>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
+                    table.ForeignKey(
+                        name: "FK_AspNetUserLogins_AspNetUsers_UserId",
+                        column: x => x.UserId,
+                        principalTable: "AspNetUsers",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "AspNetUserRoles",
+                columns: table => new
+                {
+                    UserId = table.Column<string>(nullable: false),
+                    RoleId = table.Column<string>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
+                    table.ForeignKey(
+                        name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
+                        column: x => x.RoleId,
+                        principalTable: "AspNetRoles",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                    table.ForeignKey(
+                        name: "FK_AspNetUserRoles_AspNetUsers_UserId",
+                        column: x => x.UserId,
+                        principalTable: "AspNetUsers",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "RoleNameIndex",
+                table: "AspNetRoles",
+                column: "NormalizedName");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_AspNetRoleClaims_RoleId",
+                table: "AspNetRoleClaims",
+                column: "RoleId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_AspNetUserClaims_UserId",
+                table: "AspNetUserClaims",
+                column: "UserId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_AspNetUserLogins_UserId",
+                table: "AspNetUserLogins",
+                column: "UserId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_AspNetUserRoles_RoleId",
+                table: "AspNetUserRoles",
+                column: "RoleId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_AspNetUserRoles_UserId",
+                table: "AspNetUserRoles",
+                column: "UserId");
+
+            migrationBuilder.CreateIndex(
+                name: "EmailIndex",
+                table: "AspNetUsers",
+                column: "NormalizedEmail");
+
+            migrationBuilder.CreateIndex(
+                name: "UserNameIndex",
+                table: "AspNetUsers",
+                column: "NormalizedUserName");
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "AspNetRoleClaims");
+
+            migrationBuilder.DropTable(
+                name: "AspNetUserClaims");
+
+            migrationBuilder.DropTable(
+                name: "AspNetUserLogins");
+
+            migrationBuilder.DropTable(
+                name: "AspNetUserRoles");
+
+            migrationBuilder.DropTable(
+                name: "AspNetUserTokens");
+
+            migrationBuilder.DropTable(
+                name: "AspNetRoles");
+
+            migrationBuilder.DropTable(
+                name: "AspNetUsers");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/ApplicationDbContextModelSnapshot.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/ApplicationDbContextModelSnapshot.cs
new file mode 100644
index 0000000..cb45931
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Data/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -0,0 +1,211 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using WebApplication.Data;
+
+namespace WebApplication.Data.Migrations
+{
+    [DbContext(typeof(ApplicationDbContext))]
+    partial class ApplicationDbContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "1.0.0-rc2-20901");
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
+                {
+                    b.Property<string>("Id");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken();
+
+                    b.Property<string>("Name")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("NormalizedName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .HasName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("ClaimType");
+
+                    b.Property<string>("ClaimValue");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired();
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("ClaimType");
+
+                    b.Property<string>("ClaimValue");
+
+                    b.Property<string>("UserId")
+                        .IsRequired();
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider");
+
+                    b.Property<string>("ProviderKey");
+
+                    b.Property<string>("ProviderDisplayName");
+
+                    b.Property<string>("UserId")
+                        .IsRequired();
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId");
+
+                    b.Property<string>("RoleId");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserRoles");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId");
+
+                    b.Property<string>("LoginProvider");
+
+                    b.Property<string>("Name");
+
+                    b.Property<string>("Value");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens");
+                });
+
+            modelBuilder.Entity("WebApplication.Models.ApplicationUser", b =>
+                {
+                    b.Property<string>("Id");
+
+                    b.Property<int>("AccessFailedCount");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken();
+
+                    b.Property<string>("Email")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<bool>("EmailConfirmed");
+
+                    b.Property<bool>("LockoutEnabled");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.Property<string>("PasswordHash");
+
+                    b.Property<string>("PhoneNumber");
+
+                    b.Property<bool>("PhoneNumberConfirmed");
+
+                    b.Property<string>("SecurityStamp");
+
+                    b.Property<bool>("TwoFactorEnabled");
+
+                    b.Property<string>("UserName")
+                        .HasAnnotation("MaxLength", 256);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .HasName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("WebApplication.Models.ApplicationUser")
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
new file mode 100644
index 0000000..a60894c
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class ExternalLoginConfirmationViewModel
+    {
+        [Required]
+        [EmailAddress]
+        public string Email { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ForgotPasswordViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ForgotPasswordViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ForgotPasswordViewModel.cs
new file mode 100644
index 0000000..70fab0c
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ForgotPasswordViewModel.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class ForgotPasswordViewModel
+    {
+        [Required]
+        [EmailAddress]
+        public string Email { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/LoginViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/LoginViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/LoginViewModel.cs
new file mode 100644
index 0000000..7dc974b
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/LoginViewModel.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class LoginViewModel
+    {
+        [Required]
+        [EmailAddress]
+        public string Email { get; set; }
+
+        [Required]
+        [DataType(DataType.Password)]
+        public string Password { get; set; }
+
+        [Display(Name = "Remember me?")]
+        public bool RememberMe { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/RegisterViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/RegisterViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/RegisterViewModel.cs
new file mode 100644
index 0000000..bc86f2a
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/RegisterViewModel.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class RegisterViewModel
+    {
+        [Required]
+        [EmailAddress]
+        [Display(Name = "Email")]
+        public string Email { get; set; }
+
+        [Required]
+        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
+        [DataType(DataType.Password)]
+        [Display(Name = "Password")]
+        public string Password { get; set; }
+
+        [DataType(DataType.Password)]
+        [Display(Name = "Confirm password")]
+        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
+        public string ConfirmPassword { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ResetPasswordViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ResetPasswordViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ResetPasswordViewModel.cs
new file mode 100644
index 0000000..43198b7
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/ResetPasswordViewModel.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class ResetPasswordViewModel
+    {
+        [Required]
+        [EmailAddress]
+        public string Email { get; set; }
+
+        [Required]
+        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
+        [DataType(DataType.Password)]
+        public string Password { get; set; }
+
+        [DataType(DataType.Password)]
+        [Display(Name = "Confirm password")]
+        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
+        public string ConfirmPassword { get; set; }
+
+        public string Code { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/SendCodeViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/SendCodeViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/SendCodeViewModel.cs
new file mode 100644
index 0000000..b8ed8f1
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/SendCodeViewModel.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Rendering;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class SendCodeViewModel
+    {
+        public string SelectedProvider { get; set; }
+
+        public ICollection<SelectListItem> Providers { get; set; }
+
+        public string ReturnUrl { get; set; }
+
+        public bool RememberMe { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/VerifyCodeViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/VerifyCodeViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/VerifyCodeViewModel.cs
new file mode 100644
index 0000000..394db8c
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/AccountViewModels/VerifyCodeViewModel.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.AccountViewModels
+{
+    public class VerifyCodeViewModel
+    {
+        [Required]
+        public string Provider { get; set; }
+
+        [Required]
+        public string Code { get; set; }
+
+        public string ReturnUrl { get; set; }
+
+        [Display(Name = "Remember this browser?")]
+        public bool RememberBrowser { get; set; }
+
+        [Display(Name = "Remember me?")]
+        public bool RememberMe { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ApplicationUser.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ApplicationUser.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ApplicationUser.cs
new file mode 100644
index 0000000..4642ef2
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ApplicationUser.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+
+namespace WebApplication.Models
+{
+    // Add profile data for application users by adding properties to the ApplicationUser class
+    public class ApplicationUser : IdentityUser
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/AddPhoneNumberViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/AddPhoneNumberViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/AddPhoneNumberViewModel.cs
new file mode 100644
index 0000000..d2baaf7
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/AddPhoneNumberViewModel.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class AddPhoneNumberViewModel
+    {
+        [Required]
+        [Phone]
+        [Display(Name = "Phone number")]
+        public string PhoneNumber { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ChangePasswordViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ChangePasswordViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ChangePasswordViewModel.cs
new file mode 100644
index 0000000..421b91a
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ChangePasswordViewModel.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class ChangePasswordViewModel
+    {
+        [Required]
+        [DataType(DataType.Password)]
+        [Display(Name = "Current password")]
+        public string OldPassword { get; set; }
+
+        [Required]
+        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
+        [DataType(DataType.Password)]
+        [Display(Name = "New password")]
+        public string NewPassword { get; set; }
+
+        [DataType(DataType.Password)]
+        [Display(Name = "Confirm new password")]
+        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
+        public string ConfirmPassword { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs
new file mode 100644
index 0000000..beb1fd1
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Rendering;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class ConfigureTwoFactorViewModel
+    {
+        public string SelectedProvider { get; set; }
+
+        public ICollection<SelectListItem> Providers { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/FactorViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/FactorViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/FactorViewModel.cs
new file mode 100644
index 0000000..b2d4f9e
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/FactorViewModel.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class FactorViewModel
+    {
+        public string Purpose { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/IndexViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/IndexViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/IndexViewModel.cs
new file mode 100644
index 0000000..e0b69f2
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/IndexViewModel.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class IndexViewModel
+    {
+        public bool HasPassword { get; set; }
+
+        public IList<UserLoginInfo> Logins { get; set; }
+
+        public string PhoneNumber { get; set; }
+
+        public bool TwoFactor { get; set; }
+
+        public bool BrowserRemembered { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/5e667994/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ManageLoginsViewModel.cs
----------------------------------------------------------------------
diff --git a/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ManageLoginsViewModel.cs b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ManageLoginsViewModel.cs
new file mode 100644
index 0000000..fc03a0c
--- /dev/null
+++ b/extensions/log4net.Extensions.Logging/log4net.Extensions.Logging.Test/Models/ManageViewModels/ManageLoginsViewModel.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http.Authentication;
+using Microsoft.AspNetCore.Identity;
+
+namespace WebApplication.Models.ManageViewModels
+{
+    public class ManageLoginsViewModel
+    {
+        public IList<UserLoginInfo> CurrentLogins { get; set; }
+
+        public IList<AuthenticationDescription> OtherLogins { get; set; }
+    }
+}