dotnet-new csproj templates (#4382)
Make csproj templates first-class in dotnet-new.
This commit is contained in:
parent
1926d0e4a4
commit
02a19aff56
102 changed files with 3670 additions and 445 deletions
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello World!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"version": "1.0.0-*",
|
||||||
|
"buildOptions": {
|
||||||
|
"debugType": "portable",
|
||||||
|
"emitEntryPoint": true
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"frameworks": {
|
||||||
|
"netcoreapp1.0": {
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"type": "platform",
|
||||||
|
"version": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": "dnxcore50"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
TestAssets/TestProjects/ProjectJsonWebTemplate/.bowerrc
Normal file
3
TestAssets/TestProjects/ProjectJsonWebTemplate/.bowerrc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"directory": "wwwroot/lib"
|
||||||
|
}
|
234
TestAssets/TestProjects/ProjectJsonWebTemplate/.gitignore
vendored
Normal file
234
TestAssets/TestProjects/ProjectJsonWebTemplate/.gitignore
vendored
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# DNX
|
||||||
|
project.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Microsoft Azure ApplicationInsights config file
|
||||||
|
ApplicationInsights.config
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
|
@ -0,0 +1,468 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using WebApplication.Models;
|
||||||
|
using WebApplication.Models.AccountViewModels;
|
||||||
|
using WebApplication.Services;
|
||||||
|
|
||||||
|
namespace WebApplication.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class AccountController : Controller
|
||||||
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
private readonly IEmailSender _emailSender;
|
||||||
|
private readonly ISmsSender _smsSender;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public AccountController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager,
|
||||||
|
IEmailSender emailSender,
|
||||||
|
ISmsSender smsSender,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_emailSender = emailSender;
|
||||||
|
_smsSender = smsSender;
|
||||||
|
_logger = loggerFactory.CreateLogger<AccountController>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/Login
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult Login(string returnUrl = null)
|
||||||
|
{
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/Login
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
|
||||||
|
{
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
// This doesn't count login failures towards account lockout
|
||||||
|
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||||
|
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(1, "User logged in.");
|
||||||
|
return RedirectToLocal(returnUrl);
|
||||||
|
}
|
||||||
|
if (result.RequiresTwoFactor)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||||
|
}
|
||||||
|
if (result.IsLockedOut)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(2, "User account locked out.");
|
||||||
|
return View("Lockout");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got this far, something failed, redisplay form
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/Register
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult Register(string returnUrl = null)
|
||||||
|
{
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/Register
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
|
||||||
|
{
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
|
||||||
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
|
||||||
|
// Send an email with this link
|
||||||
|
//var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
|
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||||
|
//await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
|
||||||
|
// $"Please confirm your account by clicking this link: <a href='{callbackUrl}'>link</a>");
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
_logger.LogInformation(3, "User created a new account with password.");
|
||||||
|
return RedirectToLocal(returnUrl);
|
||||||
|
}
|
||||||
|
AddErrors(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got this far, something failed, redisplay form
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/LogOff
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> LogOff()
|
||||||
|
{
|
||||||
|
await _signInManager.SignOutAsync();
|
||||||
|
_logger.LogInformation(4, "User logged out.");
|
||||||
|
return RedirectToAction(nameof(HomeController.Index), "Home");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/ExternalLogin
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public IActionResult ExternalLogin(string provider, string returnUrl = null)
|
||||||
|
{
|
||||||
|
// Request a redirect to the external login provider.
|
||||||
|
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
|
||||||
|
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
|
||||||
|
return Challenge(properties, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/ExternalLoginCallback
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
|
||||||
|
{
|
||||||
|
if (remoteError != null)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
|
||||||
|
return View(nameof(Login));
|
||||||
|
}
|
||||||
|
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(Login));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign in the user with this external login provider if the user already has a login.
|
||||||
|
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
|
||||||
|
return RedirectToLocal(returnUrl);
|
||||||
|
}
|
||||||
|
if (result.RequiresTwoFactor)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
|
||||||
|
}
|
||||||
|
if (result.IsLockedOut)
|
||||||
|
{
|
||||||
|
return View("Lockout");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the user does not have an account, then ask the user to create an account.
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
ViewData["LoginProvider"] = info.LoginProvider;
|
||||||
|
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
|
||||||
|
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/ExternalLoginConfirmation
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
// Get the information about the user from the external login provider
|
||||||
|
var info = await _signInManager.GetExternalLoginInfoAsync();
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
return View("ExternalLoginFailure");
|
||||||
|
}
|
||||||
|
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
|
||||||
|
var result = await _userManager.CreateAsync(user);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
result = await _userManager.AddLoginAsync(user, info);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
|
||||||
|
return RedirectToLocal(returnUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddErrors(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewData["ReturnUrl"] = returnUrl;
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: /Account/ConfirmEmail
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IActionResult> ConfirmEmail(string userId, string code)
|
||||||
|
{
|
||||||
|
if (userId == null || code == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
var user = await _userManager.FindByIdAsync(userId);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
var result = await _userManager.ConfirmEmailAsync(user, code);
|
||||||
|
return View(result.Succeeded ? "ConfirmEmail" : "Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/ForgotPassword
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult ForgotPassword()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/ForgotPassword
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Email);
|
||||||
|
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
|
||||||
|
{
|
||||||
|
// Don't reveal that the user does not exist or is not confirmed
|
||||||
|
return View("ForgotPasswordConfirmation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
|
||||||
|
// Send an email with this link
|
||||||
|
//var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||||
|
//var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
||||||
|
//await _emailSender.SendEmailAsync(model.Email, "Reset Password",
|
||||||
|
// $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
|
||||||
|
//return View("ForgotPasswordConfirmation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got this far, something failed, redisplay form
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/ForgotPasswordConfirmation
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult ForgotPasswordConfirmation()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/ResetPassword
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult ResetPassword(string code = null)
|
||||||
|
{
|
||||||
|
return code == null ? View("Error") : View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/ResetPassword
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Email);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
// Don't reveal that the user does not exist
|
||||||
|
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
|
||||||
|
}
|
||||||
|
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
|
||||||
|
}
|
||||||
|
AddErrors(result);
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/ResetPasswordConfirmation
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IActionResult ResetPasswordConfirmation()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/SendCode
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
|
||||||
|
{
|
||||||
|
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
|
||||||
|
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
|
||||||
|
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/SendCode
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> SendCode(SendCodeViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the token and send it
|
||||||
|
var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
|
||||||
|
if (string.IsNullOrWhiteSpace(code))
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = "Your security code is: " + code;
|
||||||
|
if (model.SelectedProvider == "Email")
|
||||||
|
{
|
||||||
|
await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message);
|
||||||
|
}
|
||||||
|
else if (model.SelectedProvider == "Phone")
|
||||||
|
{
|
||||||
|
await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Account/VerifyCode
|
||||||
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
|
||||||
|
{
|
||||||
|
// Require that the user has already logged in via username/password or external login
|
||||||
|
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Account/VerifyCode
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following code protects for brute force attacks against the two factor codes.
|
||||||
|
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||||
|
// will be locked out for a specified amount of time.
|
||||||
|
var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
return RedirectToLocal(model.ReturnUrl);
|
||||||
|
}
|
||||||
|
if (result.IsLockedOut)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(7, "User account locked out.");
|
||||||
|
return View("Lockout");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, "Invalid code.");
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Helpers
|
||||||
|
|
||||||
|
private void AddErrors(IdentityResult result)
|
||||||
|
{
|
||||||
|
foreach (var error in result.Errors)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||||
|
{
|
||||||
|
return _userManager.GetUserAsync(HttpContext.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IActionResult RedirectToLocal(string returnUrl)
|
||||||
|
{
|
||||||
|
if (Url.IsLocalUrl(returnUrl))
|
||||||
|
{
|
||||||
|
return Redirect(returnUrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(HomeController.Index), "Home");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace WebApplication.Controllers
|
||||||
|
{
|
||||||
|
public class HomeController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult About()
|
||||||
|
{
|
||||||
|
ViewData["Message"] = "Your application description page.";
|
||||||
|
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Contact()
|
||||||
|
{
|
||||||
|
ViewData["Message"] = "Your contact page.";
|
||||||
|
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Error()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,347 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using WebApplication.Models;
|
||||||
|
using WebApplication.Models.ManageViewModels;
|
||||||
|
using WebApplication.Services;
|
||||||
|
|
||||||
|
namespace WebApplication.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class ManageController : Controller
|
||||||
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
private readonly IEmailSender _emailSender;
|
||||||
|
private readonly ISmsSender _smsSender;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public ManageController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager,
|
||||||
|
IEmailSender emailSender,
|
||||||
|
ISmsSender smsSender,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_emailSender = emailSender;
|
||||||
|
_smsSender = smsSender;
|
||||||
|
_logger = loggerFactory.CreateLogger<ManageController>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/Index
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Index(ManageMessageId? message = null)
|
||||||
|
{
|
||||||
|
ViewData["StatusMessage"] =
|
||||||
|
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||||
|
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||||
|
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||||
|
: message == ManageMessageId.Error ? "An error has occurred."
|
||||||
|
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||||
|
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||||
|
: "";
|
||||||
|
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
var model = new IndexViewModel
|
||||||
|
{
|
||||||
|
HasPassword = await _userManager.HasPasswordAsync(user),
|
||||||
|
PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
|
||||||
|
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
|
||||||
|
Logins = await _userManager.GetLoginsAsync(user),
|
||||||
|
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user)
|
||||||
|
};
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/RemoveLogin
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
|
||||||
|
{
|
||||||
|
ManageMessageId? message = ManageMessageId.Error;
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
message = ManageMessageId.RemoveLoginSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/AddPhoneNumber
|
||||||
|
public IActionResult AddPhoneNumber()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/AddPhoneNumber
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
// Generate the token and send it
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
|
||||||
|
await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
|
||||||
|
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/EnableTwoFactorAuthentication
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> EnableTwoFactorAuthentication()
|
||||||
|
{
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
_logger.LogInformation(1, "User enabled two-factor authentication.");
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(Index), "Manage");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/DisableTwoFactorAuthentication
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> DisableTwoFactorAuthentication()
|
||||||
|
{
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
await _userManager.SetTwoFactorEnabledAsync(user, false);
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
_logger.LogInformation(2, "User disabled two-factor authentication.");
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(Index), "Manage");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/VerifyPhoneNumber
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
|
||||||
|
{
|
||||||
|
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber);
|
||||||
|
// Send an SMS to verify the phone number
|
||||||
|
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/VerifyPhoneNumber
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we got this far, something failed, redisplay the form
|
||||||
|
ModelState.AddModelError(string.Empty, "Failed to verify phone number");
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/RemovePhoneNumber
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> RemovePhoneNumber()
|
||||||
|
{
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var result = await _userManager.SetPhoneNumberAsync(user, null);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/ChangePassword
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult ChangePassword()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/ChangePassword
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
_logger.LogInformation(3, "User changed their password successfully.");
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||||
|
}
|
||||||
|
AddErrors(result);
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/SetPassword
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult SetPassword()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/SetPassword
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
|
||||||
|
}
|
||||||
|
AddErrors(result);
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||||
|
}
|
||||||
|
|
||||||
|
//GET: /Manage/ManageLogins
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
|
||||||
|
{
|
||||||
|
ViewData["StatusMessage"] =
|
||||||
|
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||||
|
: message == ManageMessageId.AddLoginSuccess ? "The external login was added."
|
||||||
|
: message == ManageMessageId.Error ? "An error has occurred."
|
||||||
|
: "";
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
var userLogins = await _userManager.GetLoginsAsync(user);
|
||||||
|
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
|
||||||
|
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
|
||||||
|
return View(new ManageLoginsViewModel
|
||||||
|
{
|
||||||
|
CurrentLogins = userLogins,
|
||||||
|
OtherLogins = otherLogins
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST: /Manage/LinkLogin
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public IActionResult LinkLogin(string provider)
|
||||||
|
{
|
||||||
|
// Request a redirect to the external login provider to link a login for the current user
|
||||||
|
var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
|
||||||
|
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
|
||||||
|
return Challenge(properties, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET: /Manage/LinkLoginCallback
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> LinkLoginCallback()
|
||||||
|
{
|
||||||
|
var user = await GetCurrentUserAsync();
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return View("Error");
|
||||||
|
}
|
||||||
|
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
|
||||||
|
}
|
||||||
|
var result = await _userManager.AddLoginAsync(user, info);
|
||||||
|
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
|
||||||
|
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Helpers
|
||||||
|
|
||||||
|
private void AddErrors(IdentityResult result)
|
||||||
|
{
|
||||||
|
foreach (var error in result.Errors)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ManageMessageId
|
||||||
|
{
|
||||||
|
AddPhoneSuccess,
|
||||||
|
AddLoginSuccess,
|
||||||
|
ChangePasswordSuccess,
|
||||||
|
SetTwoFactorSuccess,
|
||||||
|
SetPasswordSuccess,
|
||||||
|
RemoveLoginSuccess,
|
||||||
|
RemovePhoneSuccess,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||||
|
{
|
||||||
|
return _userManager.GetUserAsync(HttpContext.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using WebApplication.Models;
|
||||||
|
|
||||||
|
namespace WebApplication.Data
|
||||||
|
{
|
||||||
|
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||||
|
{
|
||||||
|
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||||
|
: base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(builder);
|
||||||
|
// Customize the ASP.NET Identity model and override the defaults if needed.
|
||||||
|
// For example, you can rename the ASP.NET Identity table names and more.
|
||||||
|
// Add your customizations after calling base.OnModelCreating(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using WebApplication.Data;
|
||||||
|
|
||||||
|
namespace WebApplication.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("00000000000000_CreateIdentitySchema")]
|
||||||
|
partial class CreateIdentitySchema
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.0.0-rc2-20901");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.HasName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("Value");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebApplication.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.HasName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace WebApplication.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class CreateIdentitySchema : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetRoles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(nullable: false),
|
||||||
|
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
NormalizedName = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserTokens",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
UserId = table.Column<string>(nullable: false),
|
||||||
|
LoginProvider = table.Column<string>(nullable: false),
|
||||||
|
Name = table.Column<string>(nullable: false),
|
||||||
|
Value = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(nullable: false),
|
||||||
|
AccessFailedCount = table.Column<int>(nullable: false),
|
||||||
|
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||||
|
Email = table.Column<string>(nullable: true),
|
||||||
|
EmailConfirmed = table.Column<bool>(nullable: false),
|
||||||
|
LockoutEnabled = table.Column<bool>(nullable: false),
|
||||||
|
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
|
||||||
|
NormalizedEmail = table.Column<string>(nullable: true),
|
||||||
|
NormalizedUserName = table.Column<string>(nullable: true),
|
||||||
|
PasswordHash = table.Column<string>(nullable: true),
|
||||||
|
PhoneNumber = table.Column<string>(nullable: true),
|
||||||
|
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
|
||||||
|
SecurityStamp = table.Column<string>(nullable: true),
|
||||||
|
TwoFactorEnabled = table.Column<bool>(nullable: false),
|
||||||
|
UserName = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetRoleClaims",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Autoincrement", true),
|
||||||
|
ClaimType = table.Column<string>(nullable: true),
|
||||||
|
ClaimValue = table.Column<string>(nullable: true),
|
||||||
|
RoleId = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||||
|
column: x => x.RoleId,
|
||||||
|
principalTable: "AspNetRoles",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserClaims",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Autoincrement", true),
|
||||||
|
ClaimType = table.Column<string>(nullable: true),
|
||||||
|
ClaimValue = table.Column<string>(nullable: true),
|
||||||
|
UserId = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserLogins",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
LoginProvider = table.Column<string>(nullable: false),
|
||||||
|
ProviderKey = table.Column<string>(nullable: false),
|
||||||
|
ProviderDisplayName = table.Column<string>(nullable: true),
|
||||||
|
UserId = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserRoles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
UserId = table.Column<string>(nullable: false),
|
||||||
|
RoleId = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||||
|
column: x => x.RoleId,
|
||||||
|
principalTable: "AspNetRoles",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "RoleNameIndex",
|
||||||
|
table: "AspNetRoles",
|
||||||
|
column: "NormalizedName");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetRoleClaims_RoleId",
|
||||||
|
table: "AspNetRoleClaims",
|
||||||
|
column: "RoleId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserClaims_UserId",
|
||||||
|
table: "AspNetUserClaims",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserLogins_UserId",
|
||||||
|
table: "AspNetUserLogins",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserRoles_RoleId",
|
||||||
|
table: "AspNetUserRoles",
|
||||||
|
column: "RoleId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserRoles_UserId",
|
||||||
|
table: "AspNetUserRoles",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "EmailIndex",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
column: "NormalizedEmail");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "UserNameIndex",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
column: "NormalizedUserName");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetRoleClaims");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserClaims");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserLogins");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserRoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserTokens");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetRoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,211 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using WebApplication.Data;
|
||||||
|
|
||||||
|
namespace WebApplication.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.0.0-rc2-20901");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.HasName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("Value");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WebApplication.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken();
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasAnnotation("MaxLength", 256);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.HasName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("WebApplication.Models.ApplicationUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class ExternalLoginConfirmationViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class ForgotPasswordViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class LoginViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Remember me?")]
|
||||||
|
public bool RememberMe { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class RegisterViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
[Display(Name = "Email")]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Password")]
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm password")]
|
||||||
|
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class ResetPasswordViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm password")]
|
||||||
|
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
|
||||||
|
public string Code { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class SendCodeViewModel
|
||||||
|
{
|
||||||
|
public string SelectedProvider { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SelectListItem> Providers { get; set; }
|
||||||
|
|
||||||
|
public string ReturnUrl { get; set; }
|
||||||
|
|
||||||
|
public bool RememberMe { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.AccountViewModels
|
||||||
|
{
|
||||||
|
public class VerifyCodeViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Provider { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public string ReturnUrl { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Remember this browser?")]
|
||||||
|
public bool RememberBrowser { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Remember me?")]
|
||||||
|
public bool RememberMe { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace WebApplication.Models
|
||||||
|
{
|
||||||
|
// Add profile data for application users by adding properties to the ApplicationUser class
|
||||||
|
public class ApplicationUser : IdentityUser
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class AddPhoneNumberViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[Phone]
|
||||||
|
[Display(Name = "Phone number")]
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class ChangePasswordViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Current password")]
|
||||||
|
public string OldPassword { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "New password")]
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm new password")]
|
||||||
|
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class ConfigureTwoFactorViewModel
|
||||||
|
{
|
||||||
|
public string SelectedProvider { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SelectListItem> Providers { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class FactorViewModel
|
||||||
|
{
|
||||||
|
public string Purpose { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class IndexViewModel
|
||||||
|
{
|
||||||
|
public bool HasPassword { get; set; }
|
||||||
|
|
||||||
|
public IList<UserLoginInfo> Logins { get; set; }
|
||||||
|
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
|
||||||
|
public bool TwoFactor { get; set; }
|
||||||
|
|
||||||
|
public bool BrowserRemembered { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class ManageLoginsViewModel
|
||||||
|
{
|
||||||
|
public IList<UserLoginInfo> CurrentLogins { get; set; }
|
||||||
|
|
||||||
|
public IList<AuthenticationDescription> OtherLogins { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class RemoveLoginViewModel
|
||||||
|
{
|
||||||
|
public string LoginProvider { get; set; }
|
||||||
|
public string ProviderKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class SetPasswordViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "New password")]
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm new password")]
|
||||||
|
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Models.ManageViewModels
|
||||||
|
{
|
||||||
|
public class VerifyPhoneNumberViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Phone]
|
||||||
|
[Display(Name = "Phone number")]
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
24
TestAssets/TestProjects/ProjectJsonWebTemplate/Program.cs
Normal file
24
TestAssets/TestProjects/ProjectJsonWebTemplate/Program.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace WebApplication
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseIISIntegration()
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
TestAssets/TestProjects/ProjectJsonWebTemplate/README.md
Normal file
39
TestAssets/TestProjects/ProjectJsonWebTemplate/README.md
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# Welcome to ASP.NET Core
|
||||||
|
|
||||||
|
We've made some big updates in this release, so it’s **important** that you spend a few minutes to learn what’s new.
|
||||||
|
|
||||||
|
You've created a new ASP.NET Core project. [Learn what's new](https://go.microsoft.com/fwlink/?LinkId=518016)
|
||||||
|
|
||||||
|
## This application consists of:
|
||||||
|
|
||||||
|
* Sample pages using ASP.NET Core MVC
|
||||||
|
* [Gulp](https://go.microsoft.com/fwlink/?LinkId=518007) and [Bower](https://go.microsoft.com/fwlink/?LinkId=518004) for managing client-side libraries
|
||||||
|
* Theming using [Bootstrap](https://go.microsoft.com/fwlink/?LinkID=398939)
|
||||||
|
|
||||||
|
## How to
|
||||||
|
|
||||||
|
* [Add a Controller and View](https://go.microsoft.com/fwlink/?LinkID=398600)
|
||||||
|
* [Add an appsetting in config and access it in app.](https://go.microsoft.com/fwlink/?LinkID=699562)
|
||||||
|
* [Manage User Secrets using Secret Manager.](https://go.microsoft.com/fwlink/?LinkId=699315)
|
||||||
|
* [Use logging to log a message.](https://go.microsoft.com/fwlink/?LinkId=699316)
|
||||||
|
* [Add packages using NuGet.](https://go.microsoft.com/fwlink/?LinkId=699317)
|
||||||
|
* [Add client packages using Bower.](https://go.microsoft.com/fwlink/?LinkId=699318)
|
||||||
|
* [Target development, staging or production environment.](https://go.microsoft.com/fwlink/?LinkId=699319)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
* [Conceptual overview of what is ASP.NET Core](https://go.microsoft.com/fwlink/?LinkId=518008)
|
||||||
|
* [Fundamentals of ASP.NET Core such as Startup and middleware.](https://go.microsoft.com/fwlink/?LinkId=699320)
|
||||||
|
* [Working with Data](https://go.microsoft.com/fwlink/?LinkId=398602)
|
||||||
|
* [Security](https://go.microsoft.com/fwlink/?LinkId=398603)
|
||||||
|
* [Client side development](https://go.microsoft.com/fwlink/?LinkID=699321)
|
||||||
|
* [Develop on different platforms](https://go.microsoft.com/fwlink/?LinkID=699322)
|
||||||
|
* [Read more on the documentation site](https://go.microsoft.com/fwlink/?LinkID=699323)
|
||||||
|
|
||||||
|
## Run & Deploy
|
||||||
|
|
||||||
|
* [Run your app](https://go.microsoft.com/fwlink/?LinkID=517851)
|
||||||
|
* [Run tools such as EF migrations and more](https://go.microsoft.com/fwlink/?LinkID=517853)
|
||||||
|
* [Publish to Microsoft Azure Web Apps](https://go.microsoft.com/fwlink/?LinkID=398609)
|
||||||
|
|
||||||
|
We would love to hear your [feedback](https://go.microsoft.com/fwlink/?LinkId=518015)
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Services
|
||||||
|
{
|
||||||
|
public interface IEmailSender
|
||||||
|
{
|
||||||
|
Task SendEmailAsync(string email, string subject, string message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Services
|
||||||
|
{
|
||||||
|
public interface ISmsSender
|
||||||
|
{
|
||||||
|
Task SendSmsAsync(string number, string message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WebApplication.Services
|
||||||
|
{
|
||||||
|
// This class is used by the application to send Email and SMS
|
||||||
|
// when you turn on two-factor authentication in ASP.NET Identity.
|
||||||
|
// For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
|
||||||
|
public class AuthMessageSender : IEmailSender, ISmsSender
|
||||||
|
{
|
||||||
|
public Task SendEmailAsync(string email, string subject, string message)
|
||||||
|
{
|
||||||
|
// Plug in your email service here to send an email.
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendSmsAsync(string number, string message)
|
||||||
|
{
|
||||||
|
// Plug in your SMS service here to send a text message.
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
TestAssets/TestProjects/ProjectJsonWebTemplate/Startup.cs
Normal file
88
TestAssets/TestProjects/ProjectJsonWebTemplate/Startup.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using WebApplication.Data;
|
||||||
|
using WebApplication.Models;
|
||||||
|
using WebApplication.Services;
|
||||||
|
|
||||||
|
namespace WebApplication
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IHostingEnvironment env)
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(env.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
|
||||||
|
builder.AddUserSecrets();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AddEnvironmentVariables();
|
||||||
|
Configuration = builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfigurationRoot Configuration { get; }
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
// Add framework services.
|
||||||
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
|
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
|
||||||
|
|
||||||
|
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||||
|
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||||
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
|
services.AddMvc();
|
||||||
|
|
||||||
|
// Add application services.
|
||||||
|
services.AddTransient<IEmailSender, AuthMessageSender>();
|
||||||
|
services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
|
loggerFactory.AddDebug();
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
app.UseDatabaseErrorPage();
|
||||||
|
app.UseBrowserLink();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.UseExceptionHandler("/Home/Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
app.UseIdentity();
|
||||||
|
|
||||||
|
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
|
||||||
|
|
||||||
|
app.UseMvc(routes =>
|
||||||
|
{
|
||||||
|
routes.MapRoute(
|
||||||
|
name: "default",
|
||||||
|
template: "{controller=Home}/{action=Index}/{id?}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Confirm Email";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Thank you for confirming your email. Please <a asp-controller="Account" asp-action="Login">Click here to Log in</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
|
@ -0,0 +1,35 @@
|
||||||
|
@model ExternalLoginConfirmationViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Register";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<h3>Associate your @ViewData["LoginProvider"] account.</h3>
|
||||||
|
|
||||||
|
<form asp-controller="Account" asp-action="ExternalLoginConfirmation" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<h4>Association Form</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
|
||||||
|
<p class="text-info">
|
||||||
|
You've successfully authenticated with <strong>@ViewData["LoginProvider"]</strong>.
|
||||||
|
Please enter an email address for this site below and click the Register button to finish
|
||||||
|
logging in.
|
||||||
|
</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Register</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Login Failure";
|
||||||
|
}
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<p class="text-danger">Unsuccessful login with service.</p>
|
||||||
|
</header>
|
|
@ -0,0 +1,31 @@
|
||||||
|
@model ForgotPasswordViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Forgot your password?";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"]</h2>
|
||||||
|
<p>
|
||||||
|
For more information on how to enable reset password please see this <a href="https://go.microsoft.com/fwlink/?LinkID=532713">article</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
@*<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal">
|
||||||
|
<h4>Enter your email.</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>*@
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Forgot Password Confirmation";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<p>
|
||||||
|
Please check your email to reset your password.
|
||||||
|
</p>
|
|
@ -0,0 +1,8 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Locked out";
|
||||||
|
}
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1 class="text-danger">Locked out.</h1>
|
||||||
|
<p class="text-danger">This account has been locked out, please try again later.</p>
|
||||||
|
</header>
|
|
@ -0,0 +1,92 @@
|
||||||
|
@using System.Collections.Generic
|
||||||
|
@using Microsoft.AspNetCore.Http
|
||||||
|
@using Microsoft.AspNetCore.Http.Authentication
|
||||||
|
@model LoginViewModel
|
||||||
|
@inject SignInManager<ApplicationUser> SignInManager
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Log in";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<section>
|
||||||
|
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<h4>Use a local account to log in.</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label asp-for="RememberMe">
|
||||||
|
<input asp-for="RememberMe" />
|
||||||
|
@Html.DisplayNameFor(m => m.RememberMe)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Log in</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Register as a new user?</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a asp-action="ForgotPassword">Forgot your password?</a>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<section>
|
||||||
|
<h4>Use another service to log in.</h4>
|
||||||
|
<hr />
|
||||||
|
@{
|
||||||
|
var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList();
|
||||||
|
if (loginProviders.Count == 0)
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
|
||||||
|
for details on setting up this ASP.NET application to support logging in via external services.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
@foreach (var provider in loginProviders)
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
@model RegisterViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Register";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Account" asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<h4>Create a new account.</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Register</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
@model ResetPasswordViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Reset password";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Account" asp-action="ResetPassword" method="post" class="form-horizontal">
|
||||||
|
<h4>Reset your password.</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<input asp-for="Code" type="hidden" />
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Password" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Reset password confirmation";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1>@ViewData["Title"].</h1>
|
||||||
|
<p>
|
||||||
|
Your password has been reset. Please <a asp-controller="Account" asp-action="Login">Click here to log in</a>.
|
||||||
|
</p>
|
|
@ -0,0 +1,21 @@
|
||||||
|
@model SendCodeViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Send Verification Code";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Account" asp-action="SendCode" asp-route-returnurl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||||
|
<input asp-for="RememberMe" type="hidden" />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
Select Two-Factor Authentication Provider:
|
||||||
|
<select asp-for="SelectedProvider" asp-items="Model.Providers"></select>
|
||||||
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
@model VerifyCodeViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Verify";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Account" asp-action="VerifyCode" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<input asp-for="Provider" type="hidden" />
|
||||||
|
<input asp-for="RememberMe" type="hidden" />
|
||||||
|
<h4>@ViewData["Status"]</h4>
|
||||||
|
<hr />
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Code" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Code" class="form-control" />
|
||||||
|
<span asp-validation-for="Code" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<input asp-for="RememberBrowser" />
|
||||||
|
<label asp-for="RememberBrowser"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "About";
|
||||||
|
}
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<h3>@ViewData["Message"]</h3>
|
||||||
|
|
||||||
|
<p>Use this area to provide additional information.</p>
|
|
@ -0,0 +1,17 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Contact";
|
||||||
|
}
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<h3>@ViewData["Message"]</h3>
|
||||||
|
|
||||||
|
<address>
|
||||||
|
One Microsoft Way<br />
|
||||||
|
Redmond, WA 98052-6399<br />
|
||||||
|
<abbr title="Phone">P:</abbr>
|
||||||
|
425.555.0100
|
||||||
|
</address>
|
||||||
|
|
||||||
|
<address>
|
||||||
|
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br />
|
||||||
|
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
|
||||||
|
</address>
|
|
@ -0,0 +1,109 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Home Page";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
|
||||||
|
<ol class="carousel-indicators">
|
||||||
|
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||||
|
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||||
|
<li data-target="#myCarousel" data-slide-to="2"></li>
|
||||||
|
<li data-target="#myCarousel" data-slide-to="3"></li>
|
||||||
|
</ol>
|
||||||
|
<div class="carousel-inner" role="listbox">
|
||||||
|
<div class="item active">
|
||||||
|
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
|
||||||
|
<div class="carousel-caption" role="option">
|
||||||
|
<p>
|
||||||
|
Learn how to build ASP.NET apps that can run anywhere.
|
||||||
|
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
|
||||||
|
Learn More
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<img src="~/images/banner2.svg" alt="Visual Studio" class="img-responsive" />
|
||||||
|
<div class="carousel-caption" role="option">
|
||||||
|
<p>
|
||||||
|
There are powerful new features in Visual Studio for building modern web apps.
|
||||||
|
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
|
||||||
|
Learn More
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<img src="~/images/banner3.svg" alt="Package Management" class="img-responsive" />
|
||||||
|
<div class="carousel-caption" role="option">
|
||||||
|
<p>
|
||||||
|
Bring in libraries from NuGet, Bower, and npm, and automate tasks using Grunt or Gulp.
|
||||||
|
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
|
||||||
|
Learn More
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<img src="~/images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
|
||||||
|
<div class="carousel-caption" role="option">
|
||||||
|
<p>
|
||||||
|
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
|
||||||
|
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
|
||||||
|
Learn More
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
|
||||||
|
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
</a>
|
||||||
|
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
|
||||||
|
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h2>Application uses</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Sample pages using ASP.NET Core MVC</li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518007">Gulp</a> and <a href="https://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
|
||||||
|
<li>Theming using <a href="https://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h2>How to</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699562">Add an appsetting in config and access it in app.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h2>Run & Deploy</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
|
||||||
|
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,27 @@
|
||||||
|
@model AddPhoneNumberViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Add Phone Number";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<form asp-controller="Manage" asp-action="AddPhoneNumber" method="post" class="form-horizontal">
|
||||||
|
<h4>Add a phone number.</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="PhoneNumber" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="PhoneNumber" class="form-control" />
|
||||||
|
<span asp-validation-for="PhoneNumber" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Send verification code</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
@model ChangePasswordViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Change Password";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Manage" asp-action="ChangePassword" method="post" class="form-horizontal">
|
||||||
|
<h4>Change Password Form</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="OldPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="OldPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="OldPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="NewPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="NewPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="NewPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Change password</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
@model IndexViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Manage your account";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
<p class="text-success">@ViewData["StatusMessage"]</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4>Change your account settings</h4>
|
||||||
|
<hr />
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>Password:</dt>
|
||||||
|
<dd>
|
||||||
|
@if (Model.HasPassword)
|
||||||
|
{
|
||||||
|
<a asp-controller="Manage" asp-action="ChangePassword" class="btn-bracketed">Change</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a asp-controller="Manage" asp-action="SetPassword" class="btn-bracketed">Create</a>
|
||||||
|
}
|
||||||
|
</dd>
|
||||||
|
<dt>External Logins:</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
@Model.Logins.Count <a asp-controller="Manage" asp-action="ManageLogins" class="btn-bracketed">Manage</a>
|
||||||
|
</dd>
|
||||||
|
<dt>Phone Number:</dt>
|
||||||
|
<dd>
|
||||||
|
<p>
|
||||||
|
Phone Numbers can used as a second factor of verification in two-factor authentication.
|
||||||
|
See <a href="https://go.microsoft.com/fwlink/?LinkID=532713">this article</a>
|
||||||
|
for details on setting up this ASP.NET application to support two-factor authentication using SMS.
|
||||||
|
</p>
|
||||||
|
@*@(Model.PhoneNumber ?? "None")
|
||||||
|
@if (Model.PhoneNumber != null)
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
<a asp-controller="Manage" asp-action="AddPhoneNumber" class="btn-bracketed">Change</a>
|
||||||
|
<form asp-controller="Manage" asp-action="RemovePhoneNumber" method="post">
|
||||||
|
[<button type="submit" class="btn-link">Remove</button>]
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a asp-controller="Manage" asp-action="AddPhoneNumber" class="btn-bracketed">Add</a>
|
||||||
|
}*@
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>Two-Factor Authentication:</dt>
|
||||||
|
<dd>
|
||||||
|
<p>
|
||||||
|
There are no two-factor authentication providers configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532713">this article</a>
|
||||||
|
for setting up this application to support two-factor authentication.
|
||||||
|
</p>
|
||||||
|
@*@if (Model.TwoFactor)
|
||||||
|
{
|
||||||
|
<form asp-controller="Manage" asp-action="DisableTwoFactorAuthentication" method="post" class="form-horizontal">
|
||||||
|
Enabled <button type="submit" class="btn-link btn-bracketed">Disable</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<form asp-controller="Manage" asp-action="EnableTwoFactorAuthentication" method="post" class="form-horizontal">
|
||||||
|
<button type="submit" class="btn-link btn-bracketed">Enable</button> Disabled
|
||||||
|
</form>
|
||||||
|
}*@
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
|
@ -0,0 +1,54 @@
|
||||||
|
@model ManageLoginsViewModel
|
||||||
|
@using Microsoft.AspNetCore.Http.Authentication
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Manage your external logins";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<p class="text-success">@ViewData["StatusMessage"]</p>
|
||||||
|
@if (Model.CurrentLogins.Count > 0)
|
||||||
|
{
|
||||||
|
<h4>Registered Logins</h4>
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
@for (var index = 0; index < Model.CurrentLogins.Count; index++)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@Model.CurrentLogins[index].LoginProvider</td>
|
||||||
|
<td>
|
||||||
|
@if ((bool)ViewData["ShowRemoveButton"])
|
||||||
|
{
|
||||||
|
<form asp-controller="Manage" asp-action="RemoveLogin" method="post" class="form-horizontal">
|
||||||
|
<div>
|
||||||
|
<input asp-for="@Model.CurrentLogins[index].LoginProvider" name="LoginProvider" type="hidden" />
|
||||||
|
<input asp-for="@Model.CurrentLogins[index].ProviderKey" name="ProviderKey" type="hidden" />
|
||||||
|
<input type="submit" class="btn btn-default" value="Remove" title="Remove this @Model.CurrentLogins[index].LoginProvider login from your account" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@:
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
@if (Model.OtherLogins.Count > 0)
|
||||||
|
{
|
||||||
|
<h4>Add another service to log in.</h4>
|
||||||
|
<hr />
|
||||||
|
<form asp-controller="Manage" asp-action="LinkLogin" method="post" class="form-horizontal">
|
||||||
|
<div id="socialLoginList">
|
||||||
|
<p>
|
||||||
|
@foreach (var provider in Model.OtherLogins)
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
@model SetPasswordViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Set Password";
|
||||||
|
}
|
||||||
|
|
||||||
|
<p class="text-info">
|
||||||
|
You do not have a local username/password for this site. Add a local
|
||||||
|
account so you can log in without an external login.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form asp-controller="Manage" asp-action="SetPassword" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<h4>Set your password</h4>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="NewPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="NewPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="NewPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Set password</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
@model VerifyPhoneNumberViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Verify Phone Number";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>@ViewData["Title"].</h2>
|
||||||
|
|
||||||
|
<form asp-controller="Manage" asp-action="VerifyPhoneNumber" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
|
||||||
|
<input asp-for="PhoneNumber" type="hidden" />
|
||||||
|
<h4>Add a phone number.</h4>
|
||||||
|
<h5>@ViewData["Status"]</h5>
|
||||||
|
<hr />
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Code" class="col-md-2 control-label"></label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input asp-for="Code" class="form-control" />
|
||||||
|
<span asp-validation-for="Code" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1 class="text-danger">Error.</h1>
|
||||||
|
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||||
|
|
||||||
|
<h3>Development Mode</h3>
|
||||||
|
<p>
|
||||||
|
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Development environment should not be enabled in deployed applications</strong>, 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 <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
|
||||||
|
</p>
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>@ViewData["Title"] - WebApplication</title>
|
||||||
|
|
||||||
|
<environment names="Development">
|
||||||
|
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
||||||
|
<link rel="stylesheet" href="~/css/site.css" />
|
||||||
|
</environment>
|
||||||
|
<environment names="Staging,Production">
|
||||||
|
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
|
||||||
|
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
|
||||||
|
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
|
||||||
|
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
|
||||||
|
</environment>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a asp-controller="Home" asp-action="Index" class="navbar-brand">WebApplication</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
|
||||||
|
<li><a asp-controller="Home" asp-action="About">About</a></li>
|
||||||
|
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
@await Html.PartialAsync("_LoginPartial")
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container body-content">
|
||||||
|
@RenderBody()
|
||||||
|
<hr />
|
||||||
|
<footer>
|
||||||
|
<p>© 2016 - WebApplication</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<environment names="Development">
|
||||||
|
<script src="~/lib/jquery/dist/jquery.js"></script>
|
||||||
|
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||||
|
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||||
|
</environment>
|
||||||
|
<environment names="Staging,Production">
|
||||||
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.3.min.js"
|
||||||
|
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
||||||
|
asp-fallback-test="window.jQuery">
|
||||||
|
</script>
|
||||||
|
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
|
||||||
|
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
|
||||||
|
</script>
|
||||||
|
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
||||||
|
</environment>
|
||||||
|
|
||||||
|
@RenderSection("scripts", required: false)
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
@using Microsoft.AspNetCore.Identity
|
||||||
|
@using WebApplication.Models
|
||||||
|
|
||||||
|
@inject SignInManager<ApplicationUser> SignInManager
|
||||||
|
@inject UserManager<ApplicationUser> UserManager
|
||||||
|
|
||||||
|
@if (SignInManager.IsSignedIn(User))
|
||||||
|
{
|
||||||
|
<form asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="navbar-right">
|
||||||
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
<li>
|
||||||
|
<a asp-controller="Manage" asp-action="Index" title="Manage">Hello @UserManager.GetUserName(User)!</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button type="submit" class="btn btn-link navbar-btn navbar-link">Log off</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
<li><a asp-controller="Account" asp-action="Register">Register</a></li>
|
||||||
|
<li><a asp-controller="Account" asp-action="Login">Log in</a></li>
|
||||||
|
</ul>
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<environment names="Development">
|
||||||
|
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
|
||||||
|
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
|
||||||
|
</environment>
|
||||||
|
<environment names="Staging,Production">
|
||||||
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js"
|
||||||
|
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator">
|
||||||
|
</script>
|
||||||
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
|
||||||
|
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
||||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive">
|
||||||
|
</script>
|
||||||
|
</environment>
|
|
@ -0,0 +1,6 @@
|
||||||
|
@using WebApplication
|
||||||
|
@using WebApplication.Models
|
||||||
|
@using WebApplication.Models.AccountViewModels
|
||||||
|
@using WebApplication.Models.ManageViewModels
|
||||||
|
@using Microsoft.AspNetCore.Identity
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
@ -0,0 +1,3 @@
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DefaultConnection": "Data Source=WebApplication.db"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"System": "Information",
|
||||||
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
TestAssets/TestProjects/ProjectJsonWebTemplate/bower.json
Normal file
10
TestAssets/TestProjects/ProjectJsonWebTemplate/bower.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name": "webapplication",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bootstrap": "3.3.6",
|
||||||
|
"jquery": "2.2.3",
|
||||||
|
"jquery-validation": "1.15.0",
|
||||||
|
"jquery-validation-unobtrusive": "3.2.6"
|
||||||
|
}
|
||||||
|
}
|
45
TestAssets/TestProjects/ProjectJsonWebTemplate/gulpfile.js
Normal file
45
TestAssets/TestProjects/ProjectJsonWebTemplate/gulpfile.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/// <binding Clean='clean' />
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var gulp = require("gulp"),
|
||||||
|
rimraf = require("rimraf"),
|
||||||
|
concat = require("gulp-concat"),
|
||||||
|
cssmin = require("gulp-cssmin"),
|
||||||
|
uglify = require("gulp-uglify");
|
||||||
|
|
||||||
|
var webroot = "./wwwroot/";
|
||||||
|
|
||||||
|
var paths = {
|
||||||
|
js: webroot + "js/**/*.js",
|
||||||
|
minJs: webroot + "js/**/*.min.js",
|
||||||
|
css: webroot + "css/**/*.css",
|
||||||
|
minCss: webroot + "css/**/*.min.css",
|
||||||
|
concatJsDest: webroot + "js/site.min.js",
|
||||||
|
concatCssDest: webroot + "css/site.min.css"
|
||||||
|
};
|
||||||
|
|
||||||
|
gulp.task("clean:js", function (cb) {
|
||||||
|
rimraf(paths.concatJsDest, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("clean:css", function (cb) {
|
||||||
|
rimraf(paths.concatCssDest, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("clean", ["clean:js", "clean:css"]);
|
||||||
|
|
||||||
|
gulp.task("min:js", function () {
|
||||||
|
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
|
||||||
|
.pipe(concat(paths.concatJsDest))
|
||||||
|
.pipe(uglify())
|
||||||
|
.pipe(gulp.dest("."));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("min:css", function () {
|
||||||
|
return gulp.src([paths.css, "!" + paths.minCss])
|
||||||
|
.pipe(concat(paths.concatCssDest))
|
||||||
|
.pipe(cssmin())
|
||||||
|
.pipe(gulp.dest("."));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("min", ["min:js", "min:css"]);
|
12
TestAssets/TestProjects/ProjectJsonWebTemplate/package.json
Normal file
12
TestAssets/TestProjects/ProjectJsonWebTemplate/package.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "webapplication",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "3.9.1",
|
||||||
|
"gulp-concat": "2.6.0",
|
||||||
|
"gulp-cssmin": "0.1.7",
|
||||||
|
"gulp-uglify": "1.5.3",
|
||||||
|
"rimraf": "2.5.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"userSecretsId": "aspnet-WebApplication-0799fe3e-6eaf-4c5f-b40e-7c6bfd5dfa9a",
|
||||||
|
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"type": "platform"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
|
||||||
|
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
|
||||||
|
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
|
||||||
|
"Microsoft.AspNetCore.Mvc": "1.0.1",
|
||||||
|
"Microsoft.AspNetCore.Razor.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"type": "build"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.Routing": "1.0.1",
|
||||||
|
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||||
|
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
|
||||||
|
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
|
||||||
|
"Microsoft.EntityFrameworkCore.Sqlite": "1.0.1",
|
||||||
|
"Microsoft.EntityFrameworkCore.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"type": "build"
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.Json": "1.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
|
||||||
|
"Microsoft.Extensions.Logging": "1.0.0",
|
||||||
|
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||||
|
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||||
|
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
|
||||||
|
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
|
||||||
|
"version": "1.0.0-preview2-update1",
|
||||||
|
"type": "build"
|
||||||
|
},
|
||||||
|
"Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
|
||||||
|
"version": "1.0.0-preview2-update1",
|
||||||
|
"type": "build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"tools": {
|
||||||
|
"Microsoft.AspNetCore.Razor.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"imports": "portable-net45+win8+dnxcore50"
|
||||||
|
},
|
||||||
|
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"imports": "portable-net45+win8+dnxcore50"
|
||||||
|
},
|
||||||
|
"Microsoft.EntityFrameworkCore.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"imports": [
|
||||||
|
"portable-net45+win8+dnxcore50",
|
||||||
|
"portable-net45+win8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.SecretManager.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"imports": "portable-net45+win8+dnxcore50"
|
||||||
|
},
|
||||||
|
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
|
||||||
|
"version": "1.0.0-preview2-final",
|
||||||
|
"imports": [
|
||||||
|
"portable-net45+win8+dnxcore50",
|
||||||
|
"portable-net45+win8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"frameworks": {
|
||||||
|
"netcoreapp1.0": {
|
||||||
|
"imports": [
|
||||||
|
"dotnet5.6",
|
||||||
|
"dnxcore50",
|
||||||
|
"portable-net45+win8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"buildOptions": {
|
||||||
|
"debugType": "portable",
|
||||||
|
"emitEntryPoint": true,
|
||||||
|
"preserveCompilationContext": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"runtimeOptions": {
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Server": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"publishOptions": {
|
||||||
|
"include": [
|
||||||
|
"wwwroot",
|
||||||
|
"**/*.cshtml",
|
||||||
|
"appsettings.json",
|
||||||
|
"web.config"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ],
|
||||||
|
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
"tooling": {
|
||||||
|
"defaultNamespace": "WebApplication"
|
||||||
|
}
|
||||||
|
}
|
14
TestAssets/TestProjects/ProjectJsonWebTemplate/web.config
Normal file
14
TestAssets/TestProjects/ProjectJsonWebTemplate/web.config
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Configure your application settings in appsettings.json. Learn more at https://go.microsoft.com/fwlink/?LinkId=786380
|
||||||
|
-->
|
||||||
|
|
||||||
|
<system.webServer>
|
||||||
|
<handlers>
|
||||||
|
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
||||||
|
</handlers>
|
||||||
|
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,44 @@
|
||||||
|
body {
|
||||||
|
padding-top: 50px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapping element */
|
||||||
|
/* Set some basic padding to keep content from hitting the edges */
|
||||||
|
.body-content {
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set widths on the form inputs since otherwise they're 100% wide */
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel */
|
||||||
|
.carousel-caption p {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buttons and links extension to use brackets: [ click me ] */
|
||||||
|
.btn-bracketed::before {
|
||||||
|
display:inline-block;
|
||||||
|
content: "[";
|
||||||
|
padding-right: 0.5em;
|
||||||
|
}
|
||||||
|
.btn-bracketed::after {
|
||||||
|
display:inline-block;
|
||||||
|
content: "]";
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide/rearrange for smaller screens */
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
/* Hide captions */
|
||||||
|
.carousel-caption {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
}
|
1
TestAssets/TestProjects/ProjectJsonWebTemplate/wwwroot/css/site.min.css
vendored
Normal file
1
TestAssets/TestProjects/ProjectJsonWebTemplate/wwwroot/css/site.min.css
vendored
Normal file
|
@ -0,0 +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}}
|
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.5 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.2 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1 @@
|
||||||
|
// Write your Javascript code.
|
0
TestAssets/TestProjects/ProjectJsonWebTemplate/wwwroot/js/site.min.js
vendored
Normal file
0
TestAssets/TestProjects/ProjectJsonWebTemplate/wwwroot/js/site.min.js
vendored
Normal file
|
@ -12,6 +12,7 @@
|
||||||
<UsingTask TaskName="DotNetPack" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DotNetPack" AssemblyFile="$(CLIBuildDll)" />
|
||||||
<UsingTask TaskName="DotNetPublish" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DotNetPublish" AssemblyFile="$(CLIBuildDll)" />
|
||||||
<UsingTask TaskName="DotNetRestore" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DotNetRestore" AssemblyFile="$(CLIBuildDll)" />
|
||||||
|
<UsingTask TaskName="DotNetRestore3" AssemblyFile="$(CLIBuildDll)" />
|
||||||
<UsingTask TaskName="DotNetTest" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DotNetTest" AssemblyFile="$(CLIBuildDll)" />
|
||||||
<UsingTask TaskName="DownloadFile" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DownloadFile" AssemblyFile="$(CLIBuildDll)" />
|
||||||
<UsingTask TaskName="GenerateBuildVersionInfo" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="GenerateBuildVersionInfo" AssemblyFile="$(CLIBuildDll)" />
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
|
|
||||||
<DotNetNew ToolPath="$(Stage2Directory)"
|
<DotNetNew ToolPath="$(Stage2Directory)"
|
||||||
WorkingDirectory="$(NuGetPackagesArchiveProject)" />
|
WorkingDirectory="$(NuGetPackagesArchiveProject)" />
|
||||||
<DotNetRestore ToolPath="$(Stage2Directory)"
|
|
||||||
|
<DotNetRestore3 ToolPath="$(Stage2Directory)"
|
||||||
Packages="$(NuGetPackagesArchiveFolder)"
|
Packages="$(NuGetPackagesArchiveFolder)"
|
||||||
|
SkipInvalidConfigurations="True"
|
||||||
WorkingDirectory="$(NuGetPackagesArchiveProject)" />
|
WorkingDirectory="$(NuGetPackagesArchiveProject)" />
|
||||||
|
|
||||||
<Delete Files="$(IntermediateArchive);$(IntermediateArchive).zip" />
|
<Delete Files="$(IntermediateArchive);$(IntermediateArchive).zip" />
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
<!-- workaround for https://github.com/Microsoft/msbuild/issues/885 -->
|
<!-- workaround for https://github.com/Microsoft/msbuild/issues/885 -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<CLIBuildDll Condition=" '!Exists($(CLIBuildDll))' ">$([MSBuild]::Unescape($(CLIBuildDll)))</CLIBuildDll>
|
<CLIBuildDll>$([MSBuild]::Unescape($(CLIBuildDll)))</CLIBuildDll>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
<UsingTask TaskName="DotNetTest" AssemblyFile="$(CLIBuildDll)" />
|
<UsingTask TaskName="DotNetTest" AssemblyFile="$(CLIBuildDll)" />
|
||||||
|
|
||||||
<Target Name="RunTest">
|
<Target Name="RunTest">
|
||||||
|
|
54
build_projects/dotnet-cli-build/DotNetRestore3.cs
Normal file
54
build_projects/dotnet-cli-build/DotNetRestore3.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli.Build
|
||||||
|
{
|
||||||
|
public class DotNetRestore3 : DotNetTool
|
||||||
|
{
|
||||||
|
protected override string Command
|
||||||
|
{
|
||||||
|
get { return "restore3"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Args
|
||||||
|
{
|
||||||
|
get { return $"{GetSource()} {GetPackages()} {GetSkipInvalidConfigurations()}"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Source { get; set; }
|
||||||
|
|
||||||
|
public string Packages { get; set; }
|
||||||
|
|
||||||
|
public bool SkipInvalidConfigurations { get; set; }
|
||||||
|
|
||||||
|
private string GetSource()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Source))
|
||||||
|
{
|
||||||
|
return $"--source {Source}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetPackages()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Packages))
|
||||||
|
{
|
||||||
|
return $"--packages {Packages}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSkipInvalidConfigurations()
|
||||||
|
{
|
||||||
|
if (SkipInvalidConfigurations)
|
||||||
|
{
|
||||||
|
return "/p:SkipInvalidConfigurations=true";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,8 +86,8 @@ namespace Microsoft.DotNet.Configurer
|
||||||
private bool RestoreTemporaryProject(string extractedPackagesArchiveDirectory, string workingDirectory)
|
private bool RestoreTemporaryProject(string extractedPackagesArchiveDirectory, string workingDirectory)
|
||||||
{
|
{
|
||||||
return RunCommand(
|
return RunCommand(
|
||||||
"restore",
|
"restore3",
|
||||||
new[] {"-s", $"{extractedPackagesArchiveDirectory}"},
|
new[] {"-s", extractedPackagesArchiveDirectory},
|
||||||
workingDirectory);
|
workingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Microsoft.DotNet.Tools.Migrate
|
||||||
" - a directory to migrate, it will recursively search for project.json files to migrate.",
|
" - a directory to migrate, it will recursively search for project.json files to migrate.",
|
||||||
"Defaults to current directory if nothing is specified."));
|
"Defaults to current directory if nothing is specified."));
|
||||||
|
|
||||||
CommandOption template = app.Option("-t|--template-file", "Base MSBuild template to use for migrated app. The default is the project included in dotnet new -t msbuild", CommandOptionType.SingleValue);
|
CommandOption template = app.Option("-t|--template-file", "Base MSBuild template to use for migrated app. The default is the project included in dotnet new", CommandOptionType.SingleValue);
|
||||||
CommandOption sdkVersion = app.Option("-v|--sdk-package-version", "The version of the sdk package that will be referenced in the migrated app. The default is the version of the sdk in dotnet new -t msbuild", CommandOptionType.SingleValue);
|
CommandOption sdkVersion = app.Option("-v|--sdk-package-version", "The version of the sdk package that will be referenced in the migrated app. The default is the version of the sdk in dotnet new -t msbuild", CommandOptionType.SingleValue);
|
||||||
CommandOption xprojFile = app.Option("-x|--xproj-file", "The path to the xproj file to use. Required when there is more than one xproj in a project directory.", CommandOptionType.SingleValue);
|
CommandOption xprojFile = app.Option("-x|--xproj-file", "The path to the xproj file to use. Required when there is more than one xproj in a project directory.", CommandOptionType.SingleValue);
|
||||||
CommandOption skipProjectReferences = app.Option("-s|--skip-project-references", "Skip migrating project references. By default project references are migrated recursively", CommandOptionType.BoolValue);
|
CommandOption skipProjectReferences = app.Option("-s|--skip-project-references", "Skip migrating project references. By default project references are migrated recursively", CommandOptionType.BoolValue);
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Microsoft.DotNet.Tools.Migrate
|
||||||
}
|
}
|
||||||
Directory.CreateDirectory(tempDir);
|
Directory.CreateDirectory(tempDir);
|
||||||
|
|
||||||
RunCommand("new", new string[] { "-t", "msbuild" }, tempDir);
|
RunCommand("new", new string[] {}, tempDir);
|
||||||
|
|
||||||
return tempDir;
|
return tempDir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFrameworks>netcoreapp1.0</TargetFrameworks>
|
<TargetFrameworks>netcoreapp1.0</TargetFrameworks>
|
||||||
<OutputPath>bin\$(Configuration)</OutputPath>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -17,10 +16,10 @@
|
||||||
<Version>1.0.1</Version>
|
<Version>1.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Sdk">
|
<PackageReference Include="Microsoft.NET.Sdk">
|
||||||
<Version>1.0.0-alpha-20161010-1</Version>
|
<Version>1.0.0-alpha-20161012-3</Version>
|
||||||
<PrivateAssets>All</PrivateAssets>
|
<PrivateAssets>All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.0-*",
|
|
||||||
"buildOptions": {
|
|
||||||
"debugType": "portable",
|
|
||||||
"emitEntryPoint": true
|
|
||||||
},
|
|
||||||
"dependencies": {},
|
|
||||||
"frameworks": {
|
|
||||||
"netcoreapp1.0": {
|
|
||||||
"dependencies": {
|
|
||||||
"Microsoft.NETCore.App": {
|
|
||||||
"type": "platform",
|
|
||||||
"version": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"imports": "dnxcore50"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
24
src/dotnet/commands/dotnet-new/CSharp_Lib/$projectName$.csproj
Executable file
24
src/dotnet/commands/dotnet-new/CSharp_Lib/$projectName$.csproj
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>netstandard1.4</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="**\*.cs" />
|
||||||
|
<EmbeddedResource Include="**\*.resx" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NETStandard.Library">
|
||||||
|
<Version>1.6</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Sdk">
|
||||||
|
<Version>1.0.0-alpha-20161012-3</Version>
|
||||||
|
<PrivateAssets>All</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -4,8 +4,5 @@ namespace ClassLibrary
|
||||||
{
|
{
|
||||||
public class Class1
|
public class Class1
|
||||||
{
|
{
|
||||||
public void Method1()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.0-*",
|
|
||||||
"buildOptions": {
|
|
||||||
"debugType": "portable"
|
|
||||||
},
|
|
||||||
"dependencies": {},
|
|
||||||
"frameworks": {
|
|
||||||
"netstandard1.6": {
|
|
||||||
"dependencies": {
|
|
||||||
"NETStandard.Library": "1.6.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ConsoleApplication
|
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Hello World!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,10 +28,10 @@ namespace Microsoft.DotNet.Tools.New
|
||||||
return parts[parts.Length - 2] + "." + parts[parts.Length - 1];
|
return parts[parts.Length - 2] + "." + parts[parts.Length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateEmptyProject(string languageName, string templateDir)
|
public int CreateEmptyProject(string languageName, string templateDir, bool isMsBuild)
|
||||||
{
|
{
|
||||||
// Check if project.json exists in the folder
|
// Check if project.json exists in the folder
|
||||||
if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "project.json")))
|
if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "project.json")) && !isMsBuild)
|
||||||
{
|
{
|
||||||
Reporter.Error.WriteLine($"Creating new {languageName} project failed, project already exists.");
|
Reporter.Error.WriteLine($"Creating new {languageName} project failed, project already exists.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -69,8 +69,12 @@ namespace Microsoft.DotNet.Tools.New
|
||||||
|
|
||||||
archive.ExtractToDirectory(projectDirectory);
|
archive.ExtractToDirectory(projectDirectory);
|
||||||
|
|
||||||
ReplaceProjectJsonTemplateValues(projectDirectory);
|
|
||||||
ReplaceFileTemplateNames(projectDirectory);
|
ReplaceFileTemplateNames(projectDirectory);
|
||||||
|
|
||||||
|
if (!isMsBuild)
|
||||||
|
{
|
||||||
|
ReplaceProjectJsonTemplateValues(projectDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
|
@ -128,15 +132,31 @@ namespace Microsoft.DotNet.Tools.New
|
||||||
app.Description = "Initializes empty project for .NET Platform";
|
app.Description = "Initializes empty project for .NET Platform";
|
||||||
app.HelpOption("-h|--help");
|
app.HelpOption("-h|--help");
|
||||||
|
|
||||||
var csharp = new { Name = "C#", Alias = new[] { "c#", "cs", "csharp" }, TemplatePrefix = "CSharp", Templates = new[] { "Console", "Web", "Lib", "xunittest", "nunittest", "MSBuild" } };
|
var csharp = new { Name = "C#", Alias = new[] { "c#", "cs", "csharp" }, TemplatePrefix = "CSharp",
|
||||||
var fsharp = new { Name = "F#", Alias = new[] { "f#", "fs", "fsharp" }, TemplatePrefix = "FSharp", Templates = new[] { "Console", "Lib" } };
|
Templates = new[]
|
||||||
|
{
|
||||||
|
new { Name = "Console", isMsBuild = true },
|
||||||
|
new { Name = "Web", isMsBuild = false },
|
||||||
|
new { Name = "Lib", isMsBuild = true },
|
||||||
|
new { Name = "xunittest", isMsBuild = false },
|
||||||
|
new { Name = "nunittest", isMsBuild = false }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var fsharp = new { Name = "F#", Alias = new[] { "f#", "fs", "fsharp" }, TemplatePrefix = "FSharp",
|
||||||
|
Templates = new[]
|
||||||
|
{
|
||||||
|
new { Name = "Console", isMsBuild = false },
|
||||||
|
new { Name = "Lib", isMsBuild = false }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var languages = new[] { csharp, fsharp };
|
var languages = new[] { csharp, fsharp };
|
||||||
|
|
||||||
string langValuesString = string.Join(", ", languages.Select(l => l.Name));
|
string langValuesString = string.Join(", ", languages.Select(l => l.Name));
|
||||||
var typeValues =
|
var typeValues =
|
||||||
from l in languages
|
from l in languages
|
||||||
let values = string.Join(", ", l.Templates)
|
let values = string.Join(", ", l.Templates.Select(t => t.Name))
|
||||||
select $"Valid values for {l.Name}: {values}.";
|
select $"Valid values for {l.Name}: {values}.";
|
||||||
string typeValuesString = string.Join(" ", typeValues);
|
string typeValuesString = string.Join(" ", typeValues);
|
||||||
|
|
||||||
|
@ -157,10 +177,10 @@ namespace Microsoft.DotNet.Tools.New
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
string typeValue = type.Value() ?? language.Templates.First();
|
string typeValue = type.Value() ?? language.Templates.First().Name;
|
||||||
|
|
||||||
string templateName = language.Templates.FirstOrDefault(t => StringComparer.OrdinalIgnoreCase.Equals(typeValue, t));
|
var template = language.Templates.FirstOrDefault(t => StringComparer.OrdinalIgnoreCase.Equals(typeValue, t.Name));
|
||||||
if (templateName == null)
|
if (template == null)
|
||||||
{
|
{
|
||||||
Reporter.Error.WriteLine($"Unrecognized type: {typeValue}".Red());
|
Reporter.Error.WriteLine($"Unrecognized type: {typeValue}".Red());
|
||||||
Reporter.Error.WriteLine($"Available types for {language.Name} :".Red());
|
Reporter.Error.WriteLine($"Available types for {language.Name} :".Red());
|
||||||
|
@ -171,9 +191,9 @@ namespace Microsoft.DotNet.Tools.New
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
string templateDir = $"{language.TemplatePrefix}_{templateName}";
|
string templateDir = $"{language.TemplatePrefix}_{template.Name}";
|
||||||
|
|
||||||
return dotnetNew.CreateEmptyProject(language.Name, templateDir);
|
return dotnetNew.CreateEmptyProject(language.Name, templateDir, template.isMsBuild);
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
@ -1,266 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Microsoft.DotNet.InternalAbstractions;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Tests.EndToEnd
|
|
||||||
{
|
|
||||||
public class EndToEndTest : TestBase
|
|
||||||
{
|
|
||||||
private static readonly string NetCoreAppTfm = "netcoreapp1.0";
|
|
||||||
private static readonly string s_expectedOutput = "Hello World!" + Environment.NewLine;
|
|
||||||
private static readonly string s_testdirName = "e2etestroot";
|
|
||||||
private static readonly string s_outputdirName = "test space/bin";
|
|
||||||
|
|
||||||
private static string RestoredTestProjectDirectory { get; set; }
|
|
||||||
|
|
||||||
private string Rid { get; set; }
|
|
||||||
private string TestDirectory { get; set; }
|
|
||||||
private string TestProject { get; set; }
|
|
||||||
private string OutputDirectory { get; set; }
|
|
||||||
|
|
||||||
static EndToEndTest()
|
|
||||||
{
|
|
||||||
EndToEndTest.SetupStaticTestProject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Main()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Dummy Entrypoint.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public EndToEndTest()
|
|
||||||
{
|
|
||||||
TestInstanceSetup();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetBuild()
|
|
||||||
{
|
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetCoreAppTfm);
|
|
||||||
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetIncrementalBuild()
|
|
||||||
{
|
|
||||||
// first build
|
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetCoreAppTfm);
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput);
|
|
||||||
|
|
||||||
var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false);
|
|
||||||
var latestWriteTimeFirstBuild = GetLastWriteTimeUtcOfDirectoryFiles(
|
|
||||||
binariesOutputDirectory);
|
|
||||||
|
|
||||||
// second build; should get skipped (incremental because no inputs changed)
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput);
|
|
||||||
|
|
||||||
var latestWriteTimeUtcSecondBuild = GetLastWriteTimeUtcOfDirectoryFiles(
|
|
||||||
binariesOutputDirectory);
|
|
||||||
Assert.Equal(latestWriteTimeFirstBuild, latestWriteTimeUtcSecondBuild);
|
|
||||||
|
|
||||||
TouchSourceFileInDirectory(TestDirectory);
|
|
||||||
|
|
||||||
// third build; should get compiled because the source file got touched
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput);
|
|
||||||
|
|
||||||
var latestWriteTimeUtcThirdBuild = GetLastWriteTimeUtcOfDirectoryFiles(
|
|
||||||
binariesOutputDirectory);
|
|
||||||
Assert.NotEqual(latestWriteTimeUtcSecondBuild, latestWriteTimeUtcThirdBuild);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")]
|
|
||||||
public void TestDotnetBuildNativeRyuJit()
|
|
||||||
{
|
|
||||||
if (!IsNativeCompilationSupported())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: NetCoreAppTfm);
|
|
||||||
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")]
|
|
||||||
public void TestDotnetBuildNativeCpp()
|
|
||||||
{
|
|
||||||
if (!IsNativeCompilationSupported())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetCoreAppTfm);
|
|
||||||
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")]
|
|
||||||
public void TestDotnetCompileNativeCppIncremental()
|
|
||||||
{
|
|
||||||
if (!IsNativeCompilationSupported())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first build
|
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetCoreAppTfm);
|
|
||||||
var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false);
|
|
||||||
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
|
|
||||||
|
|
||||||
var latestWriteTimeUtcFirstBuild = GetLastWriteTimeUtcOfDirectoryFiles(binariesOutputDirectory);
|
|
||||||
|
|
||||||
// second build; should be skipped because nothing changed
|
|
||||||
buildCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
|
|
||||||
|
|
||||||
var latestWriteTimeUtcSecondBuild = GetLastWriteTimeUtcOfDirectoryFiles(binariesOutputDirectory);
|
|
||||||
Assert.Equal(latestWriteTimeUtcFirstBuild, latestWriteTimeUtcSecondBuild);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetRun()
|
|
||||||
{
|
|
||||||
var restoreCommand = new TestCommand("dotnet");
|
|
||||||
restoreCommand.Execute($"restore {TestProject}")
|
|
||||||
.Should()
|
|
||||||
.Pass();
|
|
||||||
var runCommand = new RunCommand(TestProject);
|
|
||||||
|
|
||||||
runCommand.Execute()
|
|
||||||
.Should()
|
|
||||||
.Pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetPack()
|
|
||||||
{
|
|
||||||
var packCommand = new PackCommand(TestDirectory, output: OutputDirectory);
|
|
||||||
|
|
||||||
packCommand.Execute()
|
|
||||||
.Should()
|
|
||||||
.Pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetPublish()
|
|
||||||
{
|
|
||||||
var publishCommand = new PublishCommand(TestProject, output: OutputDirectory);
|
|
||||||
publishCommand.Execute().Should().Pass();
|
|
||||||
|
|
||||||
TestExecutable(OutputDirectory, publishCommand.GetPortableOutputName(), s_expectedOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetHelp()
|
|
||||||
{
|
|
||||||
var helpCommand = new HelpCommand();
|
|
||||||
helpCommand.Execute().Should().Pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestDotnetHelpBuild()
|
|
||||||
{
|
|
||||||
var helpCommand = new HelpCommand();
|
|
||||||
helpCommand.Execute("build").Should().Pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TestInstanceSetup()
|
|
||||||
{
|
|
||||||
var root = Temp.CreateDirectory();
|
|
||||||
|
|
||||||
var testInstanceDir = root.CopyDirectory(RestoredTestProjectDirectory);
|
|
||||||
|
|
||||||
TestDirectory = testInstanceDir.Path;
|
|
||||||
TestProject = Path.Combine(TestDirectory, "project.json");
|
|
||||||
OutputDirectory = Path.Combine(TestDirectory, s_outputdirName);
|
|
||||||
|
|
||||||
Rid = DotnetLegacyRuntimeIdentifiers.InferLegacyRestoreRuntimeIdentifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetupStaticTestProject()
|
|
||||||
{
|
|
||||||
RestoredTestProjectDirectory = Path.Combine(AppContext.BaseDirectory, "bin", s_testdirName);
|
|
||||||
|
|
||||||
// Ignore Delete Failure
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.Delete(RestoredTestProjectDirectory, true);
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
|
|
||||||
Directory.CreateDirectory(RestoredTestProjectDirectory);
|
|
||||||
|
|
||||||
// Todo: this is a hack until corefx is on nuget.org remove this After RC 2 Release
|
|
||||||
NuGetConfig.Write(RestoredTestProjectDirectory);
|
|
||||||
|
|
||||||
var currentDirectory = Directory.GetCurrentDirectory();
|
|
||||||
Directory.SetCurrentDirectory(RestoredTestProjectDirectory);
|
|
||||||
|
|
||||||
new NewCommand().Execute().Should().Pass();
|
|
||||||
new RestoreCommand().Execute().Should().Pass();
|
|
||||||
|
|
||||||
Directory.SetCurrentDirectory(currentDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsNativeCompilationSupported()
|
|
||||||
{
|
|
||||||
bool isSupported = true;
|
|
||||||
var platform = RuntimeEnvironment.OperatingSystem.ToLower();
|
|
||||||
switch (platform)
|
|
||||||
{
|
|
||||||
case "centos":
|
|
||||||
case "rhel":
|
|
||||||
case "fedora":
|
|
||||||
case "opensuse":
|
|
||||||
Console.WriteLine("Skipping native compilation tests on OpenSUSE/Fedora/CentOS/RHEL - https://github.com/dotnet/cli/issues/453");
|
|
||||||
isSupported = false;
|
|
||||||
break;
|
|
||||||
case "debian":
|
|
||||||
Console.WriteLine("Skipping native compilation tests on Debian - https://github.com/dotnet/cli/issues/1666");
|
|
||||||
isSupported = false;
|
|
||||||
break;
|
|
||||||
case "windows":
|
|
||||||
Console.WriteLine("Skipping native compilation tests on Windows x86 - https://github.com/dotnet/cli/issues/1550");
|
|
||||||
isSupported = RuntimeInformation.ProcessArchitecture != Architecture.X86;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DateTime GetLastWriteTimeUtcOfDirectoryFiles(string outputDirectory)
|
|
||||||
{
|
|
||||||
return Directory.EnumerateFiles(outputDirectory).Max(f => File.GetLastWriteTimeUtc(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TouchSourceFileInDirectory(string directory)
|
|
||||||
{
|
|
||||||
var csFile = Directory.EnumerateFiles(directory).First(f => Path.GetExtension(f).Equals(".cs"));
|
|
||||||
File.SetLastWriteTimeUtc(csFile, DateTime.UtcNow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,6 +9,10 @@ namespace Microsoft.DotNet.Tests.EndToEnd
|
||||||
{
|
{
|
||||||
public class GivenDotNetUsesMSBuild : TestBase
|
public class GivenDotNetUsesMSBuild : TestBase
|
||||||
{
|
{
|
||||||
|
public static void Main()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ItCanNewRestoreBuildRunCleanMSBuildProject()
|
public void ItCanNewRestoreBuildRunCleanMSBuildProject()
|
||||||
{
|
{
|
||||||
|
@ -18,13 +22,13 @@ namespace Microsoft.DotNet.Tests.EndToEnd
|
||||||
|
|
||||||
new NewCommand()
|
new NewCommand()
|
||||||
.WithWorkingDirectory(projectDirectory)
|
.WithWorkingDirectory(projectDirectory)
|
||||||
.Execute("-t msbuild")
|
.Execute("")
|
||||||
.Should()
|
.Should()
|
||||||
.Pass();
|
.Pass();
|
||||||
|
|
||||||
new Restore3Command()
|
new Restore3Command()
|
||||||
.WithWorkingDirectory(projectDirectory)
|
.WithWorkingDirectory(projectDirectory)
|
||||||
.Execute()
|
.Execute("/p:SkipInvalidConfigurations=true")
|
||||||
.Should()
|
.Should()
|
||||||
.Pass();
|
.Pass();
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Microsoft.DotNet.Configurer.UnitTests
|
||||||
SetupCommandMock(_dotnetRestoreCommandMock);
|
SetupCommandMock(_dotnetRestoreCommandMock);
|
||||||
commandFactoryMock
|
commandFactoryMock
|
||||||
.Setup(c => c.Create(
|
.Setup(c => c.Create(
|
||||||
"restore",
|
"restore3",
|
||||||
It.IsAny<IEnumerable<string>>(),
|
It.IsAny<IEnumerable<string>>(),
|
||||||
null,
|
null,
|
||||||
Constants.DefaultConfiguration))
|
Constants.DefaultConfiguration))
|
||||||
|
@ -150,7 +150,7 @@ namespace Microsoft.DotNet.Configurer.UnitTests
|
||||||
{
|
{
|
||||||
_commandFactoryMock.Verify(
|
_commandFactoryMock.Verify(
|
||||||
c => c.Create(
|
c => c.Create(
|
||||||
"restore",
|
"restore3",
|
||||||
new [] {"-s", $"{PACKAGES_ARCHIVE_PATH}"},
|
new [] {"-s", $"{PACKAGES_ARCHIVE_PATH}"},
|
||||||
null,
|
null,
|
||||||
Constants.DefaultConfiguration),
|
Constants.DefaultConfiguration),
|
||||||
|
@ -174,7 +174,7 @@ namespace Microsoft.DotNet.Configurer.UnitTests
|
||||||
|
|
||||||
commandFactoryMock.Verify(
|
commandFactoryMock.Verify(
|
||||||
c => c.Create(
|
c => c.Create(
|
||||||
"restore",
|
"restore3",
|
||||||
It.IsAny<IEnumerable<string>>(),
|
It.IsAny<IEnumerable<string>>(),
|
||||||
It.IsAny<NuGetFramework>(),
|
It.IsAny<NuGetFramework>(),
|
||||||
It.IsAny<string>()),
|
It.IsAny<string>()),
|
||||||
|
|
|
@ -11,13 +11,14 @@ namespace Microsoft.DotNet.Tests.Performance
|
||||||
public class HelloWorld : TestBase
|
public class HelloWorld : TestBase
|
||||||
{
|
{
|
||||||
private static readonly string s_testdirName = "helloworldtestroot";
|
private static readonly string s_testdirName = "helloworldtestroot";
|
||||||
|
private static readonly string s_testProject = $"{s_testdirName}.csproj";
|
||||||
private static readonly string s_outputdirName = "test space/bin";
|
private static readonly string s_outputdirName = "test space/bin";
|
||||||
|
|
||||||
private static string AssetsRoot { get; set; }
|
private static string AssetsRoot { get; set; }
|
||||||
private static string RestoredTestProjectDirectory { get; set; }
|
private static string RestoredTestProjectDirectory { get; set; }
|
||||||
|
|
||||||
|
private string ProjectPath { get; set; }
|
||||||
private string TestDirectory { get; set; }
|
private string TestDirectory { get; set; }
|
||||||
private string TestProject { get; set; }
|
|
||||||
private string OutputDirectory { get; set; }
|
private string OutputDirectory { get; set; }
|
||||||
|
|
||||||
static HelloWorld()
|
static HelloWorld()
|
||||||
|
@ -38,24 +39,24 @@ namespace Microsoft.DotNet.Tests.Performance
|
||||||
TestInstanceSetup();
|
TestInstanceSetup();
|
||||||
|
|
||||||
// Setup the build command.
|
// Setup the build command.
|
||||||
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework);
|
var buildCommand = new Build3Command();
|
||||||
using (iter.StartMeasurement())
|
using (iter.StartMeasurement())
|
||||||
{
|
{
|
||||||
// Execute the build command.
|
// Execute the build command.
|
||||||
buildCommand.Execute();
|
buildCommand.Execute($"{ProjectPath} --output \"{OutputDirectory}\" --framework {DefaultFramework}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TestInstanceSetup()
|
private void TestInstanceSetup()
|
||||||
{
|
{
|
||||||
var root = Temp.CreateDirectory();
|
var root = Temp.CreateDirectory();
|
||||||
|
|
||||||
var testInstanceDir = root.CopyDirectory(RestoredTestProjectDirectory);
|
var testInstanceDir = root.CopyDirectory(RestoredTestProjectDirectory);
|
||||||
|
|
||||||
TestDirectory = testInstanceDir.Path;
|
TestDirectory = testInstanceDir.Path;
|
||||||
TestProject = Path.Combine(TestDirectory, "project.json");
|
|
||||||
OutputDirectory = Path.Combine(TestDirectory, s_outputdirName);
|
OutputDirectory = Path.Combine(TestDirectory, s_outputdirName);
|
||||||
|
ProjectPath = Path.Combine(TestDirectory, s_testProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupStaticTestProject()
|
private static void SetupStaticTestProject()
|
||||||
|
@ -79,9 +80,10 @@ namespace Microsoft.DotNet.Tests.Performance
|
||||||
newCommand.WorkingDirectory = RestoredTestProjectDirectory;
|
newCommand.WorkingDirectory = RestoredTestProjectDirectory;
|
||||||
newCommand.Execute().Should().Pass();
|
newCommand.Execute().Should().Pass();
|
||||||
|
|
||||||
var restoreCommand = new RestoreCommand();
|
var restoreCommand = new Restore3Command();
|
||||||
restoreCommand.WorkingDirectory = RestoredTestProjectDirectory;
|
restoreCommand.WorkingDirectory = RestoredTestProjectDirectory;
|
||||||
restoreCommand.Execute().Should().Pass();
|
restoreCommand.Execute("/p:SkipInvalidConfigurations=true")
|
||||||
|
.Should().Pass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,9 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
[InlineData("TestAppWithContents")]
|
[InlineData("TestAppWithContents")]
|
||||||
public void It_migrates_apps(string projectName)
|
public void It_migrates_apps(string projectName)
|
||||||
{
|
{
|
||||||
var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i")
|
||||||
|
.WithLockFiles()
|
||||||
|
.Path;
|
||||||
|
|
||||||
CleanBinObj(projectDirectory);
|
CleanBinObj(projectDirectory);
|
||||||
|
|
||||||
|
@ -37,11 +39,14 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||||
|
|
||||||
if (!outputsIdentical)
|
if (!outputsIdentical)
|
||||||
{
|
{
|
||||||
OutputDiagnostics(outputComparisonData);
|
OutputDiagnostics(outputComparisonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputsIdentical.Should().BeTrue();
|
outputsIdentical.Should().BeTrue();
|
||||||
|
|
||||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,49 +60,60 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||||
|
|
||||||
if (!outputsIdentical)
|
if (!outputsIdentical)
|
||||||
{
|
{
|
||||||
OutputDiagnostics(outputComparisonData);
|
OutputDiagnostics(outputComparisonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputsIdentical.Should().BeTrue();
|
outputsIdentical.Should().BeTrue();
|
||||||
|
|
||||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||||
|
|
||||||
VerifyAllMSBuildOutputsAreSigned(projectDirectory);
|
VerifyAllMSBuildOutputsAreSigned(projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void It_migrates_dotnet_new_console_with_identical_outputs()
|
public void It_migrates_dotnet_new_console_with_identical_outputs()
|
||||||
{
|
{
|
||||||
var projectDirectory = Path.Combine(AppContext.BaseDirectory, "newconsoletest");
|
var testInstance = TestAssetsManager
|
||||||
if (Directory.Exists(projectDirectory))
|
.CreateTestInstance("ProjectJsonConsoleTemplate");
|
||||||
{
|
|
||||||
Directory.Delete(projectDirectory, true);
|
var projectDirectory = testInstance.Path;
|
||||||
}
|
|
||||||
Directory.CreateDirectory(projectDirectory);
|
|
||||||
|
|
||||||
var outputComparisonData = GetDotnetNewComparisonData(projectDirectory, "console");
|
var outputComparisonData = GetComparisonData(projectDirectory);
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||||
|
|
||||||
if (!outputsIdentical)
|
if (!outputsIdentical)
|
||||||
{
|
{
|
||||||
OutputDiagnostics(outputComparisonData);
|
OutputDiagnostics(outputComparisonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputsIdentical.Should().BeTrue();
|
outputsIdentical.Should().BeTrue();
|
||||||
|
|
||||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Skip="https://github.com/dotnet/cli/issues/4299")]
|
[Fact(Skip="https://github.com/dotnet/cli/issues/4299")]
|
||||||
public void It_migrates_dotnet_new_web_with_outputs_containing_project_json_outputs()
|
public void It_migrates_dotnet_new_web_with_outputs_containing_project_json_outputs()
|
||||||
{
|
{
|
||||||
var projectDirectory = Temp.CreateDirectory().Path;
|
var testInstance = TestAssetsManager
|
||||||
var outputComparisonData = GetDotnetNewComparisonData(projectDirectory, "web");
|
.CreateTestInstance("ProjectJsonWebTemplate");
|
||||||
|
|
||||||
|
var projectDirectory = testInstance.Path;
|
||||||
|
|
||||||
|
var outputComparisonData = GetComparisonData(projectDirectory);
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||||
|
|
||||||
if (!outputsIdentical)
|
if (!outputsIdentical)
|
||||||
{
|
{
|
||||||
OutputDiagnostics(outputComparisonData);
|
OutputDiagnostics(outputComparisonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputsIdentical.Should().BeTrue();
|
outputsIdentical.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +124,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
{
|
{
|
||||||
var projectDirectory =
|
var projectDirectory =
|
||||||
TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
||||||
|
|
||||||
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName);
|
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName);
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
|
@ -129,6 +146,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
{
|
{
|
||||||
var projectDirectory =
|
var projectDirectory =
|
||||||
TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
TestAssetsManager.CreateTestInstance(projectName, callingMethod: "i").WithLockFiles().Path;
|
||||||
|
|
||||||
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectName));
|
var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectName));
|
||||||
|
|
||||||
var outputsIdentical =
|
var outputsIdentical =
|
||||||
|
@ -156,6 +174,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
MigrateProject(new [] { Path.Combine(projectDirectory, projectName) });
|
MigrateProject(new [] { Path.Combine(projectDirectory, projectName) });
|
||||||
|
|
||||||
string[] migratedProjects = expectedProjects.Split(new char[] { ',' });
|
string[] migratedProjects = expectedProjects.Split(new char[] { ',' });
|
||||||
|
|
||||||
VerifyMigration(migratedProjects, projectDirectory);
|
VerifyMigration(migratedProjects, projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +211,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG", "ProjectH", "ProjectI", "ProjectJ" };
|
string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG", "ProjectH", "ProjectI", "ProjectJ" };
|
||||||
|
|
||||||
VerifyMigration(migratedProjects, projectDirectory);
|
VerifyMigration(migratedProjects, projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,9 +221,11 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path;
|
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path;
|
||||||
|
|
||||||
var project = Path.Combine(projectDirectory, "ProjectA", "project.json");
|
var project = Path.Combine(projectDirectory, "ProjectA", "project.json");
|
||||||
|
|
||||||
MigrateProject(new [] { project });
|
MigrateProject(new [] { project });
|
||||||
|
|
||||||
string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE" };
|
string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE" };
|
||||||
|
|
||||||
VerifyMigration(migratedProjects, projectDirectory);
|
VerifyMigration(migratedProjects, projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +234,9 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
public void It_migrates_and_builds_P2P_references()
|
public void It_migrates_and_builds_P2P_references()
|
||||||
{
|
{
|
||||||
var assetsDir = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").WithLockFiles().Path;
|
var assetsDir = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").WithLockFiles().Path;
|
||||||
|
|
||||||
var projectDirectory = Path.Combine(assetsDir, "ProjectF");
|
var projectDirectory = Path.Combine(assetsDir, "ProjectF");
|
||||||
|
|
||||||
var restoreDirectories = new string[]
|
var restoreDirectories = new string[]
|
||||||
{
|
{
|
||||||
projectDirectory,
|
projectDirectory,
|
||||||
|
@ -230,6 +254,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
outputsIdentical.Should().BeTrue();
|
outputsIdentical.Should().BeTrue();
|
||||||
|
|
||||||
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
VerifyAllMSBuildOutputsRunnable(projectDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +283,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
restoreDirectories);
|
restoreDirectories);
|
||||||
|
|
||||||
var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs
|
var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs
|
||||||
.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
.SetEquals(outputComparisonData.MSBuildBuildOutputs);
|
||||||
|
|
||||||
if (!outputsIdentical)
|
if (!outputsIdentical)
|
||||||
{
|
{
|
||||||
|
@ -278,11 +303,13 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
var projectDirectory = TestAssetsManager.CreateTestDirectory("Migration_outputs_error_when_no_projects_found");
|
var projectDirectory = TestAssetsManager.CreateTestDirectory("Migration_outputs_error_when_no_projects_found");
|
||||||
|
|
||||||
string argstr = string.Empty;
|
string argstr = string.Empty;
|
||||||
|
|
||||||
string errorMessage = string.Empty;
|
string errorMessage = string.Empty;
|
||||||
|
|
||||||
if (useGlobalJson)
|
if (useGlobalJson)
|
||||||
{
|
{
|
||||||
var globalJsonPath = Path.Combine(projectDirectory.Path, "global.json");
|
var globalJsonPath = Path.Combine(projectDirectory.Path, "global.json");
|
||||||
|
|
||||||
using (FileStream fs = File.Create(globalJsonPath))
|
using (FileStream fs = File.Create(globalJsonPath))
|
||||||
{
|
{
|
||||||
using (StreamWriter sw = new StreamWriter(fs))
|
using (StreamWriter sw = new StreamWriter(fs))
|
||||||
|
@ -294,11 +321,13 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
argstr = globalJsonPath;
|
argstr = globalJsonPath;
|
||||||
|
|
||||||
errorMessage = "Unable to find any projects in global.json";
|
errorMessage = "Unable to find any projects in global.json";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
argstr = projectDirectory.Path;
|
argstr = projectDirectory.Path;
|
||||||
|
|
||||||
errorMessage = $"No project.json file found in '{projectDirectory.Path}'";
|
errorMessage = $"No project.json file found in '{projectDirectory.Path}'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,17 +350,19 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
.Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1)
|
.Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1)
|
||||||
.Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project"))
|
.Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project"))
|
||||||
.Select(s => Path.GetFileName(Path.GetDirectoryName(s)));
|
.Select(s => Path.GetFileName(Path.GetDirectoryName(s)));
|
||||||
|
|
||||||
migratedProjects.Should().BeEquivalentTo(expectedProjects);
|
migratedProjects.Should().BeEquivalentTo(expectedProjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MigratedBuildComparisonData GetDotnetNewComparisonData(string projectDirectory, string dotnetNewType)
|
private MigratedBuildComparisonData GetComparisonData(string projectDirectory)
|
||||||
{
|
{
|
||||||
DotnetNew(projectDirectory, dotnetNewType);
|
|
||||||
File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config"));
|
File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config"));
|
||||||
|
|
||||||
Restore(projectDirectory);
|
Restore(projectDirectory);
|
||||||
|
|
||||||
var outputComparisonData =
|
var outputComparisonData =
|
||||||
BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory));
|
BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory));
|
||||||
|
|
||||||
return outputComparisonData;
|
return outputComparisonData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +389,9 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
foreach (var dll in runnableDlls)
|
foreach (var dll in runnableDlls)
|
||||||
{
|
{
|
||||||
var assemblyName = AssemblyLoadContext.GetAssemblyName(dll);
|
var assemblyName = AssemblyLoadContext.GetAssemblyName(dll);
|
||||||
|
|
||||||
var token = assemblyName.GetPublicKeyToken();
|
var token = assemblyName.GetPublicKeyToken();
|
||||||
|
|
||||||
token.Should().NotBeNullOrEmpty();
|
token.Should().NotBeNullOrEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,8 +399,10 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory,
|
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory,
|
||||||
string projectName)
|
string projectName)
|
||||||
{
|
{
|
||||||
return BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName,
|
return BuildProjectJsonMigrateBuildMSBuild(projectDirectory,
|
||||||
new [] { projectDirectory }, new [] { projectDirectory });
|
projectName,
|
||||||
|
new [] { projectDirectory },
|
||||||
|
new [] { projectDirectory });
|
||||||
}
|
}
|
||||||
|
|
||||||
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory,
|
private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory,
|
||||||
|
@ -376,7 +411,9 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
string[] restoreDirectories)
|
string[] restoreDirectories)
|
||||||
{
|
{
|
||||||
BuildProjectJson(projectDirectory);
|
BuildProjectJson(projectDirectory);
|
||||||
|
|
||||||
var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
var projectJsonBuildOutputs = new HashSet<string>(CollectBuildOutputs(projectDirectory));
|
||||||
|
|
||||||
CleanBinObj(projectDirectory);
|
CleanBinObj(projectDirectory);
|
||||||
|
|
||||||
// Remove lock file for migration
|
// Remove lock file for migration
|
||||||
|
@ -386,6 +423,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
MigrateProject(migrateArgs);
|
MigrateProject(migrateArgs);
|
||||||
|
|
||||||
DeleteXproj(projectDirectory);
|
DeleteXproj(projectDirectory);
|
||||||
|
|
||||||
foreach(var dir in restoreDirectories)
|
foreach(var dir in restoreDirectories)
|
||||||
|
@ -424,6 +462,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
private void BuildProjectJson(string projectDirectory)
|
private void BuildProjectJson(string projectDirectory)
|
||||||
{
|
{
|
||||||
var projectFile = Path.Combine(projectDirectory, "project.json");
|
var projectFile = Path.Combine(projectDirectory, "project.json");
|
||||||
|
|
||||||
var result = new BuildCommand(projectPath: projectFile)
|
var result = new BuildCommand(projectPath: projectFile)
|
||||||
.ExecuteWithCapturedOutput();
|
.ExecuteWithCapturedOutput();
|
||||||
|
|
||||||
|
@ -438,21 +477,12 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
result.Should().Be(0);
|
result.Should().Be(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DotnetNew(string projectDirectory, string dotnetNewType)
|
|
||||||
{
|
|
||||||
new NewCommand().WithWorkingDirectory(projectDirectory)
|
|
||||||
.ExecuteWithCapturedOutput($"-t {dotnetNewType}")
|
|
||||||
.Should()
|
|
||||||
.Pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Restore(string projectDirectory)
|
private void Restore(string projectDirectory)
|
||||||
{
|
{
|
||||||
new TestCommand("dotnet")
|
new TestCommand("dotnet")
|
||||||
.WithWorkingDirectory(projectDirectory)
|
.WithWorkingDirectory(projectDirectory)
|
||||||
.Execute("restore")
|
.Execute("restore")
|
||||||
.Should()
|
.Should().Pass();
|
||||||
.Pass();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Restore3(string projectDirectory, string projectName=null)
|
private void Restore3(string projectDirectory, string projectName=null)
|
||||||
|
@ -462,15 +492,13 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
|
|
||||||
if (projectName != null)
|
if (projectName != null)
|
||||||
{
|
{
|
||||||
command.Execute($"{projectName}.csproj")
|
command.Execute($"{projectName}.csproj /p:SkipInvalidConfigurations=true")
|
||||||
.Should()
|
.Should().Pass();
|
||||||
.Pass();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
command.Execute()
|
command.Execute("/p:SkipInvalidConfigurations=true")
|
||||||
.Should()
|
.Should().Pass();
|
||||||
.Pass();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,8 +516,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
.ExecuteWithCapturedOutput($"{projectName} /p:Configuration={configuration}");
|
.ExecuteWithCapturedOutput($"{projectName} /p:Configuration={configuration}");
|
||||||
|
|
||||||
result
|
result
|
||||||
.Should()
|
.Should().Pass();
|
||||||
.Pass();
|
|
||||||
|
|
||||||
return result.StdOut;
|
return result.StdOut;
|
||||||
}
|
}
|
||||||
|
@ -497,6 +524,7 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
private void DeleteXproj(string projectDirectory)
|
private void DeleteXproj(string projectDirectory)
|
||||||
{
|
{
|
||||||
var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj");
|
var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj");
|
||||||
|
|
||||||
foreach (var xprojFile in xprojFiles)
|
foreach (var xprojFile in xprojFiles)
|
||||||
{
|
{
|
||||||
File.Delete(xprojFile);
|
File.Delete(xprojFile);
|
||||||
|
@ -511,23 +539,27 @@ namespace Microsoft.DotNet.Migration.Tests
|
||||||
private void OutputDiagnostics(HashSet<string> msbuildBuildOutputs, HashSet<string> projectJsonBuildOutputs)
|
private void OutputDiagnostics(HashSet<string> msbuildBuildOutputs, HashSet<string> projectJsonBuildOutputs)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Project.json Outputs:");
|
Console.WriteLine("Project.json Outputs:");
|
||||||
|
|
||||||
Console.WriteLine(string.Join("\n", projectJsonBuildOutputs));
|
Console.WriteLine(string.Join("\n", projectJsonBuildOutputs));
|
||||||
|
|
||||||
Console.WriteLine("");
|
Console.WriteLine("");
|
||||||
|
|
||||||
Console.WriteLine("MSBuild Outputs:");
|
Console.WriteLine("MSBuild Outputs:");
|
||||||
|
|
||||||
Console.WriteLine(string.Join("\n", msbuildBuildOutputs));
|
Console.WriteLine(string.Join("\n", msbuildBuildOutputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MigratedBuildComparisonData
|
private class MigratedBuildComparisonData
|
||||||
{
|
{
|
||||||
public HashSet<string> ProjectJsonBuildOutputs { get; }
|
public HashSet<string> ProjectJsonBuildOutputs { get; }
|
||||||
|
|
||||||
public HashSet<string> MSBuildBuildOutputs { get; }
|
public HashSet<string> MSBuildBuildOutputs { get; }
|
||||||
|
|
||||||
public MigratedBuildComparisonData(HashSet<string> projectJsonBuildOutputs,
|
public MigratedBuildComparisonData(HashSet<string> projectJsonBuildOutputs,
|
||||||
HashSet<string> msBuildBuildOutputs)
|
HashSet<string> msBuildBuildOutputs)
|
||||||
{
|
{
|
||||||
ProjectJsonBuildOutputs = projectJsonBuildOutputs;
|
ProjectJsonBuildOutputs = projectJsonBuildOutputs;
|
||||||
|
|
||||||
MSBuildBuildOutputs = msBuildBuildOutputs;
|
MSBuildBuildOutputs = msBuildBuildOutputs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using Microsoft.Build.Construction;
|
||||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
|
||||||
|
@ -15,48 +13,49 @@ namespace Microsoft.DotNet.Tests
|
||||||
{
|
{
|
||||||
public class GivenThatIWantANewCSApp : TestBase
|
public class GivenThatIWantANewCSApp : TestBase
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact(Skip="https://github.com/dotnet/cli/issues/4381")]
|
||||||
public void When_NewtonsoftJson_dependency_added_Then_project_restores_and_runs()
|
public void When_NewtonsoftJson_dependency_added_Then_project_restores_and_runs()
|
||||||
{
|
{
|
||||||
var rootPath = Temp.CreateDirectory().Path;
|
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||||
var projectJsonFile = Path.Combine(rootPath, "project.json");
|
var projectName = new DirectoryInfo(rootPath).Name;
|
||||||
|
var projectFile = Path.Combine(rootPath, $"{projectName}.csproj");
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("new");
|
.Execute("new");
|
||||||
|
|
||||||
AddProjectJsonDependency(projectJsonFile, "Newtonsoft.Json", "7.0.1");
|
AddProjectDependency(projectFile, "Newtonsoft.Json", "7.0.1");
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("restore")
|
.Execute("restore3 /p:SkipInvalidConfigurations=true")
|
||||||
.Should().Pass();
|
.Should().Pass();
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("run")
|
.Execute("run3")
|
||||||
.Should().Pass();
|
.Should().Pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void When_dotnet_build_is_invoked_Then_project_builds_without_warnings()
|
public void When_dotnet_build_is_invoked_Then_app_builds_without_warnings()
|
||||||
{
|
{
|
||||||
var rootPath = Temp.CreateDirectory().Path;
|
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("new");
|
.Execute("new");
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("restore");
|
.Execute("restore3 /p:SkipInvalidConfigurations=true");
|
||||||
|
|
||||||
var buildResult = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
var buildResult = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.ExecuteWithCapturedOutput("build");
|
.ExecuteWithCapturedOutput("build3");
|
||||||
|
|
||||||
buildResult.Should().Pass();
|
buildResult.Should().Pass()
|
||||||
buildResult.Should().NotHaveStdErr();
|
.And.NotHaveStdErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void When_dotnet_new_is_invoked_mupliple_times_it_should_fail()
|
public void When_dotnet_new_is_invoked_mupliple_times_it_should_fail()
|
||||||
{
|
{
|
||||||
var rootPath = Temp.CreateDirectory().Path;
|
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("new");
|
.Execute("new");
|
||||||
|
@ -70,40 +69,17 @@ namespace Microsoft.DotNet.Tests
|
||||||
|
|
||||||
Assert.Equal(expectedState, actualState);
|
Assert.Equal(expectedState, actualState);
|
||||||
|
|
||||||
result.Should().Fail();
|
result.Should().Fail()
|
||||||
result.Should().HaveStdErr();
|
.And.HaveStdErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddProjectJsonDependency(string projectJsonPath, string dependencyId, string dependencyVersion)
|
private static void AddProjectDependency(string projectFilePath, string dependencyId, string dependencyVersion)
|
||||||
{
|
{
|
||||||
var projectJsonRoot = ReadProject(projectJsonPath);
|
var projectRootElement = ProjectRootElement.Open(projectFilePath);
|
||||||
|
|
||||||
var dependenciesNode = projectJsonRoot
|
projectRootElement.AddItem("PackageReference", dependencyId, new Dictionary<string, string>{{"Version", dependencyVersion}});
|
||||||
.Descendants()
|
|
||||||
.OfType<JProperty>()
|
|
||||||
.First(p => p.Name == "dependencies");
|
|
||||||
|
|
||||||
((JObject)dependenciesNode.Value).Add(new JProperty(dependencyId, dependencyVersion));
|
projectRootElement.Save();
|
||||||
|
|
||||||
WriteProject(projectJsonRoot, projectJsonPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JObject ReadProject(string projectJsonPath)
|
|
||||||
{
|
|
||||||
using (TextReader projectFileReader = File.OpenText(projectJsonPath))
|
|
||||||
{
|
|
||||||
var projectJsonReader = new JsonTextReader(projectFileReader);
|
|
||||||
|
|
||||||
var serializer = new JsonSerializer();
|
|
||||||
return serializer.Deserialize<JObject>(projectJsonReader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteProject(JObject projectRoot, string projectJsonPath)
|
|
||||||
{
|
|
||||||
string projectJson = JsonConvert.SerializeObject(projectRoot, Formatting.Indented);
|
|
||||||
|
|
||||||
File.WriteAllText(projectJsonPath, projectJson + Environment.NewLine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,44 +15,37 @@ namespace Microsoft.DotNet.Tests
|
||||||
{
|
{
|
||||||
public class GivenThatIWantANewCSLibrary : TestBase
|
public class GivenThatIWantANewCSLibrary : TestBase
|
||||||
{
|
{
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void When_library_created_Then_project_restores()
|
public void When_library_created_Then_project_restores()
|
||||||
{
|
{
|
||||||
var rootPath = Temp.CreateDirectory().Path;
|
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||||
var projectJsonFile = Path.Combine(rootPath, "project.json");
|
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("new --type lib")
|
.Execute("new --type lib")
|
||||||
.Should()
|
.Should().Pass();
|
||||||
.Pass();
|
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("restore")
|
.Execute("restore3 /p:SkipInvalidConfigurations=true")
|
||||||
.Should().Pass();
|
.Should().Pass();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void When_dotnet_build_is_invoked_Then_project_builds_without_warnings()
|
public void When_dotnet_build_is_invoked_Then_library_builds_without_warnings()
|
||||||
{
|
{
|
||||||
var rootPath = Temp.CreateDirectory().Path;
|
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("new --type lib");
|
.Execute("new --type lib");
|
||||||
|
|
||||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||||
.Execute("restore");
|
.Execute("restore3 /p:SkipInvalidConfigurations=true");
|
||||||
|
|
||||||
var buildResult = new TestCommand("dotnet")
|
var buildResult = new TestCommand("dotnet")
|
||||||
.WithWorkingDirectory(rootPath)
|
.WithWorkingDirectory(rootPath)
|
||||||
.ExecuteWithCapturedOutput("build")
|
.ExecuteWithCapturedOutput("build3")
|
||||||
.Should()
|
.Should().Pass()
|
||||||
.Pass()
|
.And.NotHaveStdErr();
|
||||||
.And
|
|
||||||
.NotHaveStdErr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
test/dotnet-new.Tests/MSBuild.exe
Normal file
1
test/dotnet-new.Tests/MSBuild.exe
Normal file
|
@ -0,0 +1 @@
|
||||||
|
https://github.com/Microsoft/msbuild/issues/927
|
1
test/dotnet-new.Tests/MSBuild.exe.config
Normal file
1
test/dotnet-new.Tests/MSBuild.exe.config
Normal file
|
@ -0,0 +1 @@
|
||||||
|
https://github.com/Microsoft/msbuild/issues/927
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue