├── .bowerrc ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── Controllers ├── AccountController.cs ├── HomeController.cs ├── ManageController.cs └── PeopleController.cs ├── Data ├── ApplicationDbContext.cs └── Migrations │ ├── 00000000000000_CreateIdentitySchema.Designer.cs │ ├── 00000000000000_CreateIdentitySchema.cs │ └── ApplicationDbContextModelSnapshot.cs ├── LICENSE ├── Models ├── AccountViewModels │ ├── ExternalLoginConfirmationViewModel.cs │ ├── ForgotPasswordViewModel.cs │ ├── LoginViewModel.cs │ ├── RegisterViewModel.cs │ ├── ResetPasswordViewModel.cs │ ├── SendCodeViewModel.cs │ └── VerifyCodeViewModel.cs ├── ApplicationUser.cs └── ManageViewModels │ ├── AddPhoneNumberViewModel.cs │ ├── ChangePasswordViewModel.cs │ ├── ConfigureTwoFactorViewModel.cs │ ├── FactorViewModel.cs │ ├── IndexViewModel.cs │ ├── ManageLoginsViewModel.cs │ ├── RemoveLoginViewModel.cs │ ├── SetPasswordViewModel.cs │ └── VerifyPhoneNumberViewModel.cs ├── Program.cs ├── README.md ├── Services ├── IEmailSender.cs ├── ISmsSender.cs └── MessageServices.cs ├── Startup.cs ├── Views ├── Account │ ├── ConfirmEmail.cshtml │ ├── ExternalLoginConfirmation.cshtml │ ├── ExternalLoginFailure.cshtml │ ├── ForgotPassword.cshtml │ ├── ForgotPasswordConfirmation.cshtml │ ├── Lockout.cshtml │ ├── Login.cshtml │ ├── Register.cshtml │ ├── ResetPassword.cshtml │ ├── ResetPasswordConfirmation.cshtml │ ├── SendCode.cshtml │ └── VerifyCode.cshtml ├── Home │ ├── About.cshtml │ ├── Contact.cshtml │ └── Index.cshtml ├── Manage │ ├── AddPhoneNumber.cshtml │ ├── ChangePassword.cshtml │ ├── Index.cshtml │ ├── ManageLogins.cshtml │ ├── SetPassword.cshtml │ └── VerifyPhoneNumber.cshtml ├── Shared │ ├── Error.cshtml │ ├── _Layout.cshtml │ ├── _LoginPartial.cshtml │ └── _ValidationScriptsPartial.cshtml ├── _ViewImports.cshtml └── _ViewStart.cshtml ├── appsettings.json ├── bower.json ├── gulpfile.js ├── package.json ├── project.json ├── tsconfig.json ├── typings.json ├── typings ├── globals │ ├── core-js │ │ ├── index.d.ts │ │ └── typings.json │ ├── jasmine │ │ ├── index.d.ts │ │ └── typings.json │ └── node │ │ ├── index.d.ts │ │ └── typings.json └── index.d.ts ├── web.config ├── webpack.config.js ├── webpack.dev.js └── wwwroot ├── app ├── app.component.ts ├── app.module.ts ├── bundle.js ├── bundle.js.map ├── main.ts └── person.service.ts ├── css ├── site.css └── site.min.css ├── favicon.ico ├── images ├── banner1.svg ├── banner2.svg ├── banner3.svg └── banner4.svg ├── index.html ├── js ├── core.js ├── reflect.js ├── site.js ├── site.min.js ├── system.js └── zone.js ├── systemjs.config.js ├── vendor.js └── vendor.js.map /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # NuGet Packages 148 | *.nupkg 149 | # The packages folder can be ignored because of Package Restore 150 | **/packages/* 151 | # except build/, which is used as an MSBuild target. 152 | !**/packages/build/ 153 | # Uncomment if necessary however generally it will be regenerated when needed 154 | #!**/packages/repositories.config 155 | 156 | # Microsoft Azure Build Output 157 | csx/ 158 | *.build.csdef 159 | 160 | # Microsoft Azure Emulator 161 | ecf/ 162 | rcf/ 163 | 164 | # Microsoft Azure ApplicationInsights config file 165 | ApplicationInsights.config 166 | 167 | # Windows Store app package directory 168 | AppPackages/ 169 | BundleArtifacts/ 170 | 171 | # Visual Studio cache files 172 | # files ending in .cache can be ignored 173 | *.[Cc]ache 174 | # but keep track of directories ending in .cache 175 | !*.[Cc]ache/ 176 | 177 | # Others 178 | ClientBin/ 179 | ~$* 180 | *~ 181 | *.dbmdl 182 | *.dbproj.schemaview 183 | *.pfx 184 | *.publishsettings 185 | node_modules/ 186 | orleans.codegen.cs 187 | 188 | # RIA/Silverlight projects 189 | Generated_Code/ 190 | 191 | # Backup & report files from converting an old project file 192 | # to a newer Visual Studio version. Backup files are not needed, 193 | # because we have git ;-) 194 | _UpgradeReport_Files/ 195 | Backup*/ 196 | UpgradeLog*.XML 197 | UpgradeLog*.htm 198 | 199 | # SQL Server files 200 | *.mdf 201 | *.ldf 202 | 203 | # Business Intelligence projects 204 | *.rdl.data 205 | *.bim.layout 206 | *.bim_*.settings 207 | 208 | # Microsoft Fakes 209 | FakesAssemblies/ 210 | 211 | # GhostDoc plugin setting file 212 | *.GhostDoc.xml 213 | 214 | # Node.js Tools for Visual Studio 215 | .ntvs_analysis.dat 216 | 217 | # Visual Studio 6 build log 218 | *.plg 219 | 220 | # Visual Studio 6 workspace options file 221 | *.opt 222 | 223 | # Visual Studio LightSwitch build output 224 | **/*.HTMLClient/GeneratedArtifacts 225 | **/*.DesktopClient/GeneratedArtifacts 226 | **/*.DesktopClient/ModelManifest.xml 227 | **/*.Server/GeneratedArtifacts 228 | **/*.Server/ModelManifest.xml 229 | _Pvt_Extensions 230 | 231 | # Paket dependency manager 232 | .paket/paket.exe 233 | 234 | # FAKE - F# Make 235 | .fake/ 236 | # Visual Studio LightSwitch build output 237 | **/*.HTMLClient/GeneratedArtifacts 238 | **/*.DesktopClient/GeneratedArtifacts 239 | **/*.DesktopClient/ModelManifest.xml 240 | **/*.Server/GeneratedArtifacts 241 | **/*.Server/ModelManifest.xml 242 | _Pvt_Extensions 243 | 244 | # Paket dependency manager 245 | .paket/paket.exe 246 | paket-files/ 247 | 248 | # FAKE - F# Make 249 | .fake/ 250 | 251 | # JetBrains Rider 252 | .idea/ 253 | *.sln.iml 254 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Launch (web)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceRoot}\\bin\\Debug\\netcoreapp1.0\\angular2-aspnetcore.dll", 10 | "args": [], 11 | "cwd": "${workspaceRoot}", 12 | "stopAtEntry": false, 13 | "internalConsoleOptions": "openOnSessionStart", 14 | "launchBrowser": { 15 | "enabled": true, 16 | "args": "${auto-detect-url}", 17 | "windows": { 18 | "command": "cmd.exe", 19 | "args": "/C start ${auto-detect-url}" 20 | }, 21 | "osx": { 22 | "command": "open" 23 | }, 24 | "linux": { 25 | "command": "xdg-open" 26 | } 27 | }, 28 | "env": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | }, 31 | "sourceFileMap": { 32 | "/Views": "${workspaceRoot}/Views" 33 | } 34 | }, 35 | { 36 | "name": ".NET Core Attach", 37 | "type": "coreclr", 38 | "request": "attach", 39 | "processId": "${command.pickProcess}" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "dotnet", 4 | "isShellCommand": true, 5 | "args": [], 6 | "tasks": [ 7 | { 8 | "taskName": "build", 9 | "args": [ 10 | "${workspaceRoot}//project.json" 11 | ], 12 | "isBuildCommand": true, 13 | "problemMatcher": "$msCompile" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Identity; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.AspNetCore.Mvc.Rendering; 10 | using Microsoft.Extensions.Logging; 11 | using WebApplication.Models; 12 | using WebApplication.Models.AccountViewModels; 13 | using WebApplication.Services; 14 | 15 | namespace WebApplication.Controllers 16 | { 17 | [Authorize] 18 | public class AccountController : Controller 19 | { 20 | private readonly UserManager _userManager; 21 | private readonly SignInManager _signInManager; 22 | private readonly IEmailSender _emailSender; 23 | private readonly ISmsSender _smsSender; 24 | private readonly ILogger _logger; 25 | 26 | public AccountController( 27 | UserManager userManager, 28 | SignInManager signInManager, 29 | IEmailSender emailSender, 30 | ISmsSender smsSender, 31 | ILoggerFactory loggerFactory) 32 | { 33 | _userManager = userManager; 34 | _signInManager = signInManager; 35 | _emailSender = emailSender; 36 | _smsSender = smsSender; 37 | _logger = loggerFactory.CreateLogger(); 38 | } 39 | 40 | // 41 | // GET: /Account/Login 42 | [HttpGet] 43 | [AllowAnonymous] 44 | public IActionResult Login(string returnUrl = null) 45 | { 46 | ViewData["ReturnUrl"] = returnUrl; 47 | return View(); 48 | } 49 | 50 | // 51 | // POST: /Account/Login 52 | [HttpPost] 53 | [AllowAnonymous] 54 | [ValidateAntiForgeryToken] 55 | public async Task Login(LoginViewModel model, string returnUrl = null) 56 | { 57 | ViewData["ReturnUrl"] = returnUrl; 58 | if (ModelState.IsValid) 59 | { 60 | // This doesn't count login failures towards account lockout 61 | // To enable password failures to trigger account lockout, set lockoutOnFailure: true 62 | var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false); 63 | if (result.Succeeded) 64 | { 65 | _logger.LogInformation(1, "User logged in."); 66 | return RedirectToLocal(returnUrl); 67 | } 68 | if (result.RequiresTwoFactor) 69 | { 70 | return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); 71 | } 72 | if (result.IsLockedOut) 73 | { 74 | _logger.LogWarning(2, "User account locked out."); 75 | return View("Lockout"); 76 | } 77 | else 78 | { 79 | ModelState.AddModelError(string.Empty, "Invalid login attempt."); 80 | return View(model); 81 | } 82 | } 83 | 84 | // If we got this far, something failed, redisplay form 85 | return View(model); 86 | } 87 | 88 | // 89 | // GET: /Account/Register 90 | [HttpGet] 91 | [AllowAnonymous] 92 | public IActionResult Register(string returnUrl = null) 93 | { 94 | ViewData["ReturnUrl"] = returnUrl; 95 | return View(); 96 | } 97 | 98 | // 99 | // POST: /Account/Register 100 | [HttpPost] 101 | [AllowAnonymous] 102 | [ValidateAntiForgeryToken] 103 | public async Task Register(RegisterViewModel model, string returnUrl = null) 104 | { 105 | ViewData["ReturnUrl"] = returnUrl; 106 | if (ModelState.IsValid) 107 | { 108 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 109 | var result = await _userManager.CreateAsync(user, model.Password); 110 | if (result.Succeeded) 111 | { 112 | // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713 113 | // Send an email with this link 114 | //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); 115 | //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); 116 | //await _emailSender.SendEmailAsync(model.Email, "Confirm your account", 117 | // $"Please confirm your account by clicking this link: link"); 118 | await _signInManager.SignInAsync(user, isPersistent: false); 119 | _logger.LogInformation(3, "User created a new account with password."); 120 | return RedirectToLocal(returnUrl); 121 | } 122 | AddErrors(result); 123 | } 124 | 125 | // If we got this far, something failed, redisplay form 126 | return View(model); 127 | } 128 | 129 | // 130 | // POST: /Account/LogOff 131 | [HttpPost] 132 | [ValidateAntiForgeryToken] 133 | public async Task LogOff() 134 | { 135 | await _signInManager.SignOutAsync(); 136 | _logger.LogInformation(4, "User logged out."); 137 | return RedirectToAction(nameof(HomeController.Index), "Home"); 138 | } 139 | 140 | // 141 | // POST: /Account/ExternalLogin 142 | [HttpPost] 143 | [AllowAnonymous] 144 | [ValidateAntiForgeryToken] 145 | public IActionResult ExternalLogin(string provider, string returnUrl = null) 146 | { 147 | // Request a redirect to the external login provider. 148 | var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }); 149 | var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); 150 | return Challenge(properties, provider); 151 | } 152 | 153 | // 154 | // GET: /Account/ExternalLoginCallback 155 | [HttpGet] 156 | [AllowAnonymous] 157 | public async Task ExternalLoginCallback(string returnUrl = null, string remoteError = null) 158 | { 159 | if (remoteError != null) 160 | { 161 | ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}"); 162 | return View(nameof(Login)); 163 | } 164 | var info = await _signInManager.GetExternalLoginInfoAsync(); 165 | if (info == null) 166 | { 167 | return RedirectToAction(nameof(Login)); 168 | } 169 | 170 | // Sign in the user with this external login provider if the user already has a login. 171 | var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 172 | if (result.Succeeded) 173 | { 174 | _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider); 175 | return RedirectToLocal(returnUrl); 176 | } 177 | if (result.RequiresTwoFactor) 178 | { 179 | return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl }); 180 | } 181 | if (result.IsLockedOut) 182 | { 183 | return View("Lockout"); 184 | } 185 | else 186 | { 187 | // If the user does not have an account, then ask the user to create an account. 188 | ViewData["ReturnUrl"] = returnUrl; 189 | ViewData["LoginProvider"] = info.LoginProvider; 190 | var email = info.Principal.FindFirstValue(ClaimTypes.Email); 191 | return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email }); 192 | } 193 | } 194 | 195 | // 196 | // POST: /Account/ExternalLoginConfirmation 197 | [HttpPost] 198 | [AllowAnonymous] 199 | [ValidateAntiForgeryToken] 200 | public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null) 201 | { 202 | if (ModelState.IsValid) 203 | { 204 | // Get the information about the user from the external login provider 205 | var info = await _signInManager.GetExternalLoginInfoAsync(); 206 | if (info == null) 207 | { 208 | return View("ExternalLoginFailure"); 209 | } 210 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 211 | var result = await _userManager.CreateAsync(user); 212 | if (result.Succeeded) 213 | { 214 | result = await _userManager.AddLoginAsync(user, info); 215 | if (result.Succeeded) 216 | { 217 | await _signInManager.SignInAsync(user, isPersistent: false); 218 | _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider); 219 | return RedirectToLocal(returnUrl); 220 | } 221 | } 222 | AddErrors(result); 223 | } 224 | 225 | ViewData["ReturnUrl"] = returnUrl; 226 | return View(model); 227 | } 228 | 229 | // GET: /Account/ConfirmEmail 230 | [HttpGet] 231 | [AllowAnonymous] 232 | public async Task ConfirmEmail(string userId, string code) 233 | { 234 | if (userId == null || code == null) 235 | { 236 | return View("Error"); 237 | } 238 | var user = await _userManager.FindByIdAsync(userId); 239 | if (user == null) 240 | { 241 | return View("Error"); 242 | } 243 | var result = await _userManager.ConfirmEmailAsync(user, code); 244 | return View(result.Succeeded ? "ConfirmEmail" : "Error"); 245 | } 246 | 247 | // 248 | // GET: /Account/ForgotPassword 249 | [HttpGet] 250 | [AllowAnonymous] 251 | public IActionResult ForgotPassword() 252 | { 253 | return View(); 254 | } 255 | 256 | // 257 | // POST: /Account/ForgotPassword 258 | [HttpPost] 259 | [AllowAnonymous] 260 | [ValidateAntiForgeryToken] 261 | public async Task ForgotPassword(ForgotPasswordViewModel model) 262 | { 263 | if (ModelState.IsValid) 264 | { 265 | var user = await _userManager.FindByNameAsync(model.Email); 266 | if (user == null || !(await _userManager.IsEmailConfirmedAsync(user))) 267 | { 268 | // Don't reveal that the user does not exist or is not confirmed 269 | return View("ForgotPasswordConfirmation"); 270 | } 271 | 272 | // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713 273 | // Send an email with this link 274 | //var code = await _userManager.GeneratePasswordResetTokenAsync(user); 275 | //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); 276 | //await _emailSender.SendEmailAsync(model.Email, "Reset Password", 277 | // $"Please reset your password by clicking here: link"); 278 | //return View("ForgotPasswordConfirmation"); 279 | } 280 | 281 | // If we got this far, something failed, redisplay form 282 | return View(model); 283 | } 284 | 285 | // 286 | // GET: /Account/ForgotPasswordConfirmation 287 | [HttpGet] 288 | [AllowAnonymous] 289 | public IActionResult ForgotPasswordConfirmation() 290 | { 291 | return View(); 292 | } 293 | 294 | // 295 | // GET: /Account/ResetPassword 296 | [HttpGet] 297 | [AllowAnonymous] 298 | public IActionResult ResetPassword(string code = null) 299 | { 300 | return code == null ? View("Error") : View(); 301 | } 302 | 303 | // 304 | // POST: /Account/ResetPassword 305 | [HttpPost] 306 | [AllowAnonymous] 307 | [ValidateAntiForgeryToken] 308 | public async Task ResetPassword(ResetPasswordViewModel model) 309 | { 310 | if (!ModelState.IsValid) 311 | { 312 | return View(model); 313 | } 314 | var user = await _userManager.FindByNameAsync(model.Email); 315 | if (user == null) 316 | { 317 | // Don't reveal that the user does not exist 318 | return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account"); 319 | } 320 | var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password); 321 | if (result.Succeeded) 322 | { 323 | return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account"); 324 | } 325 | AddErrors(result); 326 | return View(); 327 | } 328 | 329 | // 330 | // GET: /Account/ResetPasswordConfirmation 331 | [HttpGet] 332 | [AllowAnonymous] 333 | public IActionResult ResetPasswordConfirmation() 334 | { 335 | return View(); 336 | } 337 | 338 | // 339 | // GET: /Account/SendCode 340 | [HttpGet] 341 | [AllowAnonymous] 342 | public async Task SendCode(string returnUrl = null, bool rememberMe = false) 343 | { 344 | var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); 345 | if (user == null) 346 | { 347 | return View("Error"); 348 | } 349 | var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user); 350 | var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); 351 | return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe }); 352 | } 353 | 354 | // 355 | // POST: /Account/SendCode 356 | [HttpPost] 357 | [AllowAnonymous] 358 | [ValidateAntiForgeryToken] 359 | public async Task SendCode(SendCodeViewModel model) 360 | { 361 | if (!ModelState.IsValid) 362 | { 363 | return View(); 364 | } 365 | 366 | var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); 367 | if (user == null) 368 | { 369 | return View("Error"); 370 | } 371 | 372 | // Generate the token and send it 373 | var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider); 374 | if (string.IsNullOrWhiteSpace(code)) 375 | { 376 | return View("Error"); 377 | } 378 | 379 | var message = "Your security code is: " + code; 380 | if (model.SelectedProvider == "Email") 381 | { 382 | await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message); 383 | } 384 | else if (model.SelectedProvider == "Phone") 385 | { 386 | await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message); 387 | } 388 | 389 | return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe }); 390 | } 391 | 392 | // 393 | // GET: /Account/VerifyCode 394 | [HttpGet] 395 | [AllowAnonymous] 396 | public async Task VerifyCode(string provider, bool rememberMe, string returnUrl = null) 397 | { 398 | // Require that the user has already logged in via username/password or external login 399 | var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); 400 | if (user == null) 401 | { 402 | return View("Error"); 403 | } 404 | return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe }); 405 | } 406 | 407 | // 408 | // POST: /Account/VerifyCode 409 | [HttpPost] 410 | [AllowAnonymous] 411 | [ValidateAntiForgeryToken] 412 | public async Task VerifyCode(VerifyCodeViewModel model) 413 | { 414 | if (!ModelState.IsValid) 415 | { 416 | return View(model); 417 | } 418 | 419 | // The following code protects for brute force attacks against the two factor codes. 420 | // If a user enters incorrect codes for a specified amount of time then the user account 421 | // will be locked out for a specified amount of time. 422 | var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser); 423 | if (result.Succeeded) 424 | { 425 | return RedirectToLocal(model.ReturnUrl); 426 | } 427 | if (result.IsLockedOut) 428 | { 429 | _logger.LogWarning(7, "User account locked out."); 430 | return View("Lockout"); 431 | } 432 | else 433 | { 434 | ModelState.AddModelError(string.Empty, "Invalid code."); 435 | return View(model); 436 | } 437 | } 438 | 439 | #region Helpers 440 | 441 | private void AddErrors(IdentityResult result) 442 | { 443 | foreach (var error in result.Errors) 444 | { 445 | ModelState.AddModelError(string.Empty, error.Description); 446 | } 447 | } 448 | 449 | private Task GetCurrentUserAsync() 450 | { 451 | return _userManager.GetUserAsync(HttpContext.User); 452 | } 453 | 454 | private IActionResult RedirectToLocal(string returnUrl) 455 | { 456 | if (Url.IsLocalUrl(returnUrl)) 457 | { 458 | return Redirect(returnUrl); 459 | } 460 | else 461 | { 462 | return RedirectToAction(nameof(HomeController.Index), "Home"); 463 | } 464 | } 465 | 466 | #endregion 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace WebApplication.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public IActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | public IActionResult About() 17 | { 18 | ViewData["Message"] = "Your application description page."; 19 | 20 | return View(); 21 | } 22 | 23 | public IActionResult Contact() 24 | { 25 | ViewData["Message"] = "Your contact page."; 26 | 27 | return View(); 28 | } 29 | 30 | public IActionResult Error() 31 | { 32 | return View(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Controllers/ManageController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Identity; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.Extensions.Logging; 9 | using WebApplication.Models; 10 | using WebApplication.Models.ManageViewModels; 11 | using WebApplication.Services; 12 | 13 | namespace WebApplication.Controllers 14 | { 15 | [Authorize] 16 | public class ManageController : Controller 17 | { 18 | private readonly UserManager _userManager; 19 | private readonly SignInManager _signInManager; 20 | private readonly IEmailSender _emailSender; 21 | private readonly ISmsSender _smsSender; 22 | private readonly ILogger _logger; 23 | 24 | public ManageController( 25 | UserManager userManager, 26 | SignInManager signInManager, 27 | IEmailSender emailSender, 28 | ISmsSender smsSender, 29 | ILoggerFactory loggerFactory) 30 | { 31 | _userManager = userManager; 32 | _signInManager = signInManager; 33 | _emailSender = emailSender; 34 | _smsSender = smsSender; 35 | _logger = loggerFactory.CreateLogger(); 36 | } 37 | 38 | // 39 | // GET: /Manage/Index 40 | [HttpGet] 41 | public async Task Index(ManageMessageId? message = null) 42 | { 43 | ViewData["StatusMessage"] = 44 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." 45 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." 46 | : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." 47 | : message == ManageMessageId.Error ? "An error has occurred." 48 | : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." 49 | : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." 50 | : ""; 51 | 52 | var user = await GetCurrentUserAsync(); 53 | var model = new IndexViewModel 54 | { 55 | HasPassword = await _userManager.HasPasswordAsync(user), 56 | PhoneNumber = await _userManager.GetPhoneNumberAsync(user), 57 | TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), 58 | Logins = await _userManager.GetLoginsAsync(user), 59 | BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user) 60 | }; 61 | return View(model); 62 | } 63 | 64 | // 65 | // POST: /Manage/RemoveLogin 66 | [HttpPost] 67 | [ValidateAntiForgeryToken] 68 | public async Task RemoveLogin(RemoveLoginViewModel account) 69 | { 70 | ManageMessageId? message = ManageMessageId.Error; 71 | var user = await GetCurrentUserAsync(); 72 | if (user != null) 73 | { 74 | var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); 75 | if (result.Succeeded) 76 | { 77 | await _signInManager.SignInAsync(user, isPersistent: false); 78 | message = ManageMessageId.RemoveLoginSuccess; 79 | } 80 | } 81 | return RedirectToAction(nameof(ManageLogins), new { Message = message }); 82 | } 83 | 84 | // 85 | // GET: /Manage/AddPhoneNumber 86 | public IActionResult AddPhoneNumber() 87 | { 88 | return View(); 89 | } 90 | 91 | // 92 | // POST: /Manage/AddPhoneNumber 93 | [HttpPost] 94 | [ValidateAntiForgeryToken] 95 | public async Task AddPhoneNumber(AddPhoneNumberViewModel model) 96 | { 97 | if (!ModelState.IsValid) 98 | { 99 | return View(model); 100 | } 101 | // Generate the token and send it 102 | var user = await GetCurrentUserAsync(); 103 | var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); 104 | await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); 105 | return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); 106 | } 107 | 108 | // 109 | // POST: /Manage/EnableTwoFactorAuthentication 110 | [HttpPost] 111 | [ValidateAntiForgeryToken] 112 | public async Task EnableTwoFactorAuthentication() 113 | { 114 | var user = await GetCurrentUserAsync(); 115 | if (user != null) 116 | { 117 | await _userManager.SetTwoFactorEnabledAsync(user, true); 118 | await _signInManager.SignInAsync(user, isPersistent: false); 119 | _logger.LogInformation(1, "User enabled two-factor authentication."); 120 | } 121 | return RedirectToAction(nameof(Index), "Manage"); 122 | } 123 | 124 | // 125 | // POST: /Manage/DisableTwoFactorAuthentication 126 | [HttpPost] 127 | [ValidateAntiForgeryToken] 128 | public async Task DisableTwoFactorAuthentication() 129 | { 130 | var user = await GetCurrentUserAsync(); 131 | if (user != null) 132 | { 133 | await _userManager.SetTwoFactorEnabledAsync(user, false); 134 | await _signInManager.SignInAsync(user, isPersistent: false); 135 | _logger.LogInformation(2, "User disabled two-factor authentication."); 136 | } 137 | return RedirectToAction(nameof(Index), "Manage"); 138 | } 139 | 140 | // 141 | // GET: /Manage/VerifyPhoneNumber 142 | [HttpGet] 143 | public async Task VerifyPhoneNumber(string phoneNumber) 144 | { 145 | var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber); 146 | // Send an SMS to verify the phone number 147 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); 148 | } 149 | 150 | // 151 | // POST: /Manage/VerifyPhoneNumber 152 | [HttpPost] 153 | [ValidateAntiForgeryToken] 154 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) 155 | { 156 | if (!ModelState.IsValid) 157 | { 158 | return View(model); 159 | } 160 | var user = await GetCurrentUserAsync(); 161 | if (user != null) 162 | { 163 | var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); 164 | if (result.Succeeded) 165 | { 166 | await _signInManager.SignInAsync(user, isPersistent: false); 167 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); 168 | } 169 | } 170 | // If we got this far, something failed, redisplay the form 171 | ModelState.AddModelError(string.Empty, "Failed to verify phone number"); 172 | return View(model); 173 | } 174 | 175 | // 176 | // POST: /Manage/RemovePhoneNumber 177 | [HttpPost] 178 | [ValidateAntiForgeryToken] 179 | public async Task RemovePhoneNumber() 180 | { 181 | var user = await GetCurrentUserAsync(); 182 | if (user != null) 183 | { 184 | var result = await _userManager.SetPhoneNumberAsync(user, null); 185 | if (result.Succeeded) 186 | { 187 | await _signInManager.SignInAsync(user, isPersistent: false); 188 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); 189 | } 190 | } 191 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 192 | } 193 | 194 | // 195 | // GET: /Manage/ChangePassword 196 | [HttpGet] 197 | public IActionResult ChangePassword() 198 | { 199 | return View(); 200 | } 201 | 202 | // 203 | // POST: /Manage/ChangePassword 204 | [HttpPost] 205 | [ValidateAntiForgeryToken] 206 | public async Task ChangePassword(ChangePasswordViewModel model) 207 | { 208 | if (!ModelState.IsValid) 209 | { 210 | return View(model); 211 | } 212 | var user = await GetCurrentUserAsync(); 213 | if (user != null) 214 | { 215 | var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); 216 | if (result.Succeeded) 217 | { 218 | await _signInManager.SignInAsync(user, isPersistent: false); 219 | _logger.LogInformation(3, "User changed their password successfully."); 220 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); 221 | } 222 | AddErrors(result); 223 | return View(model); 224 | } 225 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 226 | } 227 | 228 | // 229 | // GET: /Manage/SetPassword 230 | [HttpGet] 231 | public IActionResult SetPassword() 232 | { 233 | return View(); 234 | } 235 | 236 | // 237 | // POST: /Manage/SetPassword 238 | [HttpPost] 239 | [ValidateAntiForgeryToken] 240 | public async Task SetPassword(SetPasswordViewModel model) 241 | { 242 | if (!ModelState.IsValid) 243 | { 244 | return View(model); 245 | } 246 | 247 | var user = await GetCurrentUserAsync(); 248 | if (user != null) 249 | { 250 | var result = await _userManager.AddPasswordAsync(user, model.NewPassword); 251 | if (result.Succeeded) 252 | { 253 | await _signInManager.SignInAsync(user, isPersistent: false); 254 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); 255 | } 256 | AddErrors(result); 257 | return View(model); 258 | } 259 | return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); 260 | } 261 | 262 | //GET: /Manage/ManageLogins 263 | [HttpGet] 264 | public async Task ManageLogins(ManageMessageId? message = null) 265 | { 266 | ViewData["StatusMessage"] = 267 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 268 | : message == ManageMessageId.AddLoginSuccess ? "The external login was added." 269 | : message == ManageMessageId.Error ? "An error has occurred." 270 | : ""; 271 | var user = await GetCurrentUserAsync(); 272 | if (user == null) 273 | { 274 | return View("Error"); 275 | } 276 | var userLogins = await _userManager.GetLoginsAsync(user); 277 | var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); 278 | ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; 279 | return View(new ManageLoginsViewModel 280 | { 281 | CurrentLogins = userLogins, 282 | OtherLogins = otherLogins 283 | }); 284 | } 285 | 286 | // 287 | // POST: /Manage/LinkLogin 288 | [HttpPost] 289 | [ValidateAntiForgeryToken] 290 | public IActionResult LinkLogin(string provider) 291 | { 292 | // Request a redirect to the external login provider to link a login for the current user 293 | var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); 294 | var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); 295 | return Challenge(properties, provider); 296 | } 297 | 298 | // 299 | // GET: /Manage/LinkLoginCallback 300 | [HttpGet] 301 | public async Task LinkLoginCallback() 302 | { 303 | var user = await GetCurrentUserAsync(); 304 | if (user == null) 305 | { 306 | return View("Error"); 307 | } 308 | var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); 309 | if (info == null) 310 | { 311 | return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); 312 | } 313 | var result = await _userManager.AddLoginAsync(user, info); 314 | var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; 315 | return RedirectToAction(nameof(ManageLogins), new { Message = message }); 316 | } 317 | 318 | #region Helpers 319 | 320 | private void AddErrors(IdentityResult result) 321 | { 322 | foreach (var error in result.Errors) 323 | { 324 | ModelState.AddModelError(string.Empty, error.Description); 325 | } 326 | } 327 | 328 | public enum ManageMessageId 329 | { 330 | AddPhoneSuccess, 331 | AddLoginSuccess, 332 | ChangePasswordSuccess, 333 | SetTwoFactorSuccess, 334 | SetPasswordSuccess, 335 | RemoveLoginSuccess, 336 | RemovePhoneSuccess, 337 | Error 338 | } 339 | 340 | private Task GetCurrentUserAsync() 341 | { 342 | return _userManager.GetUserAsync(HttpContext.User); 343 | } 344 | 345 | #endregion 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /Controllers/PeopleController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace demo 6 | { 7 | [Route("api/persons")] 8 | [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true, Duration = -1)] 9 | public class PersonsController : Controller 10 | { 11 | [HttpGet] 12 | public IEnumerable GetPersons() 13 | { 14 | return new List 15 | { 16 | new Person{Name = "Max Musterman", City="Naustadt", Dob=new DateTime(1978, 07, 29)}, 17 | new Person{Name = "Maria Musterfrau", City="London", Dob=new DateTime(1979, 08, 30)}, 18 | new Person{Name = "John Doe", City="Los Angeles", Dob=new DateTime(1980, 09, 01)} 19 | }; 20 | } 21 | } 22 | 23 | public class Person 24 | { 25 | public string Name { get; set; } 26 | public string City { get; set; } 27 | public DateTime Dob { get; set; } 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore; 7 | using WebApplication.Models; 8 | 9 | namespace WebApplication.Data 10 | { 11 | public class ApplicationDbContext : IdentityDbContext 12 | { 13 | public ApplicationDbContext(DbContextOptions options) 14 | : base(options) 15 | { 16 | } 17 | 18 | protected override void OnModelCreating(ModelBuilder builder) 19 | { 20 | base.OnModelCreating(builder); 21 | // Customize the ASP.NET Identity model and override the defaults if needed. 22 | // For example, you can rename the ASP.NET Identity table names and more. 23 | // Add your customizations after calling base.OnModelCreating(builder); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using WebApplication.Data; 7 | 8 | namespace WebApplication.Data.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | [Migration("00000000000000_CreateIdentitySchema")] 12 | partial class CreateIdentitySchema 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("ProductVersion", "1.0.0-rc2-20901"); 18 | 19 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => 20 | { 21 | b.Property("Id"); 22 | 23 | b.Property("ConcurrencyStamp") 24 | .IsConcurrencyToken(); 25 | 26 | b.Property("Name") 27 | .HasAnnotation("MaxLength", 256); 28 | 29 | b.Property("NormalizedName") 30 | .HasAnnotation("MaxLength", 256); 31 | 32 | b.HasKey("Id"); 33 | 34 | b.HasIndex("NormalizedName") 35 | .HasName("RoleNameIndex"); 36 | 37 | b.ToTable("AspNetRoles"); 38 | }); 39 | 40 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 41 | { 42 | b.Property("Id") 43 | .ValueGeneratedOnAdd(); 44 | 45 | b.Property("ClaimType"); 46 | 47 | b.Property("ClaimValue"); 48 | 49 | b.Property("RoleId") 50 | .IsRequired(); 51 | 52 | b.HasKey("Id"); 53 | 54 | b.HasIndex("RoleId"); 55 | 56 | b.ToTable("AspNetRoleClaims"); 57 | }); 58 | 59 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 60 | { 61 | b.Property("Id") 62 | .ValueGeneratedOnAdd(); 63 | 64 | b.Property("ClaimType"); 65 | 66 | b.Property("ClaimValue"); 67 | 68 | b.Property("UserId") 69 | .IsRequired(); 70 | 71 | b.HasKey("Id"); 72 | 73 | b.HasIndex("UserId"); 74 | 75 | b.ToTable("AspNetUserClaims"); 76 | }); 77 | 78 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 79 | { 80 | b.Property("LoginProvider"); 81 | 82 | b.Property("ProviderKey"); 83 | 84 | b.Property("ProviderDisplayName"); 85 | 86 | b.Property("UserId") 87 | .IsRequired(); 88 | 89 | b.HasKey("LoginProvider", "ProviderKey"); 90 | 91 | b.HasIndex("UserId"); 92 | 93 | b.ToTable("AspNetUserLogins"); 94 | }); 95 | 96 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 97 | { 98 | b.Property("UserId"); 99 | 100 | b.Property("RoleId"); 101 | 102 | b.HasKey("UserId", "RoleId"); 103 | 104 | b.HasIndex("RoleId"); 105 | 106 | b.HasIndex("UserId"); 107 | 108 | b.ToTable("AspNetUserRoles"); 109 | }); 110 | 111 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => 112 | { 113 | b.Property("UserId"); 114 | 115 | b.Property("LoginProvider"); 116 | 117 | b.Property("Name"); 118 | 119 | b.Property("Value"); 120 | 121 | b.HasKey("UserId", "LoginProvider", "Name"); 122 | 123 | b.ToTable("AspNetUserTokens"); 124 | }); 125 | 126 | modelBuilder.Entity("WebApplication.Models.ApplicationUser", b => 127 | { 128 | b.Property("Id"); 129 | 130 | b.Property("AccessFailedCount"); 131 | 132 | b.Property("ConcurrencyStamp") 133 | .IsConcurrencyToken(); 134 | 135 | b.Property("Email") 136 | .HasAnnotation("MaxLength", 256); 137 | 138 | b.Property("EmailConfirmed"); 139 | 140 | b.Property("LockoutEnabled"); 141 | 142 | b.Property("LockoutEnd"); 143 | 144 | b.Property("NormalizedEmail") 145 | .HasAnnotation("MaxLength", 256); 146 | 147 | b.Property("NormalizedUserName") 148 | .HasAnnotation("MaxLength", 256); 149 | 150 | b.Property("PasswordHash"); 151 | 152 | b.Property("PhoneNumber"); 153 | 154 | b.Property("PhoneNumberConfirmed"); 155 | 156 | b.Property("SecurityStamp"); 157 | 158 | b.Property("TwoFactorEnabled"); 159 | 160 | b.Property("UserName") 161 | .HasAnnotation("MaxLength", 256); 162 | 163 | b.HasKey("Id"); 164 | 165 | b.HasIndex("NormalizedEmail") 166 | .HasName("EmailIndex"); 167 | 168 | b.HasIndex("NormalizedUserName") 169 | .HasName("UserNameIndex"); 170 | 171 | b.ToTable("AspNetUsers"); 172 | }); 173 | 174 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 175 | { 176 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 177 | .WithMany() 178 | .HasForeignKey("RoleId") 179 | .OnDelete(DeleteBehavior.Cascade); 180 | }); 181 | 182 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 183 | { 184 | b.HasOne("WebApplication.Models.ApplicationUser") 185 | .WithMany() 186 | .HasForeignKey("UserId") 187 | .OnDelete(DeleteBehavior.Cascade); 188 | }); 189 | 190 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 191 | { 192 | b.HasOne("WebApplication.Models.ApplicationUser") 193 | .WithMany() 194 | .HasForeignKey("UserId") 195 | .OnDelete(DeleteBehavior.Cascade); 196 | }); 197 | 198 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 199 | { 200 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 201 | .WithMany() 202 | .HasForeignKey("RoleId") 203 | .OnDelete(DeleteBehavior.Cascade); 204 | 205 | b.HasOne("WebApplication.Models.ApplicationUser") 206 | .WithMany() 207 | .HasForeignKey("UserId") 208 | .OnDelete(DeleteBehavior.Cascade); 209 | }); 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /Data/Migrations/00000000000000_CreateIdentitySchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace WebApplication.Data.Migrations 6 | { 7 | public partial class CreateIdentitySchema : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "AspNetRoles", 13 | columns: table => new 14 | { 15 | Id = table.Column(nullable: false), 16 | ConcurrencyStamp = table.Column(nullable: true), 17 | Name = table.Column(nullable: true), 18 | NormalizedName = table.Column(nullable: true) 19 | }, 20 | constraints: table => 21 | { 22 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 23 | }); 24 | 25 | migrationBuilder.CreateTable( 26 | name: "AspNetUserTokens", 27 | columns: table => new 28 | { 29 | UserId = table.Column(nullable: false), 30 | LoginProvider = table.Column(nullable: false), 31 | Name = table.Column(nullable: false), 32 | Value = table.Column(nullable: true) 33 | }, 34 | constraints: table => 35 | { 36 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 37 | }); 38 | 39 | migrationBuilder.CreateTable( 40 | name: "AspNetUsers", 41 | columns: table => new 42 | { 43 | Id = table.Column(nullable: false), 44 | AccessFailedCount = table.Column(nullable: false), 45 | ConcurrencyStamp = table.Column(nullable: true), 46 | Email = table.Column(nullable: true), 47 | EmailConfirmed = table.Column(nullable: false), 48 | LockoutEnabled = table.Column(nullable: false), 49 | LockoutEnd = table.Column(nullable: true), 50 | NormalizedEmail = table.Column(nullable: true), 51 | NormalizedUserName = table.Column(nullable: true), 52 | PasswordHash = table.Column(nullable: true), 53 | PhoneNumber = table.Column(nullable: true), 54 | PhoneNumberConfirmed = table.Column(nullable: false), 55 | SecurityStamp = table.Column(nullable: true), 56 | TwoFactorEnabled = table.Column(nullable: false), 57 | UserName = table.Column(nullable: true) 58 | }, 59 | constraints: table => 60 | { 61 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 62 | }); 63 | 64 | migrationBuilder.CreateTable( 65 | name: "AspNetRoleClaims", 66 | columns: table => new 67 | { 68 | Id = table.Column(nullable: false) 69 | .Annotation("Autoincrement", true), 70 | ClaimType = table.Column(nullable: true), 71 | ClaimValue = table.Column(nullable: true), 72 | RoleId = table.Column(nullable: false) 73 | }, 74 | constraints: table => 75 | { 76 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 77 | table.ForeignKey( 78 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 79 | column: x => x.RoleId, 80 | principalTable: "AspNetRoles", 81 | principalColumn: "Id", 82 | onDelete: ReferentialAction.Cascade); 83 | }); 84 | 85 | migrationBuilder.CreateTable( 86 | name: "AspNetUserClaims", 87 | columns: table => new 88 | { 89 | Id = table.Column(nullable: false) 90 | .Annotation("Autoincrement", true), 91 | ClaimType = table.Column(nullable: true), 92 | ClaimValue = table.Column(nullable: true), 93 | UserId = table.Column(nullable: false) 94 | }, 95 | constraints: table => 96 | { 97 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 98 | table.ForeignKey( 99 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 100 | column: x => x.UserId, 101 | principalTable: "AspNetUsers", 102 | principalColumn: "Id", 103 | onDelete: ReferentialAction.Cascade); 104 | }); 105 | 106 | migrationBuilder.CreateTable( 107 | name: "AspNetUserLogins", 108 | columns: table => new 109 | { 110 | LoginProvider = table.Column(nullable: false), 111 | ProviderKey = table.Column(nullable: false), 112 | ProviderDisplayName = table.Column(nullable: true), 113 | UserId = table.Column(nullable: false) 114 | }, 115 | constraints: table => 116 | { 117 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 118 | table.ForeignKey( 119 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 120 | column: x => x.UserId, 121 | principalTable: "AspNetUsers", 122 | principalColumn: "Id", 123 | onDelete: ReferentialAction.Cascade); 124 | }); 125 | 126 | migrationBuilder.CreateTable( 127 | name: "AspNetUserRoles", 128 | columns: table => new 129 | { 130 | UserId = table.Column(nullable: false), 131 | RoleId = table.Column(nullable: false) 132 | }, 133 | constraints: table => 134 | { 135 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 136 | table.ForeignKey( 137 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 138 | column: x => x.RoleId, 139 | principalTable: "AspNetRoles", 140 | principalColumn: "Id", 141 | onDelete: ReferentialAction.Cascade); 142 | table.ForeignKey( 143 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 144 | column: x => x.UserId, 145 | principalTable: "AspNetUsers", 146 | principalColumn: "Id", 147 | onDelete: ReferentialAction.Cascade); 148 | }); 149 | 150 | migrationBuilder.CreateIndex( 151 | name: "RoleNameIndex", 152 | table: "AspNetRoles", 153 | column: "NormalizedName"); 154 | 155 | migrationBuilder.CreateIndex( 156 | name: "IX_AspNetRoleClaims_RoleId", 157 | table: "AspNetRoleClaims", 158 | column: "RoleId"); 159 | 160 | migrationBuilder.CreateIndex( 161 | name: "IX_AspNetUserClaims_UserId", 162 | table: "AspNetUserClaims", 163 | column: "UserId"); 164 | 165 | migrationBuilder.CreateIndex( 166 | name: "IX_AspNetUserLogins_UserId", 167 | table: "AspNetUserLogins", 168 | column: "UserId"); 169 | 170 | migrationBuilder.CreateIndex( 171 | name: "IX_AspNetUserRoles_RoleId", 172 | table: "AspNetUserRoles", 173 | column: "RoleId"); 174 | 175 | migrationBuilder.CreateIndex( 176 | name: "IX_AspNetUserRoles_UserId", 177 | table: "AspNetUserRoles", 178 | column: "UserId"); 179 | 180 | migrationBuilder.CreateIndex( 181 | name: "EmailIndex", 182 | table: "AspNetUsers", 183 | column: "NormalizedEmail"); 184 | 185 | migrationBuilder.CreateIndex( 186 | name: "UserNameIndex", 187 | table: "AspNetUsers", 188 | column: "NormalizedUserName"); 189 | } 190 | 191 | protected override void Down(MigrationBuilder migrationBuilder) 192 | { 193 | migrationBuilder.DropTable( 194 | name: "AspNetRoleClaims"); 195 | 196 | migrationBuilder.DropTable( 197 | name: "AspNetUserClaims"); 198 | 199 | migrationBuilder.DropTable( 200 | name: "AspNetUserLogins"); 201 | 202 | migrationBuilder.DropTable( 203 | name: "AspNetUserRoles"); 204 | 205 | migrationBuilder.DropTable( 206 | name: "AspNetUserTokens"); 207 | 208 | migrationBuilder.DropTable( 209 | name: "AspNetRoles"); 210 | 211 | migrationBuilder.DropTable( 212 | name: "AspNetUsers"); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /Data/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using WebApplication.Data; 7 | 8 | namespace WebApplication.Data.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | modelBuilder 16 | .HasAnnotation("ProductVersion", "1.0.0-rc2-20901"); 17 | 18 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => 19 | { 20 | b.Property("Id"); 21 | 22 | b.Property("ConcurrencyStamp") 23 | .IsConcurrencyToken(); 24 | 25 | b.Property("Name") 26 | .HasAnnotation("MaxLength", 256); 27 | 28 | b.Property("NormalizedName") 29 | .HasAnnotation("MaxLength", 256); 30 | 31 | b.HasKey("Id"); 32 | 33 | b.HasIndex("NormalizedName") 34 | .HasName("RoleNameIndex"); 35 | 36 | b.ToTable("AspNetRoles"); 37 | }); 38 | 39 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 40 | { 41 | b.Property("Id") 42 | .ValueGeneratedOnAdd(); 43 | 44 | b.Property("ClaimType"); 45 | 46 | b.Property("ClaimValue"); 47 | 48 | b.Property("RoleId") 49 | .IsRequired(); 50 | 51 | b.HasKey("Id"); 52 | 53 | b.HasIndex("RoleId"); 54 | 55 | b.ToTable("AspNetRoleClaims"); 56 | }); 57 | 58 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 59 | { 60 | b.Property("Id") 61 | .ValueGeneratedOnAdd(); 62 | 63 | b.Property("ClaimType"); 64 | 65 | b.Property("ClaimValue"); 66 | 67 | b.Property("UserId") 68 | .IsRequired(); 69 | 70 | b.HasKey("Id"); 71 | 72 | b.HasIndex("UserId"); 73 | 74 | b.ToTable("AspNetUserClaims"); 75 | }); 76 | 77 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 78 | { 79 | b.Property("LoginProvider"); 80 | 81 | b.Property("ProviderKey"); 82 | 83 | b.Property("ProviderDisplayName"); 84 | 85 | b.Property("UserId") 86 | .IsRequired(); 87 | 88 | b.HasKey("LoginProvider", "ProviderKey"); 89 | 90 | b.HasIndex("UserId"); 91 | 92 | b.ToTable("AspNetUserLogins"); 93 | }); 94 | 95 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 96 | { 97 | b.Property("UserId"); 98 | 99 | b.Property("RoleId"); 100 | 101 | b.HasKey("UserId", "RoleId"); 102 | 103 | b.HasIndex("RoleId"); 104 | 105 | b.HasIndex("UserId"); 106 | 107 | b.ToTable("AspNetUserRoles"); 108 | }); 109 | 110 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => 111 | { 112 | b.Property("UserId"); 113 | 114 | b.Property("LoginProvider"); 115 | 116 | b.Property("Name"); 117 | 118 | b.Property("Value"); 119 | 120 | b.HasKey("UserId", "LoginProvider", "Name"); 121 | 122 | b.ToTable("AspNetUserTokens"); 123 | }); 124 | 125 | modelBuilder.Entity("WebApplication.Models.ApplicationUser", b => 126 | { 127 | b.Property("Id"); 128 | 129 | b.Property("AccessFailedCount"); 130 | 131 | b.Property("ConcurrencyStamp") 132 | .IsConcurrencyToken(); 133 | 134 | b.Property("Email") 135 | .HasAnnotation("MaxLength", 256); 136 | 137 | b.Property("EmailConfirmed"); 138 | 139 | b.Property("LockoutEnabled"); 140 | 141 | b.Property("LockoutEnd"); 142 | 143 | b.Property("NormalizedEmail") 144 | .HasAnnotation("MaxLength", 256); 145 | 146 | b.Property("NormalizedUserName") 147 | .HasAnnotation("MaxLength", 256); 148 | 149 | b.Property("PasswordHash"); 150 | 151 | b.Property("PhoneNumber"); 152 | 153 | b.Property("PhoneNumberConfirmed"); 154 | 155 | b.Property("SecurityStamp"); 156 | 157 | b.Property("TwoFactorEnabled"); 158 | 159 | b.Property("UserName") 160 | .HasAnnotation("MaxLength", 256); 161 | 162 | b.HasKey("Id"); 163 | 164 | b.HasIndex("NormalizedEmail") 165 | .HasName("EmailIndex"); 166 | 167 | b.HasIndex("NormalizedUserName") 168 | .HasName("UserNameIndex"); 169 | 170 | b.ToTable("AspNetUsers"); 171 | }); 172 | 173 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 174 | { 175 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 176 | .WithMany() 177 | .HasForeignKey("RoleId") 178 | .OnDelete(DeleteBehavior.Cascade); 179 | }); 180 | 181 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 182 | { 183 | b.HasOne("WebApplication.Models.ApplicationUser") 184 | .WithMany() 185 | .HasForeignKey("UserId") 186 | .OnDelete(DeleteBehavior.Cascade); 187 | }); 188 | 189 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 190 | { 191 | b.HasOne("WebApplication.Models.ApplicationUser") 192 | .WithMany() 193 | .HasForeignKey("UserId") 194 | .OnDelete(DeleteBehavior.Cascade); 195 | }); 196 | 197 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 198 | { 199 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 200 | .WithMany() 201 | .HasForeignKey("RoleId") 202 | .OnDelete(DeleteBehavior.Cascade); 203 | 204 | b.HasOne("WebApplication.Models.ApplicationUser") 205 | .WithMany() 206 | .HasForeignKey("UserId") 207 | .OnDelete(DeleteBehavior.Cascade); 208 | }); 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Juergen Gutsch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class ExternalLoginConfirmationViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Models/AccountViewModels/ForgotPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class ForgotPasswordViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Models/AccountViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class LoginViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | 15 | [Required] 16 | [DataType(DataType.Password)] 17 | public string Password { get; set; } 18 | 19 | [Display(Name = "Remember me?")] 20 | public bool RememberMe { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Models/AccountViewModels/RegisterViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class RegisterViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | [Display(Name = "Email")] 14 | public string Email { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 18 | [DataType(DataType.Password)] 19 | [Display(Name = "Password")] 20 | public string Password { get; set; } 21 | 22 | [DataType(DataType.Password)] 23 | [Display(Name = "Confirm password")] 24 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 25 | public string ConfirmPassword { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Models/AccountViewModels/ResetPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class ResetPasswordViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | 15 | [Required] 16 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 17 | [DataType(DataType.Password)] 18 | public string Password { get; set; } 19 | 20 | [DataType(DataType.Password)] 21 | [Display(Name = "Confirm password")] 22 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 23 | public string ConfirmPassword { get; set; } 24 | 25 | public string Code { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Models/AccountViewModels/SendCodeViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc.Rendering; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class SendCodeViewModel 10 | { 11 | public string SelectedProvider { get; set; } 12 | 13 | public ICollection Providers { get; set; } 14 | 15 | public string ReturnUrl { get; set; } 16 | 17 | public bool RememberMe { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Models/AccountViewModels/VerifyCodeViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.AccountViewModels 8 | { 9 | public class VerifyCodeViewModel 10 | { 11 | [Required] 12 | public string Provider { get; set; } 13 | 14 | [Required] 15 | public string Code { get; set; } 16 | 17 | public string ReturnUrl { get; set; } 18 | 19 | [Display(Name = "Remember this browser?")] 20 | public bool RememberBrowser { get; set; } 21 | 22 | [Display(Name = "Remember me?")] 23 | public bool RememberMe { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 6 | 7 | namespace WebApplication.Models 8 | { 9 | // Add profile data for application users by adding properties to the ApplicationUser class 10 | public class ApplicationUser : IdentityUser 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Models/ManageViewModels/AddPhoneNumberViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class AddPhoneNumberViewModel 10 | { 11 | [Required] 12 | [Phone] 13 | [Display(Name = "Phone number")] 14 | public string PhoneNumber { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Models/ManageViewModels/ChangePasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class ChangePasswordViewModel 10 | { 11 | [Required] 12 | [DataType(DataType.Password)] 13 | [Display(Name = "Current password")] 14 | public string OldPassword { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 18 | [DataType(DataType.Password)] 19 | [Display(Name = "New password")] 20 | public string NewPassword { get; set; } 21 | 22 | [DataType(DataType.Password)] 23 | [Display(Name = "Confirm new password")] 24 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 25 | public string ConfirmPassword { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Models/ManageViewModels/ConfigureTwoFactorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc.Rendering; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class ConfigureTwoFactorViewModel 10 | { 11 | public string SelectedProvider { get; set; } 12 | 13 | public ICollection Providers { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Models/ManageViewModels/FactorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebApplication.Models.ManageViewModels 7 | { 8 | public class FactorViewModel 9 | { 10 | public string Purpose { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Models/ManageViewModels/IndexViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class IndexViewModel 10 | { 11 | public bool HasPassword { get; set; } 12 | 13 | public IList Logins { get; set; } 14 | 15 | public string PhoneNumber { get; set; } 16 | 17 | public bool TwoFactor { get; set; } 18 | 19 | public bool BrowserRemembered { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Models/ManageViewModels/ManageLoginsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Http.Authentication; 6 | using Microsoft.AspNetCore.Identity; 7 | 8 | namespace WebApplication.Models.ManageViewModels 9 | { 10 | public class ManageLoginsViewModel 11 | { 12 | public IList CurrentLogins { get; set; } 13 | 14 | public IList OtherLogins { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Models/ManageViewModels/RemoveLoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class RemoveLoginViewModel 10 | { 11 | public string LoginProvider { get; set; } 12 | public string ProviderKey { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Models/ManageViewModels/SetPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class SetPasswordViewModel 10 | { 11 | [Required] 12 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 13 | [DataType(DataType.Password)] 14 | [Display(Name = "New password")] 15 | public string NewPassword { get; set; } 16 | 17 | [DataType(DataType.Password)] 18 | [Display(Name = "Confirm new password")] 19 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 20 | public string ConfirmPassword { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Models/ManageViewModels/VerifyPhoneNumberViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebApplication.Models.ManageViewModels 8 | { 9 | public class VerifyPhoneNumberViewModel 10 | { 11 | [Required] 12 | public string Code { get; set; } 13 | 14 | [Required] 15 | [Phone] 16 | [Display(Name = "Phone number")] 17 | public string PhoneNumber { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Hosting; 7 | 8 | namespace WebApplication 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = new WebHostBuilder() 15 | .UseKestrel() 16 | .UseContentRoot(Directory.GetCurrentDirectory()) 17 | .UseIISIntegration() 18 | .UseStartup() 19 | .Build(); 20 | 21 | host.Run(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to ASP.NET Core 2 | 3 | We've made some big updates in this release, so it’s **important** that you spend a few minutes to learn what’s new. 4 | 5 | You've created a new ASP.NET Core project. [Learn what's new](https://go.microsoft.com/fwlink/?LinkId=518016) 6 | 7 | ## This application consists of: 8 | 9 | * Sample pages using ASP.NET Core MVC 10 | * [Gulp](https://go.microsoft.com/fwlink/?LinkId=518007) and [Bower](https://go.microsoft.com/fwlink/?LinkId=518004) for managing client-side libraries 11 | * Theming using [Bootstrap](https://go.microsoft.com/fwlink/?LinkID=398939) 12 | 13 | ## How to 14 | 15 | * [Add a Controller and View](https://go.microsoft.com/fwlink/?LinkID=398600) 16 | * [Add an appsetting in config and access it in app.](https://go.microsoft.com/fwlink/?LinkID=699562) 17 | * [Manage User Secrets using Secret Manager.](https://go.microsoft.com/fwlink/?LinkId=699315) 18 | * [Use logging to log a message.](https://go.microsoft.com/fwlink/?LinkId=699316) 19 | * [Add packages using NuGet.](https://go.microsoft.com/fwlink/?LinkId=699317) 20 | * [Add client packages using Bower.](https://go.microsoft.com/fwlink/?LinkId=699318) 21 | * [Target development, staging or production environment.](https://go.microsoft.com/fwlink/?LinkId=699319) 22 | 23 | ## Overview 24 | 25 | * [Conceptual overview of what is ASP.NET Core](https://go.microsoft.com/fwlink/?LinkId=518008) 26 | * [Fundamentals of ASP.NET Core such as Startup and middleware.](https://go.microsoft.com/fwlink/?LinkId=699320) 27 | * [Working with Data](https://go.microsoft.com/fwlink/?LinkId=398602) 28 | * [Security](https://go.microsoft.com/fwlink/?LinkId=398603) 29 | * [Client side development](https://go.microsoft.com/fwlink/?LinkID=699321) 30 | * [Develop on different platforms](https://go.microsoft.com/fwlink/?LinkID=699322) 31 | * [Read more on the documentation site](https://go.microsoft.com/fwlink/?LinkID=699323) 32 | 33 | ## Run & Deploy 34 | 35 | * [Run your app](https://go.microsoft.com/fwlink/?LinkID=517851) 36 | * [Run tools such as EF migrations and more](https://go.microsoft.com/fwlink/?LinkID=517853) 37 | * [Publish to Microsoft Azure Web Apps](https://go.microsoft.com/fwlink/?LinkID=398609) 38 | 39 | We would love to hear your [feedback](https://go.microsoft.com/fwlink/?LinkId=518015) 40 | -------------------------------------------------------------------------------- /Services/IEmailSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebApplication.Services 7 | { 8 | public interface IEmailSender 9 | { 10 | Task SendEmailAsync(string email, string subject, string message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Services/ISmsSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebApplication.Services 7 | { 8 | public interface ISmsSender 9 | { 10 | Task SendSmsAsync(string number, string message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Services/MessageServices.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebApplication.Services 7 | { 8 | // This class is used by the application to send Email and SMS 9 | // when you turn on two-factor authentication in ASP.NET Identity. 10 | // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713 11 | public class AuthMessageSender : IEmailSender, ISmsSender 12 | { 13 | public Task SendEmailAsync(string email, string subject, string message) 14 | { 15 | // Plug in your email service here to send an email. 16 | return Task.FromResult(0); 17 | } 18 | 19 | public Task SendSmsAsync(string number, string message) 20 | { 21 | // Plug in your SMS service here to send a text message. 22 | return Task.FromResult(0); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Startup.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Logging; 9 | using WebApplication.Data; 10 | using WebApplication.Models; 11 | using WebApplication.Services; 12 | 13 | namespace WebApplication 14 | { 15 | public class Startup 16 | { 17 | public Startup(IHostingEnvironment env) 18 | { 19 | var builder = new ConfigurationBuilder() 20 | .SetBasePath(env.ContentRootPath) 21 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 22 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); 23 | 24 | if (env.IsDevelopment()) 25 | { 26 | // For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709 27 | builder.AddUserSecrets(); 28 | } 29 | 30 | builder.AddEnvironmentVariables(); 31 | Configuration = builder.Build(); 32 | } 33 | 34 | public IConfigurationRoot Configuration { get; } 35 | 36 | // This method gets called by the runtime. Use this method to add services to the container. 37 | public void ConfigureServices(IServiceCollection services) 38 | { 39 | // Add framework services. 40 | services.AddDbContext(options => 41 | options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); 42 | 43 | services.AddIdentity() 44 | .AddEntityFrameworkStores() 45 | .AddDefaultTokenProviders(); 46 | 47 | services.AddMvc(); 48 | 49 | // Add application services. 50 | services.AddTransient(); 51 | services.AddTransient(); 52 | } 53 | 54 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 55 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 56 | { 57 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 58 | loggerFactory.AddDebug(); 59 | 60 | if (env.IsDevelopment()) 61 | { 62 | app.UseDeveloperExceptionPage(); 63 | app.UseDatabaseErrorPage(); 64 | app.UseBrowserLink(); 65 | } 66 | else 67 | { 68 | app.UseExceptionHandler("/Home/Error"); 69 | } 70 | 71 | app.Use(async (context, next) => 72 | { 73 | await next(); 74 | 75 | if (context.Response.StatusCode == 404 76 | && !Path.HasExtension(context.Request.Path.Value)) 77 | { 78 | context.Request.Path = "/index.html"; 79 | await next(); 80 | } 81 | }); 82 | 83 | app.UseStaticFiles(); 84 | 85 | app.UseIdentity(); 86 | 87 | app.UseMvc(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Views/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Confirm Email"; 3 | } 4 | 5 |

@ViewData["Title"].

6 |
7 |

8 | Thank you for confirming your email. Please Click here to Log in. 9 |

10 |
11 | -------------------------------------------------------------------------------- /Views/Account/ExternalLoginConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @model ExternalLoginConfirmationViewModel 2 | @{ 3 | ViewData["Title"] = "Register"; 4 | } 5 | 6 |

@ViewData["Title"].

7 |

Associate your @ViewData["LoginProvider"] account.

8 | 9 |
10 |

Association Form

11 |
12 |
13 | 14 |

15 | You've successfully authenticated with @ViewData["LoginProvider"]. 16 | Please enter an email address for this site below and click the Register button to finish 17 | logging in. 18 |

19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 | @section Scripts { 34 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 35 | } 36 | -------------------------------------------------------------------------------- /Views/Account/ExternalLoginFailure.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Login Failure"; 3 | } 4 | 5 |
6 |

@ViewData["Title"].

7 |

Unsuccessful login with service.

8 |
9 | -------------------------------------------------------------------------------- /Views/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ForgotPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Forgot your password?"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |

8 | For more information on how to enable reset password please see this article. 9 |

10 | 11 | @*
12 |

Enter your email.

13 |
14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 |
*@ 28 | 29 | @section Scripts { 30 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 31 | } 32 | -------------------------------------------------------------------------------- /Views/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Forgot Password Confirmation"; 3 | } 4 | 5 |

@ViewData["Title"].

6 |

7 | Please check your email to reset your password. 8 |

9 | -------------------------------------------------------------------------------- /Views/Account/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Locked out"; 3 | } 4 | 5 |
6 |

Locked out.

7 |

This account has been locked out, please try again later.

8 |
9 | -------------------------------------------------------------------------------- /Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Collections.Generic 2 | @using Microsoft.AspNetCore.Http 3 | @using Microsoft.AspNetCore.Http.Authentication 4 | @model LoginViewModel 5 | @inject SignInManager SignInManager 6 | 7 | @{ 8 | ViewData["Title"] = "Log in"; 9 | } 10 | 11 |

@ViewData["Title"].

12 |
13 |
14 |
15 |
16 |

Use a local account to log in.

17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 |
33 |
34 |
35 |
36 | 40 |
41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |

49 | Register as a new user? 50 |

51 |

52 | Forgot your password? 53 |

54 |
55 |
56 |
57 |
58 |
59 |

Use another service to log in.

60 |
61 | @{ 62 | var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList(); 63 | if (loginProviders.Count == 0) 64 | { 65 |
66 |

67 | There are no external authentication services configured. See this article 68 | for details on setting up this ASP.NET application to support logging in via external services. 69 |

70 |
71 | } 72 | else 73 | { 74 |
75 |
76 |

77 | @foreach (var provider in loginProviders) 78 | { 79 | 80 | } 81 |

82 |
83 |
84 | } 85 | } 86 |
87 |
88 |
89 | 90 | @section Scripts { 91 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 92 | } 93 | -------------------------------------------------------------------------------- /Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model RegisterViewModel 2 | @{ 3 | ViewData["Title"] = "Register"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 |

Create a new account.

10 |
11 |
12 |
13 | 14 |
15 | 16 | 17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 42 | } 43 | -------------------------------------------------------------------------------- /Views/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ResetPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Reset password"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 |

Reset your password.

10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 |
21 | 22 |
23 | 24 | 25 |
26 |
27 |
28 | 29 |
30 | 31 | 32 |
33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 | 41 | @section Scripts { 42 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 43 | } 44 | -------------------------------------------------------------------------------- /Views/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Reset password confirmation"; 3 | } 4 | 5 |

@ViewData["Title"].

6 |

7 | Your password has been reset. Please Click here to log in. 8 |

9 | -------------------------------------------------------------------------------- /Views/Account/SendCode.cshtml: -------------------------------------------------------------------------------- 1 | @model SendCodeViewModel 2 | @{ 3 | ViewData["Title"] = "Send Verification Code"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 | 10 |
11 |
12 | Select Two-Factor Authentication Provider: 13 | 14 | 15 |
16 |
17 |
18 | 19 | @section Scripts { 20 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 21 | } 22 | -------------------------------------------------------------------------------- /Views/Account/VerifyCode.cshtml: -------------------------------------------------------------------------------- 1 | @model VerifyCodeViewModel 2 | @{ 3 | ViewData["Title"] = "Verify"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 |
10 | 11 | 12 |

@ViewData["Status"]

13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |
35 | 36 | @section Scripts { 37 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 38 | } 39 | -------------------------------------------------------------------------------- /Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "About"; 3 | } 4 |

@ViewData["Title"].

5 |

@ViewData["Message"]

6 | 7 |

Use this area to provide additional information.

8 | -------------------------------------------------------------------------------- /Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Contact"; 3 | } 4 |

@ViewData["Title"].

5 |

@ViewData["Message"]

6 | 7 |
8 | One Microsoft Way
9 | Redmond, WA 98052-6399
10 | P: 11 | 425.555.0100 12 |
13 | 14 |
15 | Support: Support@example.com
16 | Marketing: Marketing@example.com 17 |
18 | -------------------------------------------------------------------------------- /Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 | 67 | 68 | 110 | -------------------------------------------------------------------------------- /Views/Manage/AddPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model AddPhoneNumberViewModel 2 | @{ 3 | ViewData["Title"] = "Add Phone Number"; 4 | } 5 | 6 |

@ViewData["Title"].

7 |
8 |

Add a phone number.

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 | @section Scripts { 26 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 27 | } 28 | -------------------------------------------------------------------------------- /Views/Manage/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChangePasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Change Password"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 |

Change Password Form

10 |
11 |
12 |
13 | 14 |
15 | 16 | 17 |
18 |
19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 42 | } 43 | -------------------------------------------------------------------------------- /Views/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IndexViewModel 2 | @{ 3 | ViewData["Title"] = "Manage your account"; 4 | } 5 | 6 |

@ViewData["Title"].

7 |

@ViewData["StatusMessage"]

8 | 9 |
10 |

Change your account settings

11 |
12 |
13 |
Password:
14 |
15 | @if (Model.HasPassword) 16 | { 17 | Change 18 | } 19 | else 20 | { 21 | Create 22 | } 23 |
24 |
External Logins:
25 |
26 | 27 | @Model.Logins.Count Manage 28 |
29 |
Phone Number:
30 |
31 |

32 | Phone Numbers can used as a second factor of verification in two-factor authentication. 33 | See this article 34 | for details on setting up this ASP.NET application to support two-factor authentication using SMS. 35 |

36 | @*@(Model.PhoneNumber ?? "None") 37 | @if (Model.PhoneNumber != null) 38 | { 39 |
40 | Change 41 |
42 | [] 43 |
44 | } 45 | else 46 | { 47 | Add 48 | }*@ 49 |
50 | 51 |
Two-Factor Authentication:
52 |
53 |

54 | There are no two-factor authentication providers configured. See this article 55 | for setting up this application to support two-factor authentication. 56 |

57 | @*@if (Model.TwoFactor) 58 | { 59 |
60 | Enabled 61 |
62 | } 63 | else 64 | { 65 |
66 | Disabled 67 |
68 | }*@ 69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /Views/Manage/ManageLogins.cshtml: -------------------------------------------------------------------------------- 1 | @model ManageLoginsViewModel 2 | @using Microsoft.AspNetCore.Http.Authentication 3 | @{ 4 | ViewData["Title"] = "Manage your external logins"; 5 | } 6 | 7 |

@ViewData["Title"].

8 | 9 |

@ViewData["StatusMessage"]

10 | @if (Model.CurrentLogins.Count > 0) 11 | { 12 |

Registered Logins

13 | 14 | 15 | @for (var index = 0; index < Model.CurrentLogins.Count; index++) 16 | { 17 | 18 | 19 | 35 | 36 | } 37 | 38 |
@Model.CurrentLogins[index].LoginProvider 20 | @if ((bool)ViewData["ShowRemoveButton"]) 21 | { 22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 | } 30 | else 31 | { 32 | @:   33 | } 34 |
39 | } 40 | @if (Model.OtherLogins.Count > 0) 41 | { 42 |

Add another service to log in.

43 |
44 |
45 |
46 |

47 | @foreach (var provider in Model.OtherLogins) 48 | { 49 | 50 | } 51 |

52 |
53 |
54 | } 55 | -------------------------------------------------------------------------------- /Views/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model SetPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Set Password"; 4 | } 5 | 6 |

7 | You do not have a local username/password for this site. Add a local 8 | account so you can log in without an external login. 9 |

10 | 11 |
12 |

Set your password

13 |
14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |
35 | 36 | @section Scripts { 37 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 38 | } 39 | -------------------------------------------------------------------------------- /Views/Manage/VerifyPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model VerifyPhoneNumberViewModel 2 | @{ 3 | ViewData["Title"] = "Verify Phone Number"; 4 | } 5 | 6 |

@ViewData["Title"].

7 | 8 |
9 | 10 |

Add a phone number.

11 |
@ViewData["Status"]
12 |
13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 | @section Scripts { 29 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } 30 | } 31 | -------------------------------------------------------------------------------- /Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 |

Development Mode

9 |

10 | Swapping to Development environment will display more detailed information about the error that occurred. 11 |

12 |

13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 14 |

15 | -------------------------------------------------------------------------------- /Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - WebApplication 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 41 |
42 | @RenderBody() 43 |
44 |
45 |

© 2016 - WebApplication

46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 63 | 64 | 65 | 66 | @RenderSection("scripts", required: false) 67 | 68 | 69 | -------------------------------------------------------------------------------- /Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using WebApplication.Models 3 | 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | @if (SignInManager.IsSignedIn(User)) 8 | { 9 | 19 | } 20 | else 21 | { 22 | 26 | } 27 | -------------------------------------------------------------------------------- /Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using WebApplication 2 | @using WebApplication.Models 3 | @using WebApplication.Models.AccountViewModels 4 | @using WebApplication.Models.ManageViewModels 5 | @using Microsoft.AspNetCore.Identity 6 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 7 | -------------------------------------------------------------------------------- /Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Data Source=WebApplication.db" 4 | }, 5 | "Logging": { 6 | "IncludeScopes": false, 7 | "LogLevel": { 8 | "Default": "Debug", 9 | "System": "Information", 10 | "Microsoft": "Information" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webapplication", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap": "3.3.6", 6 | "jquery": "2.2.3", 7 | "jquery-validation": "1.15.0", 8 | "jquery-validation-unobtrusive": "3.2.6" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /// 2 | "use strict"; 3 | 4 | var gulp = require("gulp"), 5 | rimraf = require("rimraf"), 6 | concat = require("gulp-concat"), 7 | cssmin = require("gulp-cssmin"), 8 | uglify = require("gulp-uglify"); 9 | 10 | var webroot = "./wwwroot/"; 11 | 12 | var paths = { 13 | js: webroot + "js/**/*.js", 14 | minJs: webroot + "js/**/*.min.js", 15 | css: webroot + "css/**/*.css", 16 | minCss: webroot + "css/**/*.min.css", 17 | concatJsDest: webroot + "js/site.min.js", 18 | concatCssDest: webroot + "css/site.min.css" 19 | }; 20 | 21 | gulp.task("clean:js", function (cb) { 22 | rimraf(paths.concatJsDest, cb); 23 | }); 24 | 25 | gulp.task("clean:css", function (cb) { 26 | rimraf(paths.concatCssDest, cb); 27 | }); 28 | 29 | gulp.task("clean", ["clean:js", "clean:css"]); 30 | 31 | gulp.task("min:js", function () { 32 | return gulp.src([paths.js, "!" + paths.minJs], { base: "." }) 33 | .pipe(concat(paths.concatJsDest)) 34 | .pipe(uglify()) 35 | .pipe(gulp.dest(".")); 36 | }); 37 | 38 | gulp.task("min:css", function () { 39 | return gulp.src([paths.css, "!" + paths.minCss]) 40 | .pipe(concat(paths.concatCssDest)) 41 | .pipe(cssmin()) 42 | .pipe(gulp.dest(".")); 43 | }); 44 | 45 | gulp.task("min", ["min:js", "min:css"]); 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webapplication", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ", 7 | "lite": "lite-server", 8 | "postinstall": "typings install", 9 | "tsc": "tsc", 10 | "tsc:w": "tsc -w", 11 | "typings": "typings" 12 | }, 13 | "dependencies": { 14 | "@angular/common": "2.0.0", 15 | "@angular/compiler": "2.0.0", 16 | "@angular/core": "2.0.0", 17 | "@angular/forms": "2.0.0", 18 | "@angular/http": "2.0.0", 19 | "@angular/platform-browser": "2.0.0", 20 | "@angular/platform-browser-dynamic": "2.0.0", 21 | "@angular/router": "3.0.0", 22 | "@angular/upgrade": "2.0.0", 23 | 24 | "core-js": "2.4.1", 25 | "reflect-metadata": "0.1.3", 26 | "rxjs": "5.0.0-beta.12", 27 | "systemjs": "0.19.27", 28 | "zone.js": "0.6.21", 29 | 30 | "bootstrap": "3.3.6" 31 | }, 32 | "devDependencies": { 33 | "gulp": "3.9.1", 34 | "gulp-concat": "2.6.0", 35 | "gulp-cssmin": "0.1.7", 36 | "gulp-uglify": "1.5.3", 37 | "rimraf": "2.5.2", 38 | "ts-loader": "0.8.2", 39 | "ts-node": "0.5.5", 40 | "typescript": "1.8.10", 41 | "typings": "1.3.2", 42 | "webpack": "1.13.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "userSecretsId": "aspnet-WebApplication-0799fe3e-6eaf-4c5f-b40e-7c6bfd5dfa9a", 3 | 4 | "dependencies": { 5 | "Microsoft.NETCore.App": { 6 | "version": "1.0.1", 7 | "type": "platform" 8 | }, 9 | "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", 10 | "Microsoft.AspNetCore.Diagnostics": "1.0.0", 11 | "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0", 12 | "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0", 13 | "Microsoft.AspNetCore.Mvc": "1.0.1", 14 | "Microsoft.AspNetCore.Razor.Tools": { 15 | "version": "1.0.0-preview2-final", 16 | "type": "build" 17 | }, 18 | "Microsoft.AspNetCore.Routing": "1.0.1", 19 | "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", 20 | "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", 21 | "Microsoft.AspNetCore.StaticFiles": "1.0.0", 22 | "Microsoft.EntityFrameworkCore.Sqlite": "1.0.1", 23 | "Microsoft.EntityFrameworkCore.Tools": { 24 | "version": "1.0.0-preview2-final", 25 | "type": "build" 26 | }, 27 | "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", 28 | "Microsoft.Extensions.Configuration.Json": "1.0.0", 29 | "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0", 30 | "Microsoft.Extensions.Logging": "1.0.0", 31 | "Microsoft.Extensions.Logging.Console": "1.0.0", 32 | "Microsoft.Extensions.Logging.Debug": "1.0.0", 33 | "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0", 34 | "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { 35 | "version": "1.0.0-preview2-update1", 36 | "type": "build" 37 | }, 38 | "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { 39 | "version": "1.0.0-preview2-update1", 40 | "type": "build" 41 | } 42 | }, 43 | 44 | "tools": { 45 | "Microsoft.AspNetCore.Razor.Tools": { 46 | "version": "1.0.0-preview2-final", 47 | "imports": "portable-net45+win8+dnxcore50" 48 | }, 49 | "Microsoft.AspNetCore.Server.IISIntegration.Tools": { 50 | "version": "1.0.0-preview2-final", 51 | "imports": "portable-net45+win8+dnxcore50" 52 | }, 53 | "Microsoft.EntityFrameworkCore.Tools": { 54 | "version": "1.0.0-preview2-final", 55 | "imports": [ 56 | "portable-net45+win8+dnxcore50", 57 | "portable-net45+win8" 58 | ] 59 | }, 60 | "Microsoft.Extensions.SecretManager.Tools": { 61 | "version": "1.0.0-preview2-final", 62 | "imports": "portable-net45+win8+dnxcore50" 63 | }, 64 | "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { 65 | "version": "1.0.0-preview2-final", 66 | "imports": [ 67 | "portable-net45+win8+dnxcore50", 68 | "portable-net45+win8" 69 | ] 70 | } 71 | }, 72 | 73 | "frameworks": { 74 | "netcoreapp1.0": { 75 | "imports": [ 76 | "dotnet5.6", 77 | "dnxcore50", 78 | "portable-net45+win8" 79 | ] 80 | } 81 | }, 82 | 83 | "buildOptions": { 84 | "debugType": "portable", 85 | "emitEntryPoint": true, 86 | "preserveCompilationContext": true 87 | }, 88 | 89 | "runtimeOptions": { 90 | "configProperties": { 91 | "System.GC.Server": true 92 | } 93 | }, 94 | 95 | "publishOptions": { 96 | "include": [ 97 | "wwwroot", 98 | "**/*.cshtml", 99 | "appsettings.json", 100 | "web.config" 101 | ] 102 | }, 103 | 104 | "scripts": { 105 | "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ], 106 | "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] 107 | }, 108 | 109 | "tooling": { 110 | "defaultNamespace": "WebApplication" 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160725163759", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "node": "registry:dt/node#6.0.0+20160909174046" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /typings/globals/core-js/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/25e18b592470e3dddccc826fde2bb8e7610ef863/core-js/core-js.d.ts", 5 | "raw": "registry:dt/core-js#0.0.0+20160725163759", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/25e18b592470e3dddccc826fde2bb8e7610ef863/core-js/core-js.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/jasmine/index.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c49913aa9ea419ea46c1c684e488cf2a10303b1a/jasmine/jasmine.d.ts 3 | declare function describe(description: string, specDefinitions: () => void): void; 4 | declare function fdescribe(description: string, specDefinitions: () => void): void; 5 | declare function xdescribe(description: string, specDefinitions: () => void): void; 6 | 7 | declare function it(expectation: string, assertion?: () => void, timeout?: number): void; 8 | declare function it(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void; 9 | declare function fit(expectation: string, assertion?: () => void, timeout?: number): void; 10 | declare function fit(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void; 11 | declare function xit(expectation: string, assertion?: () => void, timeout?: number): void; 12 | declare function xit(expectation: string, assertion?: (done: DoneFn) => void, timeout?: number): void; 13 | 14 | /** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */ 15 | declare function pending(reason?: string): void; 16 | 17 | declare function beforeEach(action: () => void, timeout?: number): void; 18 | declare function beforeEach(action: (done: DoneFn) => void, timeout?: number): void; 19 | declare function afterEach(action: () => void, timeout?: number): void; 20 | declare function afterEach(action: (done: DoneFn) => void, timeout?: number): void; 21 | 22 | declare function beforeAll(action: () => void, timeout?: number): void; 23 | declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void; 24 | declare function afterAll(action: () => void, timeout?: number): void; 25 | declare function afterAll(action: (done: DoneFn) => void, timeout?: number): void; 26 | 27 | declare function expect(spy: Function): jasmine.Matchers; 28 | declare function expect(actual: any): jasmine.Matchers; 29 | 30 | declare function fail(e?: any): void; 31 | /** Action method that should be called when the async work is complete */ 32 | interface DoneFn extends Function { 33 | (): void; 34 | 35 | /** fails the spec and indicates that it has completed. If the message is an Error, Error.message is used */ 36 | fail: (message?: Error|string) => void; 37 | } 38 | 39 | declare function spyOn(object: any, method: string): jasmine.Spy; 40 | 41 | declare function runs(asyncMethod: Function): void; 42 | declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void; 43 | declare function waits(timeout?: number): void; 44 | 45 | declare namespace jasmine { 46 | 47 | var clock: () => Clock; 48 | 49 | function any(aclass: any): Any; 50 | function anything(): Any; 51 | function arrayContaining(sample: any[]): ArrayContaining; 52 | function objectContaining(sample: any): ObjectContaining; 53 | function createSpy(name: string, originalFn?: Function): Spy; 54 | function createSpyObj(baseName: string, methodNames: any[]): any; 55 | function createSpyObj(baseName: string, methodNames: any[]): T; 56 | function pp(value: any): string; 57 | function getEnv(): Env; 58 | function addCustomEqualityTester(equalityTester: CustomEqualityTester): void; 59 | function addMatchers(matchers: CustomMatcherFactories): void; 60 | function stringMatching(str: string): Any; 61 | function stringMatching(str: RegExp): Any; 62 | 63 | interface Any { 64 | 65 | new (expectedClass: any): any; 66 | 67 | jasmineMatches(other: any): boolean; 68 | jasmineToString(): string; 69 | } 70 | 71 | // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() 72 | interface ArrayLike { 73 | length: number; 74 | [n: number]: T; 75 | } 76 | 77 | interface ArrayContaining { 78 | new (sample: any[]): any; 79 | 80 | asymmetricMatch(other: any): boolean; 81 | jasmineToString(): string; 82 | } 83 | 84 | interface ObjectContaining { 85 | new (sample: any): any; 86 | 87 | jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean; 88 | jasmineToString(): string; 89 | } 90 | 91 | interface Block { 92 | 93 | new (env: Env, func: SpecFunction, spec: Spec): any; 94 | 95 | execute(onComplete: () => void): void; 96 | } 97 | 98 | interface WaitsBlock extends Block { 99 | new (env: Env, timeout: number, spec: Spec): any; 100 | } 101 | 102 | interface WaitsForBlock extends Block { 103 | new (env: Env, timeout: number, latchFunction: SpecFunction, message: string, spec: Spec): any; 104 | } 105 | 106 | interface Clock { 107 | install(): void; 108 | uninstall(): void; 109 | /** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */ 110 | tick(ms: number): void; 111 | mockDate(date?: Date): void; 112 | } 113 | 114 | interface CustomEqualityTester { 115 | (first: any, second: any): boolean; 116 | } 117 | 118 | interface CustomMatcher { 119 | compare(actual: T, expected: T): CustomMatcherResult; 120 | compare(actual: any, expected: any): CustomMatcherResult; 121 | } 122 | 123 | interface CustomMatcherFactory { 124 | (util: MatchersUtil, customEqualityTesters: Array): CustomMatcher; 125 | } 126 | 127 | interface CustomMatcherFactories { 128 | [index: string]: CustomMatcherFactory; 129 | } 130 | 131 | interface CustomMatcherResult { 132 | pass: boolean; 133 | message?: string; 134 | } 135 | 136 | interface MatchersUtil { 137 | equals(a: any, b: any, customTesters?: Array): boolean; 138 | contains(haystack: ArrayLike | string, needle: any, customTesters?: Array): boolean; 139 | buildFailureMessage(matcherName: string, isNot: boolean, actual: any, ...expected: Array): string; 140 | } 141 | 142 | interface Env { 143 | setTimeout: any; 144 | clearTimeout: void; 145 | setInterval: any; 146 | clearInterval: void; 147 | updateInterval: number; 148 | 149 | currentSpec: Spec; 150 | 151 | matchersClass: Matchers; 152 | 153 | version(): any; 154 | versionString(): string; 155 | nextSpecId(): number; 156 | addReporter(reporter: Reporter): void; 157 | execute(): void; 158 | describe(description: string, specDefinitions: () => void): Suite; 159 | // ddescribe(description: string, specDefinitions: () => void): Suite; Not a part of jasmine. Angular team adds these 160 | beforeEach(beforeEachFunction: () => void): void; 161 | beforeAll(beforeAllFunction: () => void): void; 162 | currentRunner(): Runner; 163 | afterEach(afterEachFunction: () => void): void; 164 | afterAll(afterAllFunction: () => void): void; 165 | xdescribe(desc: string, specDefinitions: () => void): XSuite; 166 | it(description: string, func: () => void): Spec; 167 | // iit(description: string, func: () => void): Spec; Not a part of jasmine. Angular team adds these 168 | xit(desc: string, func: () => void): XSpec; 169 | compareRegExps_(a: RegExp, b: RegExp, mismatchKeys: string[], mismatchValues: string[]): boolean; 170 | compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; 171 | equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; 172 | contains_(haystack: any, needle: any): boolean; 173 | addCustomEqualityTester(equalityTester: CustomEqualityTester): void; 174 | addMatchers(matchers: CustomMatcherFactories): void; 175 | specFilter(spec: Spec): boolean; 176 | throwOnExpectationFailure(value: boolean): void; 177 | } 178 | 179 | interface FakeTimer { 180 | 181 | new (): any; 182 | 183 | reset(): void; 184 | tick(millis: number): void; 185 | runFunctionsWithinRange(oldMillis: number, nowMillis: number): void; 186 | scheduleFunction(timeoutKey: any, funcToCall: () => void, millis: number, recurring: boolean): void; 187 | } 188 | 189 | interface HtmlReporter { 190 | new (): any; 191 | } 192 | 193 | interface HtmlSpecFilter { 194 | new (): any; 195 | } 196 | 197 | interface Result { 198 | type: string; 199 | } 200 | 201 | interface NestedResults extends Result { 202 | description: string; 203 | 204 | totalCount: number; 205 | passedCount: number; 206 | failedCount: number; 207 | 208 | skipped: boolean; 209 | 210 | rollupCounts(result: NestedResults): void; 211 | log(values: any): void; 212 | getItems(): Result[]; 213 | addResult(result: Result): void; 214 | passed(): boolean; 215 | } 216 | 217 | interface MessageResult extends Result { 218 | values: any; 219 | trace: Trace; 220 | } 221 | 222 | interface ExpectationResult extends Result { 223 | matcherName: string; 224 | passed(): boolean; 225 | expected: any; 226 | actual: any; 227 | message: string; 228 | trace: Trace; 229 | } 230 | 231 | interface Trace { 232 | name: string; 233 | message: string; 234 | stack: any; 235 | } 236 | 237 | interface PrettyPrinter { 238 | 239 | new (): any; 240 | 241 | format(value: any): void; 242 | iterateObject(obj: any, fn: (property: string, isGetter: boolean) => void): void; 243 | emitScalar(value: any): void; 244 | emitString(value: string): void; 245 | emitArray(array: any[]): void; 246 | emitObject(obj: any): void; 247 | append(value: any): void; 248 | } 249 | 250 | interface StringPrettyPrinter extends PrettyPrinter { 251 | } 252 | 253 | interface Queue { 254 | 255 | new (env: any): any; 256 | 257 | env: Env; 258 | ensured: boolean[]; 259 | blocks: Block[]; 260 | running: boolean; 261 | index: number; 262 | offset: number; 263 | abort: boolean; 264 | 265 | addBefore(block: Block, ensure?: boolean): void; 266 | add(block: any, ensure?: boolean): void; 267 | insertNext(block: any, ensure?: boolean): void; 268 | start(onComplete?: () => void): void; 269 | isRunning(): boolean; 270 | next_(): void; 271 | results(): NestedResults; 272 | } 273 | 274 | interface Matchers { 275 | 276 | new (env: Env, actual: any, spec: Env, isNot?: boolean): any; 277 | 278 | env: Env; 279 | actual: any; 280 | spec: Env; 281 | isNot?: boolean; 282 | message(): any; 283 | 284 | toBe(expected: any, expectationFailOutput?: any): boolean; 285 | toEqual(expected: any, expectationFailOutput?: any): boolean; 286 | toMatch(expected: string | RegExp, expectationFailOutput?: any): boolean; 287 | toBeDefined(expectationFailOutput?: any): boolean; 288 | toBeUndefined(expectationFailOutput?: any): boolean; 289 | toBeNull(expectationFailOutput?: any): boolean; 290 | toBeNaN(): boolean; 291 | toBeTruthy(expectationFailOutput?: any): boolean; 292 | toBeFalsy(expectationFailOutput?: any): boolean; 293 | toHaveBeenCalled(): boolean; 294 | toHaveBeenCalledWith(...params: any[]): boolean; 295 | toHaveBeenCalledTimes(expected: number): boolean; 296 | toContain(expected: any, expectationFailOutput?: any): boolean; 297 | toBeLessThan(expected: number, expectationFailOutput?: any): boolean; 298 | toBeGreaterThan(expected: number, expectationFailOutput?: any): boolean; 299 | toBeCloseTo(expected: number, precision?: any, expectationFailOutput?: any): boolean; 300 | toThrow(expected?: any): boolean; 301 | toThrowError(message?: string | RegExp): boolean; 302 | toThrowError(expected?: new (...args: any[]) => Error, message?: string | RegExp): boolean; 303 | not: Matchers; 304 | 305 | Any: Any; 306 | } 307 | 308 | interface Reporter { 309 | reportRunnerStarting(runner: Runner): void; 310 | reportRunnerResults(runner: Runner): void; 311 | reportSuiteResults(suite: Suite): void; 312 | reportSpecStarting(spec: Spec): void; 313 | reportSpecResults(spec: Spec): void; 314 | log(str: string): void; 315 | } 316 | 317 | interface MultiReporter extends Reporter { 318 | addReporter(reporter: Reporter): void; 319 | } 320 | 321 | interface Runner { 322 | 323 | new (env: Env): any; 324 | 325 | execute(): void; 326 | beforeEach(beforeEachFunction: SpecFunction): void; 327 | afterEach(afterEachFunction: SpecFunction): void; 328 | beforeAll(beforeAllFunction: SpecFunction): void; 329 | afterAll(afterAllFunction: SpecFunction): void; 330 | finishCallback(): void; 331 | addSuite(suite: Suite): void; 332 | add(block: Block): void; 333 | specs(): Spec[]; 334 | suites(): Suite[]; 335 | topLevelSuites(): Suite[]; 336 | results(): NestedResults; 337 | } 338 | 339 | interface SpecFunction { 340 | (spec?: Spec): void; 341 | } 342 | 343 | interface SuiteOrSpec { 344 | id: number; 345 | env: Env; 346 | description: string; 347 | queue: Queue; 348 | } 349 | 350 | interface Spec extends SuiteOrSpec { 351 | 352 | new (env: Env, suite: Suite, description: string): any; 353 | 354 | suite: Suite; 355 | 356 | afterCallbacks: SpecFunction[]; 357 | spies_: Spy[]; 358 | 359 | results_: NestedResults; 360 | matchersClass: Matchers; 361 | 362 | getFullName(): string; 363 | results(): NestedResults; 364 | log(arguments: any): any; 365 | runs(func: SpecFunction): Spec; 366 | addToQueue(block: Block): void; 367 | addMatcherResult(result: Result): void; 368 | expect(actual: any): any; 369 | waits(timeout: number): Spec; 370 | waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec; 371 | fail(e?: any): void; 372 | getMatchersClass_(): Matchers; 373 | addMatchers(matchersPrototype: CustomMatcherFactories): void; 374 | finishCallback(): void; 375 | finish(onComplete?: () => void): void; 376 | after(doAfter: SpecFunction): void; 377 | execute(onComplete?: () => void): any; 378 | addBeforesAndAftersToQueue(): void; 379 | explodes(): void; 380 | spyOn(obj: any, methodName: string, ignoreMethodDoesntExist: boolean): Spy; 381 | removeAllSpies(): void; 382 | } 383 | 384 | interface XSpec { 385 | id: number; 386 | runs(): void; 387 | } 388 | 389 | interface Suite extends SuiteOrSpec { 390 | 391 | new (env: Env, description: string, specDefinitions: () => void, parentSuite: Suite): any; 392 | 393 | parentSuite: Suite; 394 | 395 | getFullName(): string; 396 | finish(onComplete?: () => void): void; 397 | beforeEach(beforeEachFunction: SpecFunction): void; 398 | afterEach(afterEachFunction: SpecFunction): void; 399 | beforeAll(beforeAllFunction: SpecFunction): void; 400 | afterAll(afterAllFunction: SpecFunction): void; 401 | results(): NestedResults; 402 | add(suiteOrSpec: SuiteOrSpec): void; 403 | specs(): Spec[]; 404 | suites(): Suite[]; 405 | children(): any[]; 406 | execute(onComplete?: () => void): void; 407 | } 408 | 409 | interface XSuite { 410 | execute(): void; 411 | } 412 | 413 | interface Spy { 414 | (...params: any[]): any; 415 | 416 | identity: string; 417 | and: SpyAnd; 418 | calls: Calls; 419 | mostRecentCall: { args: any[]; }; 420 | argsForCall: any[]; 421 | wasCalled: boolean; 422 | } 423 | 424 | interface SpyAnd { 425 | /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */ 426 | callThrough(): Spy; 427 | /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */ 428 | returnValue(val: any): Spy; 429 | /** By chaining the spy with and.returnValues, all calls to the function will return specific values in order until it reaches the end of the return values list. */ 430 | returnValues(...values: any[]): Spy; 431 | /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */ 432 | callFake(fn: Function): Spy; 433 | /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */ 434 | throwError(msg: string): Spy; 435 | /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */ 436 | stub(): Spy; 437 | } 438 | 439 | interface Calls { 440 | /** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. **/ 441 | any(): boolean; 442 | /** By chaining the spy with calls.count(), will return the number of times the spy was called **/ 443 | count(): number; 444 | /** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index **/ 445 | argsFor(index: number): any[]; 446 | /** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/ 447 | allArgs(): any[]; 448 | /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/ 449 | all(): CallInfo[]; 450 | /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/ 451 | mostRecent(): CallInfo; 452 | /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/ 453 | first(): CallInfo; 454 | /** By chaining the spy with calls.reset(), will clears all tracking for a spy **/ 455 | reset(): void; 456 | } 457 | 458 | interface CallInfo { 459 | /** The context (the this) for the call */ 460 | object: any; 461 | /** All arguments passed to the call */ 462 | args: any[]; 463 | /** The return value of the call */ 464 | returnValue: any; 465 | } 466 | 467 | interface Util { 468 | inherit(childClass: Function, parentClass: Function): any; 469 | formatException(e: any): any; 470 | htmlEscape(str: string): string; 471 | argsToArray(args: any): any; 472 | extend(destination: any, source: any): any; 473 | } 474 | 475 | interface JsApiReporter extends Reporter { 476 | 477 | started: boolean; 478 | finished: boolean; 479 | result: any; 480 | messages: any; 481 | 482 | new (): any; 483 | 484 | suites(): Suite[]; 485 | summarize_(suiteOrSpec: SuiteOrSpec): any; 486 | results(): any; 487 | resultsForSpec(specId: any): any; 488 | log(str: any): any; 489 | resultsForSpecs(specIds: any): any; 490 | summarizeResult_(result: any): any; 491 | } 492 | 493 | interface Jasmine { 494 | Spec: Spec; 495 | clock: Clock; 496 | util: Util; 497 | } 498 | 499 | export var HtmlReporter: HtmlReporter; 500 | export var HtmlSpecFilter: HtmlSpecFilter; 501 | export var DEFAULT_TIMEOUT_INTERVAL: number; 502 | } 503 | -------------------------------------------------------------------------------- /typings/globals/jasmine/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c49913aa9ea419ea46c1c684e488cf2a10303b1a/jasmine/jasmine.d.ts", 5 | "raw": "registry:dt/jasmine#2.2.0+20160621224255", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c49913aa9ea419ea46c1c684e488cf2a10303b1a/jasmine/jasmine.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/node/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/4008a51db44dabcdc368097a39a01ab7a5f9587f/node/node.d.ts", 5 | "raw": "registry:dt/node#6.0.0+20160909174046", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/4008a51db44dabcdc368097a39a01ab7a5f9587f/node/node.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var fs = require('fs'); 3 | 4 | module.exports = [ 5 | { 6 | entry: { 7 | core: './node_modules/core-js/client/shim.min.js', 8 | zone: './node_modules/zone.js/dist/zone.js', 9 | reflect: './node_modules/reflect-metadata/Reflect.js', 10 | system: './node_modules/systemjs/dist/system.src.js' 11 | }, 12 | output: { 13 | filename: './wwwroot/js/[name].js' 14 | }, 15 | target: 'web', 16 | node: { 17 | fs: "empty" 18 | } 19 | }, 20 | { 21 | entry: { 22 | app: './wwwroot/app/main.ts' 23 | }, 24 | output: { 25 | filename: './wwwroot/app/bundle.js' 26 | }, 27 | devtool: 'source-map', 28 | resolve: { 29 | extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'] 30 | }, 31 | module: { 32 | loaders: [ 33 | { test: /\.ts$/, loader: 'ts-loader' } 34 | ] 35 | } 36 | }]; -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: { 3 | //vendor: './src/vendor.ts', 4 | app: "./src/main.ts" 5 | }, 6 | output: { 7 | filename: "app/bundle.js" 8 | }, 9 | devtool: 'source-map', 10 | resolve: { 11 | extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'] 12 | }, 13 | module: { 14 | loaders: [ 15 | { test: /\.ts$/, loader: 'ts-loader' } 16 | ] 17 | } 18 | }; -------------------------------------------------------------------------------- /wwwroot/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { PersonService, Person } from './person.service'; 3 | 4 | @Component({ 5 | selector: 'my-app', 6 | template: ` 7 |

My First Angular 2 App

8 |
    9 |
  • 10 | {{person.name}}
    11 | from: {{person.city}}
    12 | date of birth: {{person.dob | date: 'dd/MM/yyyy'}} 13 |
  • 14 |
15 | `, 16 | providers: [ 17 | PersonService 18 | ] 19 | }) 20 | export class AppComponent extends OnInit { 21 | 22 | constructor(private _service: PersonService) { 23 | super(); 24 | } 25 | 26 | ngOnInit() { 27 | this._service.loadData().then(data => { 28 | this.persons = data; 29 | }) 30 | } 31 | 32 | persons: Person[] = []; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /wwwroot/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpModule } from '@angular/http'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { PersonService } from './person.service'; 8 | 9 | @NgModule({ 10 | imports: [ 11 | BrowserModule, 12 | FormsModule, 13 | HttpModule], 14 | declarations: [AppComponent], 15 | providers: [ 16 | PersonService, 17 | ], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule { } 21 | -------------------------------------------------------------------------------- /wwwroot/app/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app.module'; 3 | 4 | const platform = platformBrowserDynamic(); 5 | platform.bootstrapModule(AppModule); 6 | -------------------------------------------------------------------------------- /wwwroot/app/person.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Response } from '@angular/http'; 3 | import { Observable } from 'rxjs/Rx'; 4 | import 'rxjs/add/operator/toPromise'; 5 | 6 | @Injectable() 7 | export class PersonService { 8 | constructor(private _http: Http) { } 9 | 10 | loadData(): Promise { 11 | return this._http.get('/api/persons') 12 | .toPromise() 13 | .then(response => this.extractArray(response)) 14 | .catch(this.handleErrorPromise); 15 | } 16 | 17 | protected extractArray(res: Response, showprogress: boolean = true) { 18 | let data = res.json(); 19 | return data || []; 20 | } 21 | 22 | protected handleErrorPromise(error: any): Promise { 23 | try { 24 | error = JSON.parse(error._body); 25 | } catch (e) { 26 | } 27 | 28 | let errMsg = error.errorMessage 29 | ? error.errorMessage 30 | : error.message 31 | ? error.message 32 | : error._body 33 | ? error._body 34 | : error.status 35 | ? `${error.status} - ${error.statusText}` 36 | : 'unknown server error'; 37 | 38 | console.error(errMsg); 39 | return Promise.reject(errMsg); 40 | } 41 | } 42 | export interface Person { 43 | name: string; 44 | city: string; 45 | dob: Date; 46 | } -------------------------------------------------------------------------------- /wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Wrapping element */ 7 | /* Set some basic padding to keep content from hitting the edges */ 8 | .body-content { 9 | padding-left: 15px; 10 | padding-right: 15px; 11 | } 12 | 13 | /* Set widths on the form inputs since otherwise they're 100% wide */ 14 | input, 15 | select, 16 | textarea { 17 | max-width: 280px; 18 | } 19 | 20 | /* Carousel */ 21 | .carousel-caption p { 22 | font-size: 20px; 23 | line-height: 1.4; 24 | } 25 | 26 | /* buttons and links extension to use brackets: [ click me ] */ 27 | .btn-bracketed::before { 28 | display:inline-block; 29 | content: "["; 30 | padding-right: 0.5em; 31 | } 32 | .btn-bracketed::after { 33 | display:inline-block; 34 | content: "]"; 35 | padding-left: 0.5em; 36 | } 37 | 38 | /* Hide/rearrange for smaller screens */ 39 | @media screen and (max-width: 767px) { 40 | /* Hide captions */ 41 | .carousel-caption { 42 | display: none 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.btn-bracketed::before{display:inline-block;content:"[";padding-right:.5em}.btn-bracketed::after{display:inline-block;content:"]";padding-left:.5em}@media screen and (max-width:767px){.carousel-caption{display:none}} 2 | -------------------------------------------------------------------------------- /wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuergenGutsch/angular2-aspnetcore/687e3321400c056387f1c7f305ecaf0a83308cdd/wwwroot/favicon.ico -------------------------------------------------------------------------------- /wwwroot/images/banner1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wwwroot/images/banner2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wwwroot/images/banner3.svg: -------------------------------------------------------------------------------- 1 | banner3b -------------------------------------------------------------------------------- /wwwroot/images/banner4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angular 2 QuickStart 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | Loading... 23 | 24 | 25 | -------------------------------------------------------------------------------- /wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /wwwroot/js/site.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuergenGutsch/angular2-aspnetcore/687e3321400c056387f1c7f305ecaf0a83308cdd/wwwroot/js/site.min.js -------------------------------------------------------------------------------- /wwwroot/systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function (global) { 6 | System.config({ 7 | paths: { 8 | // paths serve as alias 9 | 'npm:': '../node_modules/' 10 | }, 11 | // map tells the System loader where to look for things 12 | map: { 13 | // our app is within the app folder 14 | app: 'app', 15 | // angular bundles 16 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 17 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 18 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 19 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 20 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 21 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 22 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 23 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 24 | // other libraries 25 | 'rxjs': 'npm:rxjs', 26 | }, 27 | meta: { 28 | './app/bundle.js': { 29 | format: 'global' 30 | } 31 | }, 32 | // packages tells the System loader how to load when no filename and/or no extension 33 | packages: { 34 | app: { 35 | main: './bundle.js', 36 | defaultExtension: 'js' 37 | }, 38 | rxjs: { 39 | defaultExtension: 'js' 40 | } 41 | } 42 | }); 43 | })(this); 44 | --------------------------------------------------------------------------------