16 | Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key
17 | used in an authenticator app you should reset your authenticator keys.
18 |
19 | Swapping to Development environment will display more detailed information about the error that occurred.
20 |
21 |
22 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application.
23 |
11 |
12 | If you reset your authenticator key your authenticator app will not work until you reconfigure it.
13 |
14 |
15 | This process disables 2FA until you verify your authenticator app and will also reset your 2FA recovery codes.
16 | If you do not complete your authenticator app configuration you may lose access to your account.
17 |
18 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/DDD.NetCore.Application/Users/IUserAppService.cs:
--------------------------------------------------------------------------------
1 | using DDD.NetCore.Domain.Authorization;
2 | using DDD.NetCore.Domain.Customers;
3 | using DDD.NetCore.Domain.Uow;
4 |
5 | namespace DDD.NetCore.Application.Users
6 | {
7 | public interface IUserAppService
8 | {
9 | void InitialCustomerForUser(string userId);
10 |
11 | Customer GetCustomerByUserId(string userId);
12 | }
13 |
14 | public class UserAppService : IUserAppService
15 | {
16 | private readonly IUnitOfWork _unitOfWork;
17 |
18 | public UserAppService(IUnitOfWork unitOfWork)
19 | {
20 | _unitOfWork = unitOfWork;
21 | }
22 |
23 | public void InitialCustomerForUser(string userId)
24 | {
25 | throw new System.NotImplementedException();
26 | }
27 |
28 | public Customer GetCustomerByUserId(string userId)
29 | {
30 | throw new System.NotImplementedException();
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Data/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore;
7 |
8 | namespace DDD.NetCore.Web.Data
9 | {
10 | public class ApplicationDbContext : IdentityDbContext
11 | {
12 | public ApplicationDbContext(DbContextOptions options)
13 | : base(options)
14 | {
15 | }
16 |
17 | protected override void OnModelCreating(ModelBuilder builder)
18 | {
19 | base.OnModelCreating(builder);
20 | // Customize the ASP.NET Identity model and override the defaults if needed.
21 | // For example, you can rename the ASP.NET Identity table names and more.
22 | // Add your customizations after calling base.OnModelCreating(builder);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/_LoginPartial.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Identity
2 | @using DDD.NetCore.Web.Data
3 | @inject SignInManager SignInManager
4 | @inject UserManager UserManager
5 |
6 | @if (SignInManager.IsSignedIn(User))
7 | {
8 |
18 | }
19 | else
20 | {
21 |
10 | You have requested to log in with a recovery code. This login will not be remembered until you provide
11 | an authenticator app code at log in or disable 2FA and log in again.
12 |
13 |
14 |
15 |
24 |
25 |
26 |
27 | @section Scripts {
28 | @await Html.PartialAsync("_ValidationScriptsPartial")
29 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Controllers/AccountController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.Logging;
8 | using DDD.NetCore.Web.Data;
9 |
10 | namespace DDD.NetCore.Web.Controllers
11 | {
12 | [Route("[controller]/[action]")]
13 | public class AccountController : Controller
14 | {
15 | private readonly SignInManager _signInManager;
16 | private readonly ILogger _logger;
17 |
18 | public AccountController(SignInManager signInManager, ILogger logger)
19 | {
20 | _signInManager = signInManager;
21 | _logger = logger;
22 | }
23 |
24 | [HttpPost]
25 | [ValidateAntiForgeryToken]
26 | public async Task Logout()
27 | {
28 | await _signInManager.SignOutAsync();
29 | _logger.LogInformation("User logged out.");
30 | return RedirectToPage("/Index");
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/DDD.NetCore.Web.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.0
4 | aspnet-DDD.NetCore.Web-0E6A0680-1CAB-4355-8B2D-BBAF788B62D8
5 | ..\docker-compose.dcproj
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/ExternalLogin.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ExternalLoginModel
3 | @{
4 | ViewData["Title"] = "Register";
5 | }
6 |
7 |
@ViewData["Title"]
8 |
Associate your @Model.LoginProvider account.
9 |
10 |
11 |
12 | You've successfully authenticated with @Model.LoginProvider.
13 | Please enter an email address for this site below and click the Register button to finish
14 | logging in.
15 |
38 |
39 | @section Scripts {
40 | @await Html.PartialAsync("_ValidationScriptsPartial")
41 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/DDD.NetCore.Domain/Orders/SaleOrder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DDD.NetCore.Domain.Customers;
4 | using DDD.NetCore.Domain.Entities;
5 |
6 | namespace DDD.NetCore.Domain.Orders
7 | {
8 | public class SaleOrder : AggregateRoot
9 | {
10 | public SaleOrder()
11 | {
12 | CreationTime = DateTime.Now;
13 | OrderStatus = SaleOrderStatus.Created;
14 | }
15 |
16 | public int CustomerId { get; set; }
17 |
18 | public virtual Customer Customer { get; set; }
19 |
20 | public SaleOrderStatus OrderStatus { get; set; }
21 |
22 | public int DeliveryAddressId { get; set; }
23 | public virtual Address DeliveryAddress { get; set; }
24 |
25 | public List SaleOrderLines { get; } = new List();
26 |
27 | public DateTime CreationTime { get; private set; }
28 |
29 |
30 | }
31 |
32 | public enum SaleOrderStatus
33 | {
34 | ///
35 | /// 表示销售订单的已创建状态 - 表明销售订单已被创建(未用)。
36 | ///
37 | Created = 0,
38 | ///
39 | /// 表示销售订单的已付款状态 - 表明客户已向销售订单付款。
40 | ///
41 | Paid,
42 | ///
43 | /// 表示销售订单的已拣货状态 - 表明销售订单中包含的商品已从仓库拣货(未用)。
44 | ///
45 | Picked,
46 | ///
47 | /// 表示销售订单的已发货状态。
48 | ///
49 | Dispatched,
50 | ///
51 | /// 表示销售订单的已派送状态。
52 | ///
53 | Delivered
54 | }
55 |
56 | public class SaleOrderLine : Entity
57 | {
58 | public int SaleOrderId { get; set; }
59 | public virtual SaleOrder SaleOrder { get; set; }
60 | public int GoodsId { get; set; }
61 | public virtual Goods.Goods Goods { get; set; }
62 |
63 | }
64 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/Manage/GenerateRecoveryCodes.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 | using DDD.NetCore.Web.Data;
10 |
11 | namespace DDD.NetCore.Web.Pages.Account.Manage
12 | {
13 | public class GenerateRecoveryCodesModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 | private readonly ILogger _logger;
17 |
18 | public GenerateRecoveryCodesModel(
19 | UserManager userManager,
20 | ILogger logger)
21 | {
22 | _userManager = userManager;
23 | _logger = logger;
24 | }
25 |
26 | public string[] RecoveryCodes { get; set; }
27 |
28 | public async Task OnGetAsync()
29 | {
30 | var user = await _userManager.GetUserAsync(User);
31 | if (user == null)
32 | {
33 | throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
34 | }
35 |
36 | if (!user.TwoFactorEnabled)
37 | {
38 | throw new ApplicationException($"Cannot generate recovery codes for user with ID '{user.Id}' as they do not have 2FA enabled.");
39 | }
40 |
41 | var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
42 | RecoveryCodes = recoveryCodes.ToArray();
43 |
44 | _logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", user.Id);
45 |
46 | return Page();
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/Manage/TwoFactorAuthentication.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model TwoFactorAuthenticationModel
3 | @{
4 | ViewData["Title"] = "Two-factor authentication (2FA)";
5 | }
6 |
7 |
41 |
42 |
52 | }
53 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/ForgotPassword.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using DDD.NetCore.Web.Data;
9 | using DDD.NetCore.Web.Services;
10 |
11 | namespace DDD.NetCore.Web.Pages.Account
12 | {
13 | public class ForgotPasswordModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 | private readonly IEmailSender _emailSender;
17 |
18 | public ForgotPasswordModel(UserManager userManager, IEmailSender emailSender)
19 | {
20 | _userManager = userManager;
21 | _emailSender = emailSender;
22 | }
23 |
24 | [BindProperty]
25 | public InputModel Input { get; set; }
26 |
27 | public class InputModel
28 | {
29 | [Required]
30 | [EmailAddress]
31 | public string Email { get; set; }
32 | }
33 |
34 | public async Task OnPostAsync()
35 | {
36 | if (ModelState.IsValid)
37 | {
38 | var user = await _userManager.FindByEmailAsync(Input.Email);
39 | if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
40 | {
41 | // Don't reveal that the user does not exist or is not confirmed
42 | return RedirectToPage("./ForgotPasswordConfirmation");
43 | }
44 |
45 | // For more information on how to enable account confirmation and password reset please
46 | // visit https://go.microsoft.com/fwlink/?LinkID=532713
47 | var code = await _userManager.GeneratePasswordResetTokenAsync(user);
48 | var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme);
49 | await _emailSender.SendResetPasswordAsync(Input.Email, callbackUrl);
50 | return RedirectToPage("./ForgotPasswordConfirmation");
51 | }
52 |
53 | return Page();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/DDD.NetCore/Exception/EntityNotFoundException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DDD.NetCore.Exception
4 | {
5 | ///
6 | /// This exception is thrown if an entity excepted to be found but not found.
7 | ///
8 | public class EntityNotFoundException : ExceptionBase
9 | {
10 | ///
11 | /// Type of the entity.
12 | ///
13 | public Type EntityType { get; set; }
14 |
15 | ///
16 | /// Id of the Entity.
17 | ///
18 | public object Id { get; set; }
19 |
20 | ///
21 | /// Creates a new object.
22 | ///
23 | public EntityNotFoundException()
24 | {
25 |
26 | }
27 |
28 | ///
29 | /// Creates a new object.
30 | ///
31 | public EntityNotFoundException(Type entityType, object id)
32 | : this(entityType, id, null)
33 | {
34 |
35 | }
36 |
37 | ///
38 | /// Creates a new object.
39 | ///
40 | public EntityNotFoundException(Type entityType, object id, System.Exception innerException)
41 | : base($"There is no such an entity. Entity type: {entityType.FullName}, id: {id}", innerException)
42 | {
43 | EntityType = entityType;
44 | Id = id;
45 | }
46 |
47 | ///
48 | /// Creates a new object.
49 | ///
50 | /// Exception message
51 | public EntityNotFoundException(string message)
52 | : base(message)
53 | {
54 |
55 | }
56 |
57 | ///
58 | /// Creates a new object.
59 | ///
60 | /// Exception message
61 | /// Inner exception
62 | public EntityNotFoundException(string message, System.Exception innerException)
63 | : base(message, innerException)
64 | {
65 |
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/DDD.NetCore.Application/ShoppingCarts/ShoppingCartService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using DDD.NetCore.Domain.Customers;
4 | using DDD.NetCore.Domain.Goods;
5 | using DDD.NetCore.Domain.ShoppingCarts;
6 |
7 | namespace DDD.NetCore.Application.ShoppingCarts
8 | {
9 | public class ShoppingCartService : IShoppingCartService
10 | {
11 | private readonly IShoppingCartRepository _shoppingCartRepository;
12 | private readonly IGoodsRepository _goodsRepository;
13 | private readonly ICustomerRepository _customerRepository;
14 | public ShoppingCartService(IShoppingCartRepository shoppingCartRepository,
15 | IGoodsRepository goodsRepository, ICustomerRepository customerRepository)
16 | {
17 | _shoppingCartRepository = shoppingCartRepository;
18 | _goodsRepository = goodsRepository;
19 | _customerRepository = customerRepository;
20 | }
21 | public void AddGoodsToCart(string userId, int goodsId, int qty)
22 | {
23 | var customer = _customerRepository.GetCustomerByUserId(userId);
24 | var cart = _shoppingCartRepository.Find(customer.ShoppingCartId);
25 | var goods = _goodsRepository.Find(goodsId);
26 |
27 | cart.AddGoods(goods, qty);
28 | _shoppingCartRepository.Update(cart);
29 |
30 | }
31 |
32 | public void RemoveItemFromCart(int cartId, int cartLineId)
33 | {
34 | var cart = _shoppingCartRepository.Find(cartId);
35 | var cartLine = cart.ShoppingCartLines.FirstOrDefault(c => c.Id == cartLineId);
36 | cart.RemoveItem(cartLine);
37 | }
38 |
39 | public ShoppingCart GetShoppingCart(int cartId)
40 | {
41 | return _shoppingCartRepository.Find(cartId);
42 | }
43 |
44 | public void ChangeItmeQty(int cartId, int cartLineId, int qty)
45 | {
46 | var cart = _shoppingCartRepository.Find(cartId);
47 | var cartLine = cart.ShoppingCartLines.FirstOrDefault(c => c.Id == cartLineId);
48 | cart.ChangeItmeQty(cartLine, qty);
49 | }
50 |
51 | public void ClearCart(int cartId)
52 | {
53 | var cart = _shoppingCartRepository.Find(cartId);
54 | cart.Clear();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/Manage/Disable2fa.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Identity;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 | using DDD.NetCore.Web.Data;
10 |
11 | namespace DDD.NetCore.Web.Pages.Account.Manage
12 | {
13 | public class Disable2faModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 | private readonly ILogger _logger;
17 |
18 | public Disable2faModel(
19 | UserManager userManager,
20 | ILogger logger)
21 | {
22 | _userManager = userManager;
23 | _logger = logger;
24 | }
25 |
26 | public async Task OnGet()
27 | {
28 | var user = await _userManager.GetUserAsync(User);
29 | if (user == null)
30 | {
31 | throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
32 | }
33 |
34 | if (!await _userManager.GetTwoFactorEnabledAsync(user))
35 | {
36 | throw new ApplicationException($"Cannot disable 2FA for user with ID '{_userManager.GetUserId(User)}' as it's not currently enabled.");
37 | }
38 |
39 | return Page();
40 | }
41 |
42 | public async Task OnPostAsync()
43 | {
44 | var user = await _userManager.GetUserAsync(User);
45 | if (user == null)
46 | {
47 | throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
48 | }
49 |
50 | var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false);
51 | if (!disable2faResult.Succeeded)
52 | {
53 | throw new ApplicationException($"Unexpected error occurred disabling 2FA for user with ID '{_userManager.GetUserId(User)}'.");
54 | }
55 |
56 | _logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User));
57 |
58 | return RedirectToPage("./TwoFactorAuthentication");
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Test/TestBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DDD.NetCore.Infrastructure.EfCore;
3 | using DDD.NetCore.Test.TestData;
4 | using Microsoft.Data.Sqlite;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Diagnostics;
7 | using Microsoft.Extensions.Options;
8 |
9 | namespace DDD.NetCore.Test
10 | {
11 | public class TestBase
12 | {
13 | ///
14 | /// 内存数据库,用于测试关系型数据库
15 | ///
16 | public ApplicationDbContext InMemoryTestDbContext { get; set; }
17 |
18 | ///
19 | /// 内存数据库,用于测试非关系型数据库
20 | ///
21 | public ApplicationDbContext InMemorySqliteTestDbContext { get; set; }
22 |
23 |
24 | public TestBase()
25 | {
26 | GetInMemoryDbContext();
27 | GetSqliteInMemoryDbContext();
28 | }
29 |
30 | private ApplicationDbContext GetInMemoryDbContext()
31 | {
32 | var options = new DbContextOptionsBuilder()
33 | .UseInMemoryDatabase(Guid.NewGuid().ToString())
34 | // don't raise the error warning us that the in memory db doesn't support transactions
35 | .ConfigureWarnings(x => x.Ignore(InMemoryEventId.TransactionIgnoredWarning))
36 | .Options;
37 |
38 | InMemoryTestDbContext = new ApplicationDbContext(options);
39 | GoodsTestData.Initialize(InMemoryTestDbContext);
40 | UsersTestData.CreateTestUser(InMemoryTestDbContext);
41 | return InMemoryTestDbContext;
42 | }
43 |
44 | public ApplicationDbContext GetSqliteInMemoryDbContext()
45 | {
46 | // In-memory database only exists while the connection is open
47 | var connection = new SqliteConnection("DataSource=:memory:");
48 | connection.Open();
49 | var options = new DbContextOptionsBuilder()
50 | .UseSqlite(connection)
51 | .Options;
52 |
53 | InMemorySqliteTestDbContext = new ApplicationDbContext(options);
54 | InMemorySqliteTestDbContext.Database.EnsureCreated();
55 |
56 | GoodsTestData.Initialize(InMemorySqliteTestDbContext);
57 | UsersTestData.CreateTestUser(InMemorySqliteTestDbContext);
58 |
59 | return InMemorySqliteTestDbContext;
60 |
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/DDD.NetCore/Domain/Uow/UnitOfWork.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DDD.NetCore.Domain.Entities;
3 | using DDD.NetCore.Domain.Repositories;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Storage;
6 |
7 | namespace DDD.NetCore.Domain.Uow
8 | {
9 | public class UnitOfWork : IUnitOfWork where TDbContext : DbContext
10 | {
11 | private bool _disposed = false;
12 |
13 | private IDbContextTransaction _transaction;
14 |
15 | private IServiceProvider _serviceProvider;
16 | public UnitOfWork(TDbContext dbContext,IServiceProvider serviceProvider)
17 | {
18 | DbContext = dbContext;
19 | _serviceProvider = serviceProvider;
20 | }
21 |
22 |
23 | public IRepository GetRepository() where TEntity : class, IEntity
24 | {
25 | var repository = GetRepository() as IRepository;
26 | return repository;
27 | }
28 |
29 | public IRepository GetRepository() where TEntity : class, IEntity
30 | {
31 | //return _serviceProvider.GetService>();
32 | return new EfCoreRepository(DbContext);
33 | }
34 |
35 | public void SaveChanges()
36 | {
37 | DbContext.SaveChanges();
38 | }
39 |
40 | public IDbContextTransaction BeginTransaction()
41 | {
42 | _transaction = DbContext.Database.BeginTransaction();
43 | return _transaction;
44 | }
45 |
46 | public TDbContext DbContext { get; }
47 |
48 | ///
49 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
50 | ///
51 | public void Dispose()
52 | {
53 | Dispose(true);
54 |
55 | GC.SuppressFinalize(this);
56 | }
57 |
58 | ///
59 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
60 | ///
61 | /// The disposing.
62 | protected virtual void Dispose(bool disposing)
63 | {
64 | if (!_disposed)
65 | {
66 | if (disposing)
67 | {
68 | _transaction.Dispose();
69 | DbContext.Dispose();
70 | }
71 | }
72 |
73 | _disposed = true;
74 | }
75 |
76 | }
77 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/Manage/EnableAuthenticator.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model EnableAuthenticatorModel
3 | @{
4 | ViewData["Title"] = "Configure authenticator app";
5 | ViewData["ActivePage"] = "TwoFactorAuthentication";
6 | }
7 |
8 |
@ViewData["Title"]
9 |
10 |
To use an authenticator app go through the following steps:
11 |
12 |
13 |
14 | Download a two-factor authenticator app like Microsoft Authenticator for
15 | Windows Phone,
16 | Android and
17 | iOS or
18 | Google Authenticator for
19 | Android and
20 | iOS.
21 |
22 |
23 |
24 |
Scan the QR Code or enter this key @Model.SharedKey into your two factor authenticator app. Spaces and casing do not matter.
25 |
To enable QR code generation please read our documentation.
26 |
27 |
28 |
29 |
30 |
31 | Once you have scanned the QR code or input the key above, your two factor authentication app will provide you
32 | with a unique code. Enter the code in the confirmation box below.
33 |
34 |
35 |
36 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | @section Scripts {
52 | @await Html.PartialAsync("_ValidationScriptsPartial")
53 | }
54 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Identity;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.EntityFrameworkCore;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using DDD.NetCore.Web.Data;
13 | using DDD.NetCore.Web.Services;
14 |
15 | namespace DDD.NetCore.Web
16 | {
17 | public class Startup
18 | {
19 | public Startup(IConfiguration configuration)
20 | {
21 | Configuration = configuration;
22 | }
23 |
24 | public IConfiguration Configuration { get; }
25 |
26 | // This method gets called by the runtime. Use this method to add services to the container.
27 | public void ConfigureServices(IServiceCollection services)
28 | {
29 | services.AddDbContext(options =>
30 | options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
31 |
32 | services.AddIdentity()
33 | .AddEntityFrameworkStores()
34 | .AddDefaultTokenProviders();
35 |
36 | services.AddMvc()
37 | .AddRazorPagesOptions(options =>
38 | {
39 | options.Conventions.AuthorizeFolder("/Account/Manage");
40 | options.Conventions.AuthorizePage("/Account/Logout");
41 | });
42 |
43 | // Register no-op EmailSender used by account confirmation and password reset during development
44 | // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=532713
45 | services.AddSingleton();
46 | }
47 |
48 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
49 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
50 | {
51 | if (env.IsDevelopment())
52 | {
53 | app.UseDeveloperExceptionPage();
54 | app.UseBrowserLink();
55 | app.UseDatabaseErrorPage();
56 | }
57 | else
58 | {
59 | app.UseExceptionHandler("/Error");
60 | }
61 |
62 | app.UseStaticFiles();
63 |
64 | app.UseAuthentication();
65 |
66 | app.UseMvc(routes =>
67 | {
68 | routes.MapRoute(
69 | name: "default",
70 | template: "{controller}/{action=Index}/{id?}");
71 | });
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/DDD.NetCore.Infrastructure/EfCore/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using DDD.NetCore.Domain.Authorization;
2 | using DDD.NetCore.Domain.Customers;
3 | using DDD.NetCore.Domain.Goods;
4 | using DDD.NetCore.Domain.Orders;
5 | using DDD.NetCore.Domain.ShoppingCarts;
6 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
7 | using Microsoft.EntityFrameworkCore;
8 |
9 | namespace DDD.NetCore.Infrastructure.EfCore
10 | {
11 | public class ApplicationDbContext : IdentityDbContext
12 | {
13 | public ApplicationDbContext(DbContextOptions options)
14 | : base(options)
15 | {
16 | }
17 | //private readonly DbConnection _dbConnection;
18 | //public ApplicationDbContext(DbConnection dbConnection)
19 | //{
20 | // _dbConnection = dbConnection;
21 | //}
22 |
23 | public DbSet Customers { get; set; }
24 | public DbSet Goods { get; set; }
25 | public DbSet GoodsCategories { get; set; }
26 | public DbSet ShoppingCarts { get; set; }
27 | public DbSet ShoppingCartLines { get; set; }
28 |
29 | public DbSet Addresses { get; set; }
30 |
31 | public DbSet SaleOrders { get; set; }
32 |
33 | public DbSet SaleOrderLines { get; set; }
34 |
35 | //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
36 | //{
37 | // optionsBuilder.UseSqlServer(_dbConnection);
38 | //}
39 |
40 | protected override void OnModelCreating(ModelBuilder builder)
41 | {
42 | base.OnModelCreating(builder);
43 | // Customize the ASP.NET Identity model and override the defaults if needed.
44 | // For example, you can rename the ASP.NET Identity table names and more.
45 | // Add your customizations after calling base.OnModelCreating(builder);
46 | builder.Entity().HasOne(c => c.ApplicationUser);
47 | builder.Entity()
48 | .HasOne(c => c.ShoppingCart)
49 | .WithOne(sc => sc.Customer)
50 | .HasForeignKey(c => c.CustomerId);
51 |
52 | builder.Entity().HasMany(c => c.ShippingAddresses);
53 | builder.Entity().HasMany(sc => sc.ShoppingCartLines).WithOne(cl => cl.ShoppingCart);
54 | builder.Entity().HasOne(scl => scl.Goods);
55 |
56 | builder.Entity().HasOne(g => g.GoodsCategory).WithMany(gc => gc.GoodsList);
57 |
58 | builder.Entity().HasMany(so => so.SaleOrderLines).WithOne(sol => sol.SaleOrder);
59 | builder.Entity().HasOne(so => so.Customer);
60 | builder.Entity().HasOne(so => so.DeliveryAddress);
61 |
62 | builder.Entity().HasOne(sol => sol.Goods);
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/ResetPassword.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Identity;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.AspNetCore.Mvc.RazorPages;
9 | using DDD.NetCore.Web.Data;
10 |
11 | namespace DDD.NetCore.Web.Pages.Account
12 | {
13 | public class ResetPasswordModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 |
17 | public ResetPasswordModel(UserManager userManager)
18 | {
19 | _userManager = userManager;
20 | }
21 |
22 | [BindProperty]
23 | public InputModel Input { get; set; }
24 |
25 | public class InputModel
26 | {
27 | [Required]
28 | [EmailAddress]
29 | public string Email { get; set; }
30 |
31 | [Required]
32 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
33 | [DataType(DataType.Password)]
34 | public string Password { get; set; }
35 |
36 | [DataType(DataType.Password)]
37 | [Display(Name = "Confirm password")]
38 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
39 | public string ConfirmPassword { get; set; }
40 |
41 | public string Code { get; set; }
42 | }
43 |
44 | public IActionResult OnGet(string code = null)
45 | {
46 | if (code == null)
47 | {
48 | throw new ApplicationException("A code must be supplied for password reset.");
49 | }
50 | else
51 | {
52 | Input = new InputModel
53 | {
54 | Code = code
55 | };
56 | return Page();
57 | }
58 | }
59 |
60 | public async Task OnPostAsync()
61 | {
62 | if (!ModelState.IsValid)
63 | {
64 | return Page();
65 | }
66 |
67 | var user = await _userManager.FindByEmailAsync(Input.Email);
68 | if (user == null)
69 | {
70 | // Don't reveal that the user does not exist
71 | return RedirectToPage("./ResetPasswordConfirmation");
72 | }
73 |
74 | var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password);
75 | if (result.Succeeded)
76 | {
77 | return RedirectToPage("./ResetPasswordConfirmation");
78 | }
79 |
80 | foreach (var error in result.Errors)
81 | {
82 | ModelState.AddModelError(string.Empty, error.Description);
83 | }
84 | return Page();
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/LoginWithRecoveryCode.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Identity;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.AspNetCore.Mvc.RazorPages;
9 | using Microsoft.Extensions.Logging;
10 | using DDD.NetCore.Web.Data;
11 |
12 | namespace DDD.NetCore.Web.Pages.Account
13 | {
14 | public class LoginWithRecoveryCodeModel : PageModel
15 | {
16 | private readonly SignInManager _signInManager;
17 | private readonly ILogger _logger;
18 |
19 | public LoginWithRecoveryCodeModel(SignInManager signInManager, ILogger logger)
20 | {
21 | _signInManager = signInManager;
22 | _logger = logger;
23 | }
24 |
25 | [BindProperty]
26 | public InputModel Input { get; set; }
27 |
28 | public string ReturnUrl { get; set; }
29 |
30 | public class InputModel
31 | {
32 | [BindProperty]
33 | [Required]
34 | [DataType(DataType.Text)]
35 | [Display(Name = "Recovery Code")]
36 | public string RecoveryCode { get; set; }
37 | }
38 |
39 | public async Task OnGetAsync(string returnUrl = null)
40 | {
41 | // Ensure the user has gone through the username & password screen first
42 | var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
43 | if (user == null)
44 | {
45 | throw new ApplicationException($"Unable to load two-factor authentication user.");
46 | }
47 |
48 | ReturnUrl = returnUrl;
49 |
50 | return Page();
51 | }
52 |
53 | public async Task OnPostAsync(string returnUrl = null)
54 | {
55 | if (!ModelState.IsValid)
56 | {
57 | return Page();
58 | }
59 |
60 | var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
61 | if (user == null)
62 | {
63 | throw new ApplicationException($"Unable to load two-factor authentication user.");
64 | }
65 |
66 | var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty);
67 |
68 | var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
69 |
70 | if (result.Succeeded)
71 | {
72 | _logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", user.Id);
73 | return LocalRedirect(Url.GetLocalUrl(returnUrl));
74 | }
75 | if (result.IsLockedOut)
76 | {
77 | _logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id);
78 | return RedirectToPage("./Lockout");
79 | }
80 | else
81 | {
82 | _logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", user.Id);
83 | ModelState.AddModelError(string.Empty, "Invalid recovery code entered.");
84 | return Page();
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/Account/Manage/SetPassword.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Identity;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.AspNetCore.Mvc.RazorPages;
9 | using DDD.NetCore.Web.Data;
10 |
11 | namespace DDD.NetCore.Web.Pages.Account.Manage
12 | {
13 | public class SetPasswordModel : PageModel
14 | {
15 | private readonly UserManager _userManager;
16 | private readonly SignInManager _signInManager;
17 |
18 | public SetPasswordModel(
19 | UserManager userManager,
20 | SignInManager signInManager)
21 | {
22 | _userManager = userManager;
23 | _signInManager = signInManager;
24 | }
25 |
26 | [BindProperty]
27 | public InputModel Input { get; set; }
28 |
29 | [TempData]
30 | public string StatusMessage { get; set; }
31 |
32 | public class InputModel
33 | {
34 | [Required]
35 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
36 | [DataType(DataType.Password)]
37 | [Display(Name = "New password")]
38 | public string NewPassword { get; set; }
39 |
40 | [DataType(DataType.Password)]
41 | [Display(Name = "Confirm new password")]
42 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
43 | public string ConfirmPassword { get; set; }
44 | }
45 |
46 | public async Task OnGetAsync()
47 | {
48 | var user = await _userManager.GetUserAsync(User);
49 | if (user == null)
50 | {
51 | throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
52 | }
53 |
54 | var hasPassword = await _userManager.HasPasswordAsync(user);
55 |
56 | if (hasPassword)
57 | {
58 | return RedirectToPage("./ChangePassword");
59 | }
60 |
61 | return Page();
62 | }
63 |
64 | public async Task OnPostAsync()
65 | {
66 | if (!ModelState.IsValid)
67 | {
68 | return Page();
69 | }
70 |
71 | var user = await _userManager.GetUserAsync(User);
72 | if (user == null)
73 | {
74 | throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
75 | }
76 |
77 | var addPasswordResult = await _userManager.AddPasswordAsync(user, Input.NewPassword);
78 | if (!addPasswordResult.Succeeded)
79 | {
80 | foreach (var error in addPasswordResult.Errors)
81 | {
82 | ModelState.AddModelError(string.Empty, error.Description);
83 | }
84 | return Page();
85 | }
86 |
87 | await _signInManager.SignInAsync(user, isPersistent: false);
88 | StatusMessage = "Your password has been set.";
89 |
90 | return RedirectToPage();
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/DDD.NetCore.Test/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using DDD.NetCore.Domain.Customers;
4 | using DDD.NetCore.Domain.ShoppingCarts;
5 | using Microsoft.EntityFrameworkCore;
6 | using Xunit;
7 |
8 | namespace DDD.NetCore.Test
9 | {
10 | public class UnitTest1 : TestBase
11 | {
12 | [Fact]
13 | public void Test1()
14 | {
15 | var result = InMemorySqliteTestDbContext.Database.EnsureCreated();
16 | Assert.Equal(true, InMemorySqliteTestDbContext.Goods.Any());
17 |
18 | }
19 |
20 | [Fact]
21 | public void Test2()
22 | {
23 | var customerCount = InMemorySqliteTestDbContext.Customers.Count();
24 | var shoppingCartCount = InMemorySqliteTestDbContext.ShoppingCarts.Count();
25 | using (var trasnaction = InMemorySqliteTestDbContext.Database.BeginTransaction())
26 | {
27 | var user = InMemorySqliteTestDbContext.Users.FirstOrDefault();
28 | var customer = new Customer() { ApplicationUserId = user.Id };
29 | InMemorySqliteTestDbContext.Customers.Add(customer);
30 | InMemorySqliteTestDbContext.SaveChanges();
31 |
32 | var cart = new ShoppingCart() { CustomerId = customer.Id };
33 | InMemorySqliteTestDbContext.ShoppingCarts.Add(cart);
34 | InMemorySqliteTestDbContext.SaveChanges();
35 |
36 | customer.ShoppingCartId = cart.Id;
37 | InMemorySqliteTestDbContext.Entry(customer).State = EntityState.Modified;
38 | InMemorySqliteTestDbContext.SaveChanges();
39 |
40 | trasnaction.Commit();
41 | }
42 | Assert.Equal(customerCount + 1, InMemorySqliteTestDbContext.Customers.Count());
43 | Assert.Equal(shoppingCartCount + 1, InMemorySqliteTestDbContext.ShoppingCarts.Count());
44 | }
45 |
46 | [Fact]
47 | public void Test3()
48 | {
49 | var customerCount = InMemorySqliteTestDbContext.Customers.Count();
50 | var shoppingCartCount = InMemorySqliteTestDbContext.ShoppingCarts.Count();
51 | using (var trasnaction = InMemorySqliteTestDbContext.Database.BeginTransaction())
52 | {
53 | try
54 | {
55 | var user = InMemorySqliteTestDbContext.Users.FirstOrDefault();
56 | var customer = new Customer() { ApplicationUserId = user.Id };
57 | InMemorySqliteTestDbContext.Customers.Add(customer);
58 | InMemorySqliteTestDbContext.SaveChanges();
59 |
60 | var cart = new ShoppingCart();//{ CustomerId = customer.Id };
61 | InMemorySqliteTestDbContext.ShoppingCarts.Add(cart);
62 | InMemorySqliteTestDbContext.SaveChanges();
63 |
64 | customer.ShoppingCartId = cart.Id;
65 | InMemorySqliteTestDbContext.Entry(customer).State = EntityState.Modified;
66 | InMemorySqliteTestDbContext.SaveChanges();
67 |
68 | trasnaction.Commit();
69 | }
70 | catch (System.Exception)
71 | {
72 | trasnaction.Rollback();
73 | }
74 | }
75 | Assert.Equal(customerCount, InMemorySqliteTestDbContext.Customers.Count());
76 | Assert.Equal(shoppingCartCount, InMemorySqliteTestDbContext.ShoppingCarts.Count());
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/DDD.NetCore.Web/Pages/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - DDD.NetCore.Web
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
41 |
57 | There are no external authentication services configured. See this article
58 | for details on setting up this ASP.NET application to support logging in via external services.
59 |