Browse Source
* udated to .net6 * used the .net6 version RC2 * added editconfig. * App core new Scoped Namespaces style. * BlazorAdmin new Scoped Namespaces style. * Blazor Shared new Scoped Namespaces style. * Infra new Scoped Namespaces style. * public api new Scoped Namespaces style. * web new Scoped Namespaces style. * FunctionalTests new Scoped Namespaces style. * Integrational tests new Scoped Namespaces style. * unit tests new Scoped Namespaces style. * update github action. * update github action. * change the global.main
committed by
GitHub
252 changed files with 6120 additions and 6226 deletions
@ -0,0 +1,134 @@ |
|||||
|
############################### |
||||
|
# Core EditorConfig Options # |
||||
|
############################### |
||||
|
root = true |
||||
|
# All files |
||||
|
[*] |
||||
|
indent_style = space |
||||
|
|
||||
|
# XML project files |
||||
|
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] |
||||
|
indent_size = 2 |
||||
|
|
||||
|
# XML config files |
||||
|
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] |
||||
|
indent_size = 2 |
||||
|
|
||||
|
# Code files |
||||
|
[*.{cs,csx,vb,vbx}] |
||||
|
indent_size = 4 |
||||
|
insert_final_newline = true |
||||
|
charset = utf-8-bom |
||||
|
############################### |
||||
|
# .NET Coding Conventions # |
||||
|
############################### |
||||
|
[*.{cs,vb}] |
||||
|
# Organize usings |
||||
|
dotnet_sort_system_directives_first = true |
||||
|
# this. preferences |
||||
|
dotnet_style_qualification_for_field = false:silent |
||||
|
dotnet_style_qualification_for_property = false:silent |
||||
|
dotnet_style_qualification_for_method = false:silent |
||||
|
dotnet_style_qualification_for_event = false:silent |
||||
|
# Language keywords vs BCL types preferences |
||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true:silent |
||||
|
dotnet_style_predefined_type_for_member_access = true:silent |
||||
|
# Parentheses preferences |
||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent |
||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent |
||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent |
||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent |
||||
|
# Modifier preferences |
||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent |
||||
|
dotnet_style_readonly_field = true:suggestion |
||||
|
# Expression-level preferences |
||||
|
dotnet_style_object_initializer = true:suggestion |
||||
|
dotnet_style_collection_initializer = true:suggestion |
||||
|
dotnet_style_explicit_tuple_names = true:suggestion |
||||
|
dotnet_style_null_propagation = true:suggestion |
||||
|
dotnet_style_coalesce_expression = true:suggestion |
||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent |
||||
|
dotnet_style_prefer_inferred_tuple_names = true:suggestion |
||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion |
||||
|
dotnet_style_prefer_auto_properties = true:silent |
||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true:silent |
||||
|
dotnet_style_prefer_conditional_expression_over_return = true:silent |
||||
|
############################### |
||||
|
# Naming Conventions # |
||||
|
############################### |
||||
|
# Style Definitions |
||||
|
dotnet_naming_style.pascal_case_style.capitalization = pascal_case |
||||
|
# Use PascalCase for constant fields |
||||
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion |
||||
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields |
||||
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style |
||||
|
dotnet_naming_symbols.constant_fields.applicable_kinds = field |
||||
|
dotnet_naming_symbols.constant_fields.applicable_accessibilities = * |
||||
|
dotnet_naming_symbols.constant_fields.required_modifiers = const |
||||
|
############################### |
||||
|
# C# Coding Conventions # |
||||
|
############################### |
||||
|
[*.cs] |
||||
|
# var preferences |
||||
|
csharp_style_var_for_built_in_types = true:silent |
||||
|
csharp_style_var_when_type_is_apparent = true:silent |
||||
|
csharp_style_var_elsewhere = true:silent |
||||
|
# Expression-bodied members |
||||
|
csharp_style_expression_bodied_methods = false:silent |
||||
|
csharp_style_expression_bodied_constructors = false:silent |
||||
|
csharp_style_expression_bodied_operators = false:silent |
||||
|
csharp_style_expression_bodied_properties = true:silent |
||||
|
csharp_style_expression_bodied_indexers = true:silent |
||||
|
csharp_style_expression_bodied_accessors = true:silent |
||||
|
# Pattern matching preferences |
||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion |
||||
|
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion |
||||
|
# Null-checking preferences |
||||
|
csharp_style_throw_expression = true:suggestion |
||||
|
csharp_style_conditional_delegate_call = true:suggestion |
||||
|
# Modifier preferences |
||||
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion |
||||
|
# Expression-level preferences |
||||
|
csharp_prefer_braces = true:silent |
||||
|
csharp_style_deconstructed_variable_declaration = true:suggestion |
||||
|
csharp_prefer_simple_default_expression = true:suggestion |
||||
|
csharp_style_pattern_local_over_anonymous_function = true:suggestion |
||||
|
csharp_style_inlined_variable_declaration = true:suggestion |
||||
|
# Namespaces |
||||
|
csharp_style_namespace_declarations = file_scoped:warning |
||||
|
############################### |
||||
|
# C# Formatting Rules # |
||||
|
############################### |
||||
|
# New line preferences |
||||
|
csharp_new_line_before_open_brace = all |
||||
|
csharp_new_line_before_else = true |
||||
|
csharp_new_line_before_catch = true |
||||
|
csharp_new_line_before_finally = true |
||||
|
csharp_new_line_before_members_in_object_initializers = true |
||||
|
csharp_new_line_before_members_in_anonymous_types = true |
||||
|
csharp_new_line_between_query_expression_clauses = true |
||||
|
# Indentation preferences |
||||
|
csharp_indent_case_contents = true |
||||
|
csharp_indent_switch_labels = true |
||||
|
csharp_indent_labels = flush_left |
||||
|
# Space preferences |
||||
|
csharp_space_after_cast = false |
||||
|
csharp_space_after_keywords_in_control_flow_statements = true |
||||
|
csharp_space_between_method_call_parameter_list_parentheses = false |
||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false |
||||
|
csharp_space_between_parentheses = false |
||||
|
csharp_space_before_colon_in_inheritance_clause = true |
||||
|
csharp_space_after_colon_in_inheritance_clause = true |
||||
|
csharp_space_around_binary_operators = before_and_after |
||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false |
||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false |
||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false |
||||
|
# Wrapping preferences |
||||
|
csharp_preserve_single_line_statements = true |
||||
|
csharp_preserve_single_line_blocks = true |
||||
|
############################### |
||||
|
# VB Coding Conventions # |
||||
|
############################### |
||||
|
[*.vb] |
||||
|
# Modifier preferences |
||||
|
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"sdk": { |
||||
|
"version": "6.0.x", |
||||
|
"rollForward": "latestFeature" |
||||
|
} |
||||
|
} |
||||
@ -1,7 +1,6 @@ |
|||||
namespace Microsoft.eShopWeb |
namespace Microsoft.eShopWeb; |
||||
|
|
||||
|
public class CatalogSettings |
||||
{ |
{ |
||||
public class CatalogSettings |
public string CatalogBaseUrl { get; set; } |
||||
{ |
|
||||
public string CatalogBaseUrl { get; set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,13 +1,12 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Constants |
namespace Microsoft.eShopWeb.ApplicationCore.Constants; |
||||
|
|
||||
|
public class AuthorizationConstants |
||||
{ |
{ |
||||
public class AuthorizationConstants |
public const string AUTH_KEY = "AuthKeyOfDoomThatMustBeAMinimumNumberOfBytes"; |
||||
{ |
|
||||
public const string AUTH_KEY = "AuthKeyOfDoomThatMustBeAMinimumNumberOfBytes"; |
|
||||
|
|
||||
// TODO: Don't use this in production
|
// TODO: Don't use this in production
|
||||
public const string DEFAULT_PASSWORD = "Pass@word1"; |
public const string DEFAULT_PASSWORD = "Pass@word1"; |
||||
|
|
||||
// TODO: Change this to an environment variable
|
// TODO: Change this to an environment variable
|
||||
public const string JWT_SECRET_KEY = "SecretKeyOfDoomThatMustBeAMinimumNumberOfBytes"; |
public const string JWT_SECRET_KEY = "SecretKeyOfDoomThatMustBeAMinimumNumberOfBytes"; |
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities |
namespace Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
|
// This can easily be modified to be BaseEntity<T> and public T Id to support different key types.
|
||||
|
// Using non-generic integer types for simplicity and to ease caching logic
|
||||
|
public abstract class BaseEntity |
||||
{ |
{ |
||||
// This can easily be modified to be BaseEntity<T> and public T Id to support different key types.
|
public virtual int Id { get; protected set; } |
||||
// Using non-generic integer types for simplicity and to ease caching logic
|
|
||||
public abstract class BaseEntity |
|
||||
{ |
|
||||
public virtual int Id { get; protected set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,39 +1,38 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
using System.Linq; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
|
|
||||
|
public class Basket : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class Basket : BaseEntity, IAggregateRoot |
public string BuyerId { get; private set; } |
||||
{ |
private readonly List<BasketItem> _items = new List<BasketItem>(); |
||||
public string BuyerId { get; private set; } |
public IReadOnlyCollection<BasketItem> Items => _items.AsReadOnly(); |
||||
private readonly List<BasketItem> _items = new List<BasketItem>(); |
|
||||
public IReadOnlyCollection<BasketItem> Items => _items.AsReadOnly(); |
|
||||
|
|
||||
public Basket(string buyerId) |
public Basket(string buyerId) |
||||
{ |
{ |
||||
BuyerId = buyerId; |
BuyerId = buyerId; |
||||
} |
} |
||||
|
|
||||
public void AddItem(int catalogItemId, decimal unitPrice, int quantity = 1) |
public void AddItem(int catalogItemId, decimal unitPrice, int quantity = 1) |
||||
|
{ |
||||
|
if (!Items.Any(i => i.CatalogItemId == catalogItemId)) |
||||
{ |
{ |
||||
if (!Items.Any(i => i.CatalogItemId == catalogItemId)) |
_items.Add(new BasketItem(catalogItemId, quantity, unitPrice)); |
||||
{ |
return; |
||||
_items.Add(new BasketItem(catalogItemId, quantity, unitPrice)); |
|
||||
return; |
|
||||
} |
|
||||
var existingItem = Items.FirstOrDefault(i => i.CatalogItemId == catalogItemId); |
|
||||
existingItem.AddQuantity(quantity); |
|
||||
} |
} |
||||
|
var existingItem = Items.FirstOrDefault(i => i.CatalogItemId == catalogItemId); |
||||
|
existingItem.AddQuantity(quantity); |
||||
|
} |
||||
|
|
||||
public void RemoveEmptyItems() |
public void RemoveEmptyItems() |
||||
{ |
{ |
||||
_items.RemoveAll(i => i.Quantity == 0); |
_items.RemoveAll(i => i.Quantity == 0); |
||||
} |
} |
||||
|
|
||||
public void SetNewBuyerId(string buyerId) |
public void SetNewBuyerId(string buyerId) |
||||
{ |
{ |
||||
BuyerId = buyerId; |
BuyerId = buyerId; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,34 +1,33 @@ |
|||||
using Ardalis.GuardClauses; |
using Ardalis.GuardClauses; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
|
|
||||
|
public class BasketItem : BaseEntity |
||||
{ |
{ |
||||
public class BasketItem : BaseEntity |
|
||||
{ |
|
||||
|
|
||||
public decimal UnitPrice { get; private set; } |
public decimal UnitPrice { get; private set; } |
||||
public int Quantity { get; private set; } |
public int Quantity { get; private set; } |
||||
public int CatalogItemId { get; private set; } |
public int CatalogItemId { get; private set; } |
||||
public int BasketId { get; private set; } |
public int BasketId { get; private set; } |
||||
|
|
||||
public BasketItem(int catalogItemId, int quantity, decimal unitPrice) |
public BasketItem(int catalogItemId, int quantity, decimal unitPrice) |
||||
{ |
{ |
||||
CatalogItemId = catalogItemId; |
CatalogItemId = catalogItemId; |
||||
UnitPrice = unitPrice; |
UnitPrice = unitPrice; |
||||
SetQuantity(quantity); |
SetQuantity(quantity); |
||||
} |
} |
||||
|
|
||||
public void AddQuantity(int quantity) |
public void AddQuantity(int quantity) |
||||
{ |
{ |
||||
Guard.Against.OutOfRange(quantity, nameof(quantity), 0, int.MaxValue); |
Guard.Against.OutOfRange(quantity, nameof(quantity), 0, int.MaxValue); |
||||
|
|
||||
Quantity += quantity; |
Quantity += quantity; |
||||
} |
} |
||||
|
|
||||
public void SetQuantity(int quantity) |
public void SetQuantity(int quantity) |
||||
{ |
{ |
||||
Guard.Against.OutOfRange(quantity, nameof(quantity), 0, int.MaxValue); |
Guard.Against.OutOfRange(quantity, nameof(quantity), 0, int.MaxValue); |
||||
|
|
||||
Quantity = quantity; |
Quantity = quantity; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,26 +1,25 @@ |
|||||
using Ardalis.GuardClauses; |
using System.Collections.Generic; |
||||
|
using Ardalis.GuardClauses; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate; |
||||
|
|
||||
|
public class Buyer : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class Buyer : BaseEntity, IAggregateRoot |
public string IdentityGuid { get; private set; } |
||||
{ |
|
||||
public string IdentityGuid { get; private set; } |
|
||||
|
|
||||
private List<PaymentMethod> _paymentMethods = new List<PaymentMethod>(); |
private List<PaymentMethod> _paymentMethods = new List<PaymentMethod>(); |
||||
|
|
||||
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly(); |
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly(); |
||||
|
|
||||
private Buyer() |
private Buyer() |
||||
{ |
{ |
||||
// required by EF
|
// required by EF
|
||||
} |
} |
||||
|
|
||||
public Buyer(string identity) : this() |
public Buyer(string identity) : this() |
||||
{ |
{ |
||||
Guard.Against.NullOrEmpty(identity, nameof(identity)); |
Guard.Against.NullOrEmpty(identity, nameof(identity)); |
||||
IdentityGuid = identity; |
IdentityGuid = identity; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate; |
||||
|
|
||||
|
public class PaymentMethod : BaseEntity |
||||
{ |
{ |
||||
public class PaymentMethod : BaseEntity |
public string Alias { get; private set; } |
||||
{ |
public string CardId { get; private set; } // actual card data must be stored in a PCI compliant system, like Stripe
|
||||
public string Alias { get; private set; } |
public string Last4 { get; private set; } |
||||
public string CardId { get; private set; } // actual card data must be stored in a PCI compliant system, like Stripe
|
|
||||
public string Last4 { get; private set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,13 +1,12 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities |
namespace Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
|
public class CatalogBrand : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class CatalogBrand : BaseEntity, IAggregateRoot |
public string Brand { get; private set; } |
||||
|
public CatalogBrand(string brand) |
||||
{ |
{ |
||||
public string Brand { get; private set; } |
Brand = brand; |
||||
public CatalogBrand(string brand) |
|
||||
{ |
|
||||
Brand = brand; |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,66 +1,65 @@ |
|||||
using Ardalis.GuardClauses; |
using System; |
||||
|
using Ardalis.GuardClauses; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
using System; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities |
namespace Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
|
public class CatalogItem : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class CatalogItem : BaseEntity, IAggregateRoot |
public string Name { get; private set; } |
||||
{ |
public string Description { get; private set; } |
||||
public string Name { get; private set; } |
public decimal Price { get; private set; } |
||||
public string Description { get; private set; } |
public string PictureUri { get; private set; } |
||||
public decimal Price { get; private set; } |
public int CatalogTypeId { get; private set; } |
||||
public string PictureUri { get; private set; } |
public CatalogType CatalogType { get; private set; } |
||||
public int CatalogTypeId { get; private set; } |
public int CatalogBrandId { get; private set; } |
||||
public CatalogType CatalogType { get; private set; } |
public CatalogBrand CatalogBrand { get; private set; } |
||||
public int CatalogBrandId { get; private set; } |
|
||||
public CatalogBrand CatalogBrand { get; private set; } |
|
||||
|
|
||||
public CatalogItem(int catalogTypeId, |
public CatalogItem(int catalogTypeId, |
||||
int catalogBrandId, |
int catalogBrandId, |
||||
string description, |
string description, |
||||
string name, |
string name, |
||||
decimal price, |
decimal price, |
||||
string pictureUri) |
string pictureUri) |
||||
{ |
{ |
||||
CatalogTypeId = catalogTypeId; |
CatalogTypeId = catalogTypeId; |
||||
CatalogBrandId = catalogBrandId; |
CatalogBrandId = catalogBrandId; |
||||
Description = description; |
Description = description; |
||||
Name = name; |
Name = name; |
||||
Price = price; |
Price = price; |
||||
PictureUri = pictureUri; |
PictureUri = pictureUri; |
||||
} |
} |
||||
|
|
||||
public void UpdateDetails(string name, string description, decimal price) |
public void UpdateDetails(string name, string description, decimal price) |
||||
{ |
{ |
||||
Guard.Against.NullOrEmpty(name, nameof(name)); |
Guard.Against.NullOrEmpty(name, nameof(name)); |
||||
Guard.Against.NullOrEmpty(description, nameof(description)); |
Guard.Against.NullOrEmpty(description, nameof(description)); |
||||
Guard.Against.NegativeOrZero(price, nameof(price)); |
Guard.Against.NegativeOrZero(price, nameof(price)); |
||||
|
|
||||
Name = name; |
Name = name; |
||||
Description = description; |
Description = description; |
||||
Price = price; |
Price = price; |
||||
} |
} |
||||
|
|
||||
public void UpdateBrand(int catalogBrandId) |
public void UpdateBrand(int catalogBrandId) |
||||
{ |
{ |
||||
Guard.Against.Zero(catalogBrandId, nameof(catalogBrandId)); |
Guard.Against.Zero(catalogBrandId, nameof(catalogBrandId)); |
||||
CatalogBrandId = catalogBrandId; |
CatalogBrandId = catalogBrandId; |
||||
} |
} |
||||
|
|
||||
public void UpdateType(int catalogTypeId) |
public void UpdateType(int catalogTypeId) |
||||
{ |
{ |
||||
Guard.Against.Zero(catalogTypeId, nameof(catalogTypeId)); |
Guard.Against.Zero(catalogTypeId, nameof(catalogTypeId)); |
||||
CatalogTypeId = catalogTypeId; |
CatalogTypeId = catalogTypeId; |
||||
} |
} |
||||
|
|
||||
public void UpdatePictureUri(string pictureName) |
public void UpdatePictureUri(string pictureName) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(pictureName)) |
||||
{ |
{ |
||||
if (string.IsNullOrEmpty(pictureName)) |
PictureUri = string.Empty; |
||||
{ |
return; |
||||
PictureUri = string.Empty; |
|
||||
return; |
|
||||
} |
|
||||
PictureUri = $"images\\products\\{pictureName}?{new DateTime().Ticks}"; |
|
||||
} |
} |
||||
|
PictureUri = $"images\\products\\{pictureName}?{new DateTime().Ticks}"; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,13 +1,12 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities |
namespace Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
|
public class CatalogType : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class CatalogType : BaseEntity, IAggregateRoot |
public string Type { get; private set; } |
||||
|
public CatalogType(string type) |
||||
{ |
{ |
||||
public string Type { get; private set; } |
Type = type; |
||||
public CatalogType(string type) |
|
||||
{ |
|
||||
Type = type; |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,26 +1,25 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
|
public class Address // ValueObject
|
||||
{ |
{ |
||||
public class Address // ValueObject
|
public string Street { get; private set; } |
||||
{ |
|
||||
public string Street { get; private set; } |
|
||||
|
|
||||
public string City { get; private set; } |
public string City { get; private set; } |
||||
|
|
||||
public string State { get; private set; } |
public string State { get; private set; } |
||||
|
|
||||
public string Country { get; private set; } |
public string Country { get; private set; } |
||||
|
|
||||
public string ZipCode { get; private set; } |
public string ZipCode { get; private set; } |
||||
|
|
||||
private Address() { } |
private Address() { } |
||||
|
|
||||
public Address(string street, string city, string state, string country, string zipcode) |
public Address(string street, string city, string state, string country, string zipcode) |
||||
{ |
{ |
||||
Street = street; |
Street = street; |
||||
City = city; |
City = city; |
||||
State = state; |
State = state; |
||||
Country = country; |
Country = country; |
||||
ZipCode = zipcode; |
ZipCode = zipcode; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,31 +1,30 @@ |
|||||
using Ardalis.GuardClauses; |
using Ardalis.GuardClauses; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents a snapshot of the item that was ordered. If catalog item details change, details of
|
||||
|
/// the item that was part of a completed order should not change.
|
||||
|
/// </summary>
|
||||
|
public class CatalogItemOrdered // ValueObject
|
||||
{ |
{ |
||||
/// <summary>
|
public CatalogItemOrdered(int catalogItemId, string productName, string pictureUri) |
||||
/// Represents a snapshot of the item that was ordered. If catalog item details change, details of
|
|
||||
/// the item that was part of a completed order should not change.
|
|
||||
/// </summary>
|
|
||||
public class CatalogItemOrdered // ValueObject
|
|
||||
{ |
{ |
||||
public CatalogItemOrdered(int catalogItemId, string productName, string pictureUri) |
Guard.Against.OutOfRange(catalogItemId, nameof(catalogItemId), 1, int.MaxValue); |
||||
{ |
Guard.Against.NullOrEmpty(productName, nameof(productName)); |
||||
Guard.Against.OutOfRange(catalogItemId, nameof(catalogItemId), 1, int.MaxValue); |
Guard.Against.NullOrEmpty(pictureUri, nameof(pictureUri)); |
||||
Guard.Against.NullOrEmpty(productName, nameof(productName)); |
|
||||
Guard.Against.NullOrEmpty(pictureUri, nameof(pictureUri)); |
|
||||
|
|
||||
CatalogItemId = catalogItemId; |
|
||||
ProductName = productName; |
|
||||
PictureUri = pictureUri; |
|
||||
} |
|
||||
|
|
||||
private CatalogItemOrdered() |
CatalogItemId = catalogItemId; |
||||
{ |
ProductName = productName; |
||||
// required by EF
|
PictureUri = pictureUri; |
||||
} |
} |
||||
|
|
||||
public int CatalogItemId { get; private set; } |
private CatalogItemOrdered() |
||||
public string ProductName { get; private set; } |
{ |
||||
public string PictureUri { get; private set; } |
// required by EF
|
||||
} |
} |
||||
|
|
||||
|
public int CatalogItemId { get; private set; } |
||||
|
public string ProductName { get; private set; } |
||||
|
public string PictureUri { get; private set; } |
||||
} |
} |
||||
|
|||||
@ -1,52 +1,51 @@ |
|||||
using Ardalis.GuardClauses; |
using System; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
using Ardalis.GuardClauses; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate |
public class Order : BaseEntity, IAggregateRoot |
||||
{ |
{ |
||||
public class Order : BaseEntity, IAggregateRoot |
private Order() |
||||
{ |
{ |
||||
private Order() |
// required by EF
|
||||
{ |
} |
||||
// required by EF
|
|
||||
} |
|
||||
|
|
||||
public Order(string buyerId, Address shipToAddress, List<OrderItem> items) |
public Order(string buyerId, Address shipToAddress, List<OrderItem> items) |
||||
{ |
{ |
||||
Guard.Against.NullOrEmpty(buyerId, nameof(buyerId)); |
Guard.Against.NullOrEmpty(buyerId, nameof(buyerId)); |
||||
Guard.Against.Null(shipToAddress, nameof(shipToAddress)); |
Guard.Against.Null(shipToAddress, nameof(shipToAddress)); |
||||
Guard.Against.Null(items, nameof(items)); |
Guard.Against.Null(items, nameof(items)); |
||||
|
|
||||
BuyerId = buyerId; |
BuyerId = buyerId; |
||||
ShipToAddress = shipToAddress; |
ShipToAddress = shipToAddress; |
||||
_orderItems = items; |
_orderItems = items; |
||||
} |
} |
||||
|
|
||||
public string BuyerId { get; private set; } |
public string BuyerId { get; private set; } |
||||
public DateTimeOffset OrderDate { get; private set; } = DateTimeOffset.Now; |
public DateTimeOffset OrderDate { get; private set; } = DateTimeOffset.Now; |
||||
public Address ShipToAddress { get; private set; } |
public Address ShipToAddress { get; private set; } |
||||
|
|
||||
// DDD Patterns comment
|
// DDD Patterns comment
|
||||
// Using a private collection field, better for DDD Aggregate's encapsulation
|
// Using a private collection field, better for DDD Aggregate's encapsulation
|
||||
// so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection,
|
// so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection,
|
||||
// but only through the method Order.AddOrderItem() which includes behavior.
|
// but only through the method Order.AddOrderItem() which includes behavior.
|
||||
private readonly List<OrderItem> _orderItems = new List<OrderItem>(); |
private readonly List<OrderItem> _orderItems = new List<OrderItem>(); |
||||
|
|
||||
// Using List<>.AsReadOnly()
|
// Using List<>.AsReadOnly()
|
||||
// This will create a read only wrapper around the private list so is protected against "external updates".
|
// This will create a read only wrapper around the private list so is protected against "external updates".
|
||||
// It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance)
|
// It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance)
|
||||
//https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx
|
//https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx
|
||||
public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly(); |
public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly(); |
||||
|
|
||||
public decimal Total() |
public decimal Total() |
||||
|
{ |
||||
|
var total = 0m; |
||||
|
foreach (var item in _orderItems) |
||||
{ |
{ |
||||
var total = 0m; |
total += item.UnitPrice * item.Units; |
||||
foreach (var item in _orderItems) |
|
||||
{ |
|
||||
total += item.UnitPrice * item.Units; |
|
||||
} |
|
||||
return total; |
|
||||
} |
} |
||||
|
return total; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,21 +1,20 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate |
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
|
public class OrderItem : BaseEntity |
||||
{ |
{ |
||||
public class OrderItem : BaseEntity |
public CatalogItemOrdered ItemOrdered { get; private set; } |
||||
{ |
public decimal UnitPrice { get; private set; } |
||||
public CatalogItemOrdered ItemOrdered { get; private set; } |
public int Units { get; private set; } |
||||
public decimal UnitPrice { get; private set; } |
|
||||
public int Units { get; private set; } |
|
||||
|
|
||||
private OrderItem() |
private OrderItem() |
||||
{ |
{ |
||||
// required by EF
|
// required by EF
|
||||
} |
} |
||||
|
|
||||
public OrderItem(CatalogItemOrdered itemOrdered, decimal unitPrice, int units) |
public OrderItem(CatalogItemOrdered itemOrdered, decimal unitPrice, int units) |
||||
{ |
{ |
||||
ItemOrdered = itemOrdered; |
ItemOrdered = itemOrdered; |
||||
UnitPrice = unitPrice; |
UnitPrice = unitPrice; |
||||
Units = units; |
Units = units; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,11 +1,10 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions |
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions; |
||||
|
|
||||
|
public class BasketNotFoundException : Exception |
||||
{ |
{ |
||||
public class BasketNotFoundException : Exception |
public BasketNotFoundException(int basketId) : base($"No basket found with id {basketId}") |
||||
{ |
{ |
||||
public BasketNotFoundException(int basketId) : base($"No basket found with id {basketId}") |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,14 +1,12 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions |
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions; |
||||
{ |
|
||||
|
|
||||
public class DuplicateException : Exception |
public class DuplicateException : Exception |
||||
|
{ |
||||
|
public DuplicateException(string message) : base(message) |
||||
{ |
{ |
||||
public DuplicateException(string message) : base(message) |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,24 +1,23 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions |
namespace Microsoft.eShopWeb.ApplicationCore.Exceptions; |
||||
|
|
||||
|
public class EmptyBasketOnCheckoutException : Exception |
||||
{ |
{ |
||||
public class EmptyBasketOnCheckoutException : Exception |
public EmptyBasketOnCheckoutException() |
||||
|
: base($"Basket cannot have 0 items on checkout") |
||||
{ |
{ |
||||
public EmptyBasketOnCheckoutException() |
} |
||||
: base($"Basket cannot have 0 items on checkout") |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected EmptyBasketOnCheckoutException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) |
protected EmptyBasketOnCheckoutException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) |
||||
{ |
{ |
||||
} |
} |
||||
|
|
||||
public EmptyBasketOnCheckoutException(string message) : base(message) |
public EmptyBasketOnCheckoutException(string message) : base(message) |
||||
{ |
{ |
||||
} |
} |
||||
|
|
||||
public EmptyBasketOnCheckoutException(string message, Exception innerException) : base(message, innerException) |
public EmptyBasketOnCheckoutException(string message, Exception innerException) : base(message, innerException) |
||||
{ |
{ |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,22 +1,21 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using System.Collections.Generic; |
||||
using Microsoft.eShopWeb.ApplicationCore.Exceptions; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
using System.Linq; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Exceptions; |
||||
|
|
||||
|
namespace Ardalis.GuardClauses; |
||||
|
|
||||
namespace Ardalis.GuardClauses |
public static class BasketGuards |
||||
{ |
{ |
||||
public static class BasketGuards |
public static void NullBasket(this IGuardClause guardClause, int basketId, Basket basket) |
||||
{ |
{ |
||||
public static void NullBasket(this IGuardClause guardClause, int basketId, Basket basket) |
if (basket == null) |
||||
{ |
throw new BasketNotFoundException(basketId); |
||||
if (basket == null) |
} |
||||
throw new BasketNotFoundException(basketId); |
|
||||
} |
|
||||
|
|
||||
public static void EmptyBasketOnCheckout(this IGuardClause guardClause, IReadOnlyCollection<BasketItem> basketItems) |
public static void EmptyBasketOnCheckout(this IGuardClause guardClause, IReadOnlyCollection<BasketItem> basketItems) |
||||
{ |
{ |
||||
if (!basketItems.Any()) |
if (!basketItems.Any()) |
||||
throw new EmptyBasketOnCheckoutException(); |
throw new EmptyBasketOnCheckoutException(); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,18 +1,17 @@ |
|||||
using System.Text.Json; |
using System.Text.Json; |
||||
|
|
||||
namespace Microsoft.eShopWeb |
namespace Microsoft.eShopWeb; |
||||
|
|
||||
|
public static class JsonExtensions |
||||
{ |
{ |
||||
public static class JsonExtensions |
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions |
||||
{ |
{ |
||||
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions |
PropertyNameCaseInsensitive = true |
||||
{ |
}; |
||||
PropertyNameCaseInsensitive = true |
|
||||
}; |
|
||||
|
|
||||
public static T FromJson<T>(this string json) => |
public static T FromJson<T>(this string json) => |
||||
JsonSerializer.Deserialize<T>(json, _jsonOptions); |
JsonSerializer.Deserialize<T>(json, _jsonOptions); |
||||
|
|
||||
public static string ToJson<T>(this T obj) => |
public static string ToJson<T>(this T obj) => |
||||
JsonSerializer.Serialize<T>(obj, _jsonOptions); |
JsonSerializer.Serialize<T>(obj, _jsonOptions); |
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,5 +1,4 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
{ |
|
||||
public interface IAggregateRoot |
public interface IAggregateRoot |
||||
{ } |
{ } |
||||
} |
|
||||
|
|||||
@ -1,12 +1,11 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This type eliminates the need to depend directly on the ASP.NET Core logging types.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
public interface IAppLogger<T> |
||||
{ |
{ |
||||
/// <summary>
|
void LogInformation(string message, params object[] args); |
||||
/// This type eliminates the need to depend directly on the ASP.NET Core logging types.
|
void LogWarning(string message, params object[] args); |
||||
/// </summary>
|
|
||||
/// <typeparam name="T"></typeparam>
|
|
||||
public interface IAppLogger<T> |
|
||||
{ |
|
||||
void LogInformation(string message, params object[] args); |
|
||||
void LogWarning(string message, params object[] args); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IBasketQueryService |
||||
{ |
{ |
||||
public interface IBasketQueryService |
Task<int> CountTotalBasketItems(string username); |
||||
{ |
|
||||
Task<int> CountTotalBasketItems(string username); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,14 +1,13 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IBasketService |
||||
{ |
{ |
||||
public interface IBasketService |
Task TransferBasketAsync(string anonymousId, string userName); |
||||
{ |
Task<Basket> AddItemToBasket(string username, int catalogItemId, decimal price, int quantity = 1); |
||||
Task TransferBasketAsync(string anonymousId, string userName); |
Task<Basket> SetQuantities(int basketId, Dictionary<string, int> quantities); |
||||
Task<Basket> AddItemToBasket(string username, int catalogItemId, decimal price, int quantity = 1); |
Task DeleteBasketAsync(int basketId); |
||||
Task<Basket> SetQuantities(int basketId, Dictionary<string, int> quantities); |
|
||||
Task DeleteBasketAsync(int basketId); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,10 +1,8 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
{ |
|
||||
|
|
||||
public interface IEmailSender |
public interface IEmailSender |
||||
{ |
{ |
||||
Task SendEmailAsync(string email, string subject, string message); |
Task SendEmailAsync(string email, string subject, string message); |
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,10 +1,9 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
using System.Threading.Tasks; |
||||
using System.Threading.Tasks; |
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IOrderService |
||||
{ |
{ |
||||
public interface IOrderService |
Task CreateOrderAsync(int basketId, Address shippingAddress); |
||||
{ |
|
||||
Task CreateOrderAsync(int basketId, Address shippingAddress); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,8 +1,7 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IReadRepository<T> : IReadRepositoryBase<T> where T : class, IAggregateRoot |
||||
{ |
{ |
||||
public interface IReadRepository<T> : IReadRepositoryBase<T> where T : class, IAggregateRoot |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,8 +1,7 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IRepository<T> : IRepositoryBase<T> where T : class, IAggregateRoot |
||||
{ |
{ |
||||
public interface IRepository<T> : IRepositoryBase<T> where T : class, IAggregateRoot |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface ITokenClaimsService |
||||
{ |
{ |
||||
public interface ITokenClaimsService |
Task<string> GetTokenAsync(string userName); |
||||
{ |
|
||||
Task<string> GetTokenAsync(string userName); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,7 +1,6 @@ |
|||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces |
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
|
public interface IUriComposer |
||||
{ |
{ |
||||
public interface IUriComposer |
string ComposePicUri(string uriTemplate); |
||||
{ |
|
||||
string ComposePicUri(string uriTemplate); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,87 +1,86 @@ |
|||||
using Ardalis.GuardClauses; |
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Ardalis.GuardClauses; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications; |
using Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Services |
namespace Microsoft.eShopWeb.ApplicationCore.Services; |
||||
|
|
||||
|
public class BasketService : IBasketService |
||||
{ |
{ |
||||
public class BasketService : IBasketService |
private readonly IRepository<Basket> _basketRepository; |
||||
|
private readonly IAppLogger<BasketService> _logger; |
||||
|
|
||||
|
public BasketService(IRepository<Basket> basketRepository, |
||||
|
IAppLogger<BasketService> logger) |
||||
{ |
{ |
||||
private readonly IRepository<Basket> _basketRepository; |
_basketRepository = basketRepository; |
||||
private readonly IAppLogger<BasketService> _logger; |
_logger = logger; |
||||
|
} |
||||
|
|
||||
public BasketService(IRepository<Basket> basketRepository, |
public async Task<Basket> AddItemToBasket(string username, int catalogItemId, decimal price, int quantity = 1) |
||||
IAppLogger<BasketService> logger) |
{ |
||||
{ |
var basketSpec = new BasketWithItemsSpecification(username); |
||||
_basketRepository = basketRepository; |
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
||||
_logger = logger; |
|
||||
} |
|
||||
|
|
||||
public async Task<Basket> AddItemToBasket(string username, int catalogItemId, decimal price, int quantity = 1) |
if (basket == null) |
||||
{ |
{ |
||||
var basketSpec = new BasketWithItemsSpecification(username); |
basket = new Basket(username); |
||||
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
await _basketRepository.AddAsync(basket); |
||||
|
} |
||||
|
|
||||
if (basket == null) |
basket.AddItem(catalogItemId, price, quantity); |
||||
{ |
|
||||
basket = new Basket(username); |
|
||||
await _basketRepository.AddAsync(basket); |
|
||||
} |
|
||||
|
|
||||
basket.AddItem(catalogItemId, price, quantity); |
await _basketRepository.UpdateAsync(basket); |
||||
|
return basket; |
||||
|
} |
||||
|
|
||||
await _basketRepository.UpdateAsync(basket); |
public async Task DeleteBasketAsync(int basketId) |
||||
return basket; |
{ |
||||
} |
var basket = await _basketRepository.GetByIdAsync(basketId); |
||||
|
await _basketRepository.DeleteAsync(basket); |
||||
|
} |
||||
|
|
||||
public async Task DeleteBasketAsync(int basketId) |
public async Task<Basket> SetQuantities(int basketId, Dictionary<string, int> quantities) |
||||
{ |
{ |
||||
var basket = await _basketRepository.GetByIdAsync(basketId); |
Guard.Against.Null(quantities, nameof(quantities)); |
||||
await _basketRepository.DeleteAsync(basket); |
var basketSpec = new BasketWithItemsSpecification(basketId); |
||||
} |
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
||||
|
Guard.Against.NullBasket(basketId, basket); |
||||
|
|
||||
public async Task<Basket> SetQuantities(int basketId, Dictionary<string, int> quantities) |
foreach (var item in basket.Items) |
||||
{ |
{ |
||||
Guard.Against.Null(quantities, nameof(quantities)); |
if (quantities.TryGetValue(item.Id.ToString(), out var quantity)) |
||||
var basketSpec = new BasketWithItemsSpecification(basketId); |
|
||||
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
|
||||
Guard.Against.NullBasket(basketId, basket); |
|
||||
|
|
||||
foreach (var item in basket.Items) |
|
||||
{ |
{ |
||||
if (quantities.TryGetValue(item.Id.ToString(), out var quantity)) |
if (_logger != null) _logger.LogInformation($"Updating quantity of item ID:{item.Id} to {quantity}."); |
||||
{ |
item.SetQuantity(quantity); |
||||
if (_logger != null) _logger.LogInformation($"Updating quantity of item ID:{item.Id} to {quantity}."); |
|
||||
item.SetQuantity(quantity); |
|
||||
} |
|
||||
} |
} |
||||
basket.RemoveEmptyItems(); |
|
||||
await _basketRepository.UpdateAsync(basket); |
|
||||
return basket; |
|
||||
} |
} |
||||
|
basket.RemoveEmptyItems(); |
||||
|
await _basketRepository.UpdateAsync(basket); |
||||
|
return basket; |
||||
|
} |
||||
|
|
||||
public async Task TransferBasketAsync(string anonymousId, string userName) |
public async Task TransferBasketAsync(string anonymousId, string userName) |
||||
|
{ |
||||
|
Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId)); |
||||
|
Guard.Against.NullOrEmpty(userName, nameof(userName)); |
||||
|
var anonymousBasketSpec = new BasketWithItemsSpecification(anonymousId); |
||||
|
var anonymousBasket = await _basketRepository.GetBySpecAsync(anonymousBasketSpec); |
||||
|
if (anonymousBasket == null) return; |
||||
|
var userBasketSpec = new BasketWithItemsSpecification(userName); |
||||
|
var userBasket = await _basketRepository.GetBySpecAsync(userBasketSpec); |
||||
|
if (userBasket == null) |
||||
{ |
{ |
||||
Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId)); |
userBasket = new Basket(userName); |
||||
Guard.Against.NullOrEmpty(userName, nameof(userName)); |
await _basketRepository.AddAsync(userBasket); |
||||
var anonymousBasketSpec = new BasketWithItemsSpecification(anonymousId); |
} |
||||
var anonymousBasket = await _basketRepository.GetBySpecAsync(anonymousBasketSpec); |
foreach (var item in anonymousBasket.Items) |
||||
if (anonymousBasket == null) return; |
{ |
||||
var userBasketSpec = new BasketWithItemsSpecification(userName); |
userBasket.AddItem(item.CatalogItemId, item.UnitPrice, item.Quantity); |
||||
var userBasket = await _basketRepository.GetBySpecAsync(userBasketSpec); |
|
||||
if (userBasket == null) |
|
||||
{ |
|
||||
userBasket = new Basket(userName); |
|
||||
await _basketRepository.AddAsync(userBasket); |
|
||||
} |
|
||||
foreach (var item in anonymousBasket.Items) |
|
||||
{ |
|
||||
userBasket.AddItem(item.CatalogItemId, item.UnitPrice, item.Quantity); |
|
||||
} |
|
||||
await _basketRepository.UpdateAsync(userBasket); |
|
||||
await _basketRepository.DeleteAsync(anonymousBasket); |
|
||||
} |
} |
||||
|
await _basketRepository.UpdateAsync(userBasket); |
||||
|
await _basketRepository.DeleteAsync(anonymousBasket); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,54 +1,53 @@ |
|||||
using Ardalis.GuardClauses; |
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Ardalis.GuardClauses; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications; |
using Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Services |
namespace Microsoft.eShopWeb.ApplicationCore.Services; |
||||
|
|
||||
|
public class OrderService : IOrderService |
||||
{ |
{ |
||||
public class OrderService : IOrderService |
private readonly IRepository<Order> _orderRepository; |
||||
|
private readonly IUriComposer _uriComposer; |
||||
|
private readonly IRepository<Basket> _basketRepository; |
||||
|
private readonly IRepository<CatalogItem> _itemRepository; |
||||
|
|
||||
|
public OrderService(IRepository<Basket> basketRepository, |
||||
|
IRepository<CatalogItem> itemRepository, |
||||
|
IRepository<Order> orderRepository, |
||||
|
IUriComposer uriComposer) |
||||
{ |
{ |
||||
private readonly IRepository<Order> _orderRepository; |
_orderRepository = orderRepository; |
||||
private readonly IUriComposer _uriComposer; |
_uriComposer = uriComposer; |
||||
private readonly IRepository<Basket> _basketRepository; |
_basketRepository = basketRepository; |
||||
private readonly IRepository<CatalogItem> _itemRepository; |
_itemRepository = itemRepository; |
||||
|
} |
||||
public OrderService(IRepository<Basket> basketRepository, |
|
||||
IRepository<CatalogItem> itemRepository, |
|
||||
IRepository<Order> orderRepository, |
|
||||
IUriComposer uriComposer) |
|
||||
{ |
|
||||
_orderRepository = orderRepository; |
|
||||
_uriComposer = uriComposer; |
|
||||
_basketRepository = basketRepository; |
|
||||
_itemRepository = itemRepository; |
|
||||
} |
|
||||
|
|
||||
public async Task CreateOrderAsync(int basketId, Address shippingAddress) |
public async Task CreateOrderAsync(int basketId, Address shippingAddress) |
||||
{ |
{ |
||||
var basketSpec = new BasketWithItemsSpecification(basketId); |
var basketSpec = new BasketWithItemsSpecification(basketId); |
||||
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
var basket = await _basketRepository.GetBySpecAsync(basketSpec); |
||||
|
|
||||
Guard.Against.NullBasket(basketId, basket); |
Guard.Against.NullBasket(basketId, basket); |
||||
Guard.Against.EmptyBasketOnCheckout(basket.Items); |
Guard.Against.EmptyBasketOnCheckout(basket.Items); |
||||
|
|
||||
var catalogItemsSpecification = new CatalogItemsSpecification(basket.Items.Select(item => item.CatalogItemId).ToArray()); |
var catalogItemsSpecification = new CatalogItemsSpecification(basket.Items.Select(item => item.CatalogItemId).ToArray()); |
||||
var catalogItems = await _itemRepository.ListAsync(catalogItemsSpecification); |
var catalogItems = await _itemRepository.ListAsync(catalogItemsSpecification); |
||||
|
|
||||
var items = basket.Items.Select(basketItem => |
var items = basket.Items.Select(basketItem => |
||||
{ |
{ |
||||
var catalogItem = catalogItems.First(c => c.Id == basketItem.CatalogItemId); |
var catalogItem = catalogItems.First(c => c.Id == basketItem.CatalogItemId); |
||||
var itemOrdered = new CatalogItemOrdered(catalogItem.Id, catalogItem.Name, _uriComposer.ComposePicUri(catalogItem.PictureUri)); |
var itemOrdered = new CatalogItemOrdered(catalogItem.Id, catalogItem.Name, _uriComposer.ComposePicUri(catalogItem.PictureUri)); |
||||
var orderItem = new OrderItem(itemOrdered, basketItem.UnitPrice, basketItem.Quantity); |
var orderItem = new OrderItem(itemOrdered, basketItem.UnitPrice, basketItem.Quantity); |
||||
return orderItem; |
return orderItem; |
||||
}).ToList(); |
}).ToList(); |
||||
|
|
||||
var order = new Order(basket.BuyerId, shippingAddress, items); |
var order = new Order(basket.BuyerId, shippingAddress, items); |
||||
|
|
||||
await _orderRepository.AddAsync(order); |
await _orderRepository.AddAsync(order); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,16 +1,15 @@ |
|||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Services |
namespace Microsoft.eShopWeb.ApplicationCore.Services; |
||||
|
|
||||
|
public class UriComposer : IUriComposer |
||||
{ |
{ |
||||
public class UriComposer : IUriComposer |
private readonly CatalogSettings _catalogSettings; |
||||
{ |
|
||||
private readonly CatalogSettings _catalogSettings; |
|
||||
|
|
||||
public UriComposer(CatalogSettings catalogSettings) => _catalogSettings = catalogSettings; |
public UriComposer(CatalogSettings catalogSettings) => _catalogSettings = catalogSettings; |
||||
|
|
||||
public string ComposePicUri(string uriTemplate) |
public string ComposePicUri(string uriTemplate) |
||||
{ |
{ |
||||
return uriTemplate.Replace("http://catalogbaseurltobereplaced", _catalogSettings.CatalogBaseUrl); |
return uriTemplate.Replace("http://catalogbaseurltobereplaced", _catalogSettings.CatalogBaseUrl); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,22 +1,21 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public sealed class BasketWithItemsSpecification : Specification<Basket>, ISingleResultSpecification |
||||
{ |
{ |
||||
public sealed class BasketWithItemsSpecification : Specification<Basket>, ISingleResultSpecification |
public BasketWithItemsSpecification(int basketId) |
||||
{ |
{ |
||||
public BasketWithItemsSpecification(int basketId) |
Query |
||||
{ |
.Where(b => b.Id == basketId) |
||||
Query |
.Include(b => b.Items); |
||||
.Where(b => b.Id == basketId) |
} |
||||
.Include(b => b.Items); |
|
||||
} |
|
||||
|
|
||||
public BasketWithItemsSpecification(string buyerId) |
public BasketWithItemsSpecification(string buyerId) |
||||
{ |
{ |
||||
Query |
Query |
||||
.Where(b => b.BuyerId == buyerId) |
.Where(b => b.BuyerId == buyerId) |
||||
.Include(b => b.Items); |
.Include(b => b.Items); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,21 +1,20 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public class CatalogFilterPaginatedSpecification : Specification<CatalogItem> |
||||
{ |
{ |
||||
public class CatalogFilterPaginatedSpecification : Specification<CatalogItem> |
public CatalogFilterPaginatedSpecification(int skip, int take, int? brandId, int? typeId) |
||||
|
: base() |
||||
{ |
{ |
||||
public CatalogFilterPaginatedSpecification(int skip, int take, int? brandId, int? typeId) |
if (take == 0) |
||||
: base() |
|
||||
{ |
{ |
||||
if (take == 0) |
take = int.MaxValue; |
||||
{ |
|
||||
take = int.MaxValue; |
|
||||
} |
|
||||
Query |
|
||||
.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) && |
|
||||
(!typeId.HasValue || i.CatalogTypeId == typeId)) |
|
||||
.Skip(skip).Take(take); |
|
||||
} |
} |
||||
|
Query |
||||
|
.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) && |
||||
|
(!typeId.HasValue || i.CatalogTypeId == typeId)) |
||||
|
.Skip(skip).Take(take); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,14 +1,13 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public class CatalogFilterSpecification : Specification<CatalogItem> |
||||
{ |
{ |
||||
public class CatalogFilterSpecification : Specification<CatalogItem> |
public CatalogFilterSpecification(int? brandId, int? typeId) |
||||
{ |
{ |
||||
public CatalogFilterSpecification(int? brandId, int? typeId) |
Query.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) && |
||||
{ |
(!typeId.HasValue || i.CatalogTypeId == typeId)); |
||||
Query.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) && |
|
||||
(!typeId.HasValue || i.CatalogTypeId == typeId)); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,13 +1,12 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public class CatalogItemNameSpecification : Specification<CatalogItem> |
||||
{ |
{ |
||||
public class CatalogItemNameSpecification : Specification<CatalogItem> |
public CatalogItemNameSpecification(string catalogItemName) |
||||
{ |
{ |
||||
public CatalogItemNameSpecification(string catalogItemName) |
Query.Where(item => catalogItemName == item.Name); |
||||
{ |
|
||||
Query.Where(item => catalogItemName == item.Name); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,15 +1,14 @@ |
|||||
using Ardalis.Specification; |
using System; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|
||||
using System; |
|
||||
using System.Linq; |
using System.Linq; |
||||
|
using Ardalis.Specification; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
|
|
||||
|
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
public class CatalogItemsSpecification : Specification<CatalogItem> |
||||
{ |
{ |
||||
public class CatalogItemsSpecification : Specification<CatalogItem> |
public CatalogItemsSpecification(params int[] ids) |
||||
{ |
{ |
||||
public CatalogItemsSpecification(params int[] ids) |
Query.Where(c => ids.Contains(c.Id)); |
||||
{ |
|
||||
Query.Where(c => ids.Contains(c.Id)); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,15 +1,14 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public class CustomerOrdersWithItemsSpecification : Specification<Order> |
||||
{ |
{ |
||||
public class CustomerOrdersWithItemsSpecification : Specification<Order> |
public CustomerOrdersWithItemsSpecification(string buyerId) |
||||
{ |
{ |
||||
public CustomerOrdersWithItemsSpecification(string buyerId) |
Query.Where(o => o.BuyerId == buyerId) |
||||
{ |
.Include(o => o.OrderItems) |
||||
Query.Where(o => o.BuyerId == buyerId) |
.ThenInclude(i => i.ItemOrdered); |
||||
.Include(o => o.OrderItems) |
|
||||
.ThenInclude(i => i.ItemOrdered); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,16 +1,15 @@ |
|||||
using Ardalis.Specification; |
using Ardalis.Specification; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
|
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications |
namespace Microsoft.eShopWeb.ApplicationCore.Specifications; |
||||
|
|
||||
|
public class OrderWithItemsByIdSpec : Specification<Order>, ISingleResultSpecification |
||||
{ |
{ |
||||
public class OrderWithItemsByIdSpec : Specification<Order>, ISingleResultSpecification |
public OrderWithItemsByIdSpec(int orderId) |
||||
{ |
{ |
||||
public OrderWithItemsByIdSpec(int orderId) |
Query |
||||
{ |
.Where(order => order.Id == orderId) |
||||
Query |
.Include(o => o.OrderItems) |
||||
.Where(order => order.Id == orderId) |
.ThenInclude(i => i.ItemOrdered); |
||||
.Include(o => o.OrderItems) |
|
||||
.ThenInclude(i => i.ItemOrdered); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,87 +1,86 @@ |
|||||
using BlazorShared.Authorization; |
using System; |
||||
using Microsoft.AspNetCore.Components.Authorization; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using System; |
|
||||
using System.Net.Http; |
using System.Net.Http; |
||||
using System.Net.Http.Headers; |
using System.Net.Http.Headers; |
||||
using System.Net.Http.Json; |
using System.Net.Http.Json; |
||||
using System.Security.Claims; |
using System.Security.Claims; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared.Authorization; |
||||
|
using Microsoft.AspNetCore.Components.Authorization; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace BlazorAdmin; |
||||
|
|
||||
namespace BlazorAdmin |
public class CustomAuthStateProvider : AuthenticationStateProvider |
||||
{ |
{ |
||||
public class CustomAuthStateProvider : AuthenticationStateProvider |
// TODO: Get Default Cache Duration from Config
|
||||
{ |
private static readonly TimeSpan UserCacheRefreshInterval = TimeSpan.FromSeconds(60); |
||||
// TODO: Get Default Cache Duration from Config
|
|
||||
private static readonly TimeSpan UserCacheRefreshInterval = TimeSpan.FromSeconds(60); |
|
||||
|
|
||||
private readonly HttpClient _httpClient; |
private readonly HttpClient _httpClient; |
||||
private readonly ILogger<CustomAuthStateProvider> _logger; |
private readonly ILogger<CustomAuthStateProvider> _logger; |
||||
|
|
||||
private DateTimeOffset _userLastCheck = DateTimeOffset.FromUnixTimeSeconds(0); |
private DateTimeOffset _userLastCheck = DateTimeOffset.FromUnixTimeSeconds(0); |
||||
private ClaimsPrincipal _cachedUser = new ClaimsPrincipal(new ClaimsIdentity()); |
private ClaimsPrincipal _cachedUser = new ClaimsPrincipal(new ClaimsIdentity()); |
||||
|
|
||||
public CustomAuthStateProvider(HttpClient httpClient, |
public CustomAuthStateProvider(HttpClient httpClient, |
||||
ILogger<CustomAuthStateProvider> logger) |
ILogger<CustomAuthStateProvider> logger) |
||||
{ |
{ |
||||
_httpClient = httpClient; |
_httpClient = httpClient; |
||||
_logger = logger; |
_logger = logger; |
||||
} |
} |
||||
|
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync() |
public override async Task<AuthenticationState> GetAuthenticationStateAsync() |
||||
|
{ |
||||
|
return new AuthenticationState(await GetUser(useCache: true)); |
||||
|
} |
||||
|
|
||||
|
private async ValueTask<ClaimsPrincipal> GetUser(bool useCache = false) |
||||
|
{ |
||||
|
var now = DateTimeOffset.Now; |
||||
|
if (useCache && now < _userLastCheck + UserCacheRefreshInterval) |
||||
{ |
{ |
||||
return new AuthenticationState(await GetUser(useCache: true)); |
return _cachedUser; |
||||
} |
} |
||||
|
|
||||
private async ValueTask<ClaimsPrincipal> GetUser(bool useCache = false) |
_cachedUser = await FetchUser(); |
||||
{ |
_userLastCheck = now; |
||||
var now = DateTimeOffset.Now; |
|
||||
if (useCache && now < _userLastCheck + UserCacheRefreshInterval) |
|
||||
{ |
|
||||
return _cachedUser; |
|
||||
} |
|
||||
|
|
||||
_cachedUser = await FetchUser(); |
return _cachedUser; |
||||
_userLastCheck = now; |
} |
||||
|
|
||||
return _cachedUser; |
private async Task<ClaimsPrincipal> FetchUser() |
||||
} |
{ |
||||
|
UserInfo user = null; |
||||
|
|
||||
private async Task<ClaimsPrincipal> FetchUser() |
try |
||||
{ |
{ |
||||
UserInfo user = null; |
_logger.LogInformation("Fetching user details from web api."); |
||||
|
user = await _httpClient.GetFromJsonAsync<UserInfo>("User"); |
||||
try |
} |
||||
{ |
catch (Exception exc) |
||||
_logger.LogInformation("Fetching user details from web api."); |
{ |
||||
user = await _httpClient.GetFromJsonAsync<UserInfo>("User"); |
_logger.LogWarning(exc, "Fetching user failed."); |
||||
} |
} |
||||
catch (Exception exc) |
|
||||
{ |
|
||||
_logger.LogWarning(exc, "Fetching user failed."); |
|
||||
} |
|
||||
|
|
||||
if (user == null || !user.IsAuthenticated) |
if (user == null || !user.IsAuthenticated) |
||||
{ |
{ |
||||
return null; |
return null; |
||||
} |
} |
||||
|
|
||||
var identity = new ClaimsIdentity( |
var identity = new ClaimsIdentity( |
||||
nameof(CustomAuthStateProvider), |
nameof(CustomAuthStateProvider), |
||||
user.NameClaimType, |
user.NameClaimType, |
||||
user.RoleClaimType); |
user.RoleClaimType); |
||||
|
|
||||
if (user.Claims != null) |
if (user.Claims != null) |
||||
|
{ |
||||
|
foreach (var claim in user.Claims) |
||||
{ |
{ |
||||
foreach (var claim in user.Claims) |
identity.AddClaim(new Claim(claim.Type, claim.Value)); |
||||
{ |
|
||||
identity.AddClaim(new Claim(claim.Type, claim.Value)); |
|
||||
} |
|
||||
} |
} |
||||
|
} |
||||
|
|
||||
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", user.Token); |
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", user.Token); |
||||
|
|
||||
return new ClaimsPrincipal(identity); |
return new ClaimsPrincipal(identity); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,26 +1,25 @@ |
|||||
using Microsoft.AspNetCore.Components; |
using Microsoft.AspNetCore.Components; |
||||
|
|
||||
namespace BlazorAdmin.Helpers |
namespace BlazorAdmin.Helpers; |
||||
{ |
|
||||
public class BlazorComponent : ComponentBase |
|
||||
{ |
|
||||
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; |
|
||||
|
|
||||
protected override void OnInitialized() |
public class BlazorComponent : ComponentBase |
||||
{ |
{ |
||||
_refresh.RefreshRequested += DoRefresh; |
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; |
||||
base.OnInitialized(); |
|
||||
} |
|
||||
|
|
||||
public void CallRequestRefresh() |
protected override void OnInitialized() |
||||
{ |
{ |
||||
_refresh.CallRequestRefresh(); |
_refresh.RefreshRequested += DoRefresh; |
||||
} |
base.OnInitialized(); |
||||
|
} |
||||
|
|
||||
private void DoRefresh() |
public void CallRequestRefresh() |
||||
{ |
{ |
||||
StateHasChanged(); |
_refresh.CallRequestRefresh(); |
||||
} |
} |
||||
|
|
||||
|
private void DoRefresh() |
||||
|
{ |
||||
|
StateHasChanged(); |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,25 +1,24 @@ |
|||||
using Microsoft.AspNetCore.Components; |
using Microsoft.AspNetCore.Components; |
||||
|
|
||||
namespace BlazorAdmin.Helpers |
namespace BlazorAdmin.Helpers; |
||||
|
|
||||
|
public class BlazorLayoutComponent : LayoutComponentBase |
||||
{ |
{ |
||||
public class BlazorLayoutComponent : LayoutComponentBase |
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; |
||||
{ |
|
||||
private readonly RefreshBroadcast _refresh = RefreshBroadcast.Instance; |
|
||||
|
|
||||
protected override void OnInitialized() |
protected override void OnInitialized() |
||||
{ |
{ |
||||
_refresh.RefreshRequested += DoRefresh; |
_refresh.RefreshRequested += DoRefresh; |
||||
base.OnInitialized(); |
base.OnInitialized(); |
||||
} |
} |
||||
|
|
||||
public void CallRequestRefresh() |
public void CallRequestRefresh() |
||||
{ |
{ |
||||
_refresh.CallRequestRefresh(); |
_refresh.CallRequestRefresh(); |
||||
} |
} |
||||
|
|
||||
private void DoRefresh() |
private void DoRefresh() |
||||
{ |
{ |
||||
StateHasChanged(); |
StateHasChanged(); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,24 +1,23 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace BlazorAdmin.Helpers |
namespace BlazorAdmin.Helpers; |
||||
|
|
||||
|
internal sealed class RefreshBroadcast |
||||
{ |
{ |
||||
internal sealed class RefreshBroadcast |
private static readonly Lazy<RefreshBroadcast> |
||||
{ |
Lazy = |
||||
private static readonly Lazy<RefreshBroadcast> |
new Lazy<RefreshBroadcast> |
||||
Lazy = |
(() => new RefreshBroadcast()); |
||||
new Lazy<RefreshBroadcast> |
|
||||
(() => new RefreshBroadcast()); |
|
||||
|
|
||||
public static RefreshBroadcast Instance => Lazy.Value; |
public static RefreshBroadcast Instance => Lazy.Value; |
||||
|
|
||||
private RefreshBroadcast() |
private RefreshBroadcast() |
||||
{ |
{ |
||||
} |
} |
||||
|
|
||||
public event Action RefreshRequested; |
public event Action RefreshRequested; |
||||
public void CallRequestRefresh() |
public void CallRequestRefresh() |
||||
{ |
{ |
||||
RefreshRequested?.Invoke(); |
RefreshRequested?.Invoke(); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,88 +1,87 @@ |
|||||
using BlazorAdmin.Services; |
using System; |
||||
|
using BlazorAdmin.Services; |
||||
using Microsoft.AspNetCore.Components; |
using Microsoft.AspNetCore.Components; |
||||
using System; |
|
||||
|
|
||||
namespace BlazorAdmin.Helpers |
namespace BlazorAdmin.Helpers; |
||||
|
|
||||
|
public class ToastComponent : ComponentBase, IDisposable |
||||
{ |
{ |
||||
public class ToastComponent : ComponentBase, IDisposable |
[Inject] |
||||
|
ToastService ToastService |
||||
{ |
{ |
||||
[Inject] |
get; |
||||
ToastService ToastService |
set; |
||||
{ |
} |
||||
get; |
protected string Heading |
||||
set; |
{ |
||||
} |
get; |
||||
protected string Heading |
set; |
||||
{ |
} |
||||
get; |
protected string Message |
||||
set; |
{ |
||||
} |
get; |
||||
protected string Message |
set; |
||||
{ |
} |
||||
get; |
protected bool IsVisible |
||||
set; |
{ |
||||
} |
get; |
||||
protected bool IsVisible |
set; |
||||
{ |
} |
||||
get; |
protected string BackgroundCssClass |
||||
set; |
{ |
||||
} |
get; |
||||
protected string BackgroundCssClass |
set; |
||||
{ |
} |
||||
get; |
protected string IconCssClass |
||||
set; |
{ |
||||
} |
get; |
||||
protected string IconCssClass |
set; |
||||
{ |
} |
||||
get; |
protected override void OnInitialized() |
||||
set; |
{ |
||||
} |
ToastService.OnShow += ShowToast; |
||||
protected override void OnInitialized() |
ToastService.OnHide += HideToast; |
||||
{ |
} |
||||
ToastService.OnShow += ShowToast; |
private void ShowToast(string message, ToastLevel level) |
||||
ToastService.OnHide += HideToast; |
{ |
||||
} |
BuildToastSettings(level, message); |
||||
private void ShowToast(string message, ToastLevel level) |
IsVisible = true; |
||||
{ |
StateHasChanged(); |
||||
BuildToastSettings(level, message); |
} |
||||
IsVisible = true; |
private void HideToast() |
||||
StateHasChanged(); |
{ |
||||
} |
IsVisible = false; |
||||
private void HideToast() |
StateHasChanged(); |
||||
{ |
} |
||||
IsVisible = false; |
private void BuildToastSettings(ToastLevel level, string message) |
||||
StateHasChanged(); |
{ |
||||
} |
switch (level) |
||||
private void BuildToastSettings(ToastLevel level, string message) |
|
||||
{ |
|
||||
switch (level) |
|
||||
{ |
|
||||
case ToastLevel.Info: |
|
||||
BackgroundCssClass = "bg-info"; |
|
||||
IconCssClass = "info"; |
|
||||
Heading = "Info"; |
|
||||
break; |
|
||||
case ToastLevel.Success: |
|
||||
BackgroundCssClass = "bg-success"; |
|
||||
IconCssClass = "check"; |
|
||||
Heading = "Success"; |
|
||||
break; |
|
||||
case ToastLevel.Warning: |
|
||||
BackgroundCssClass = "bg-warning"; |
|
||||
IconCssClass = "exclamation"; |
|
||||
Heading = "Warning"; |
|
||||
break; |
|
||||
case ToastLevel.Error: |
|
||||
BackgroundCssClass = "bg-danger"; |
|
||||
IconCssClass = "times"; |
|
||||
Heading = "Error"; |
|
||||
break; |
|
||||
} |
|
||||
Message = message; |
|
||||
} |
|
||||
public void Dispose() |
|
||||
{ |
{ |
||||
ToastService.OnShow -= ShowToast; |
case ToastLevel.Info: |
||||
|
BackgroundCssClass = "bg-info"; |
||||
|
IconCssClass = "info"; |
||||
|
Heading = "Info"; |
||||
|
break; |
||||
|
case ToastLevel.Success: |
||||
|
BackgroundCssClass = "bg-success"; |
||||
|
IconCssClass = "check"; |
||||
|
Heading = "Success"; |
||||
|
break; |
||||
|
case ToastLevel.Warning: |
||||
|
BackgroundCssClass = "bg-warning"; |
||||
|
IconCssClass = "exclamation"; |
||||
|
Heading = "Warning"; |
||||
|
break; |
||||
|
case ToastLevel.Error: |
||||
|
BackgroundCssClass = "bg-danger"; |
||||
|
IconCssClass = "times"; |
||||
|
Heading = "Error"; |
||||
|
break; |
||||
} |
} |
||||
|
Message = message; |
||||
|
} |
||||
|
public void Dispose() |
||||
|
{ |
||||
|
ToastService.OnShow -= ShowToast; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,25 +1,24 @@ |
|||||
using Microsoft.JSInterop; |
using System.Threading.Tasks; |
||||
using System.Threading.Tasks; |
using Microsoft.JSInterop; |
||||
|
|
||||
namespace BlazorAdmin.JavaScript |
namespace BlazorAdmin.JavaScript; |
||||
|
|
||||
|
public class Cookies |
||||
{ |
{ |
||||
public class Cookies |
private readonly IJSRuntime _jsRuntime; |
||||
{ |
|
||||
private readonly IJSRuntime _jsRuntime; |
|
||||
|
|
||||
public Cookies(IJSRuntime jsRuntime) |
public Cookies(IJSRuntime jsRuntime) |
||||
{ |
{ |
||||
_jsRuntime = jsRuntime; |
_jsRuntime = jsRuntime; |
||||
} |
} |
||||
|
|
||||
public async Task DeleteCookie(string name) |
public async Task DeleteCookie(string name) |
||||
{ |
{ |
||||
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.DeleteCookie, name); |
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.DeleteCookie, name); |
||||
} |
} |
||||
|
|
||||
public async Task<string> GetCookie(string name) |
public async Task<string> GetCookie(string name) |
||||
{ |
{ |
||||
return await _jsRuntime.InvokeAsync<string>(JSInteropConstants.GetCookie, name); |
return await _jsRuntime.InvokeAsync<string>(JSInteropConstants.GetCookie, name); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,25 +1,24 @@ |
|||||
using Microsoft.JSInterop; |
using System.Threading.Tasks; |
||||
using System.Threading.Tasks; |
using Microsoft.JSInterop; |
||||
|
|
||||
namespace BlazorAdmin.JavaScript |
namespace BlazorAdmin.JavaScript; |
||||
|
|
||||
|
public class Css |
||||
{ |
{ |
||||
public class Css |
private readonly IJSRuntime _jsRuntime; |
||||
|
|
||||
|
public Css(IJSRuntime jsRuntime) |
||||
{ |
{ |
||||
private readonly IJSRuntime _jsRuntime; |
_jsRuntime = jsRuntime; |
||||
|
} |
||||
|
|
||||
public Css(IJSRuntime jsRuntime) |
public async Task ShowBodyOverflow() |
||||
{ |
{ |
||||
_jsRuntime = jsRuntime; |
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.ShowBodyOverflow); |
||||
} |
} |
||||
|
|
||||
public async Task ShowBodyOverflow() |
|
||||
{ |
|
||||
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.ShowBodyOverflow); |
|
||||
} |
|
||||
|
|
||||
public async Task<string> HideBodyOverflow() |
public async Task<string> HideBodyOverflow() |
||||
{ |
{ |
||||
return await _jsRuntime.InvokeAsync<string>(JSInteropConstants.HideBodyOverflow); |
return await _jsRuntime.InvokeAsync<string>(JSInteropConstants.HideBodyOverflow); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,11 +1,10 @@ |
|||||
namespace BlazorAdmin.JavaScript |
namespace BlazorAdmin.JavaScript; |
||||
|
|
||||
|
public static class JSInteropConstants |
||||
{ |
{ |
||||
public static class JSInteropConstants |
public static string DeleteCookie => "deleteCookie"; |
||||
{ |
public static string GetCookie => "getCookie"; |
||||
public static string DeleteCookie => "deleteCookie"; |
public static string RouteOutside => "routeOutside"; |
||||
public static string GetCookie => "getCookie"; |
public static string HideBodyOverflow => "hideBodyOverflow"; |
||||
public static string RouteOutside => "routeOutside"; |
public static string ShowBodyOverflow => "showBodyOverflow"; |
||||
public static string HideBodyOverflow => "hideBodyOverflow"; |
|
||||
public static string ShowBodyOverflow => "showBodyOverflow"; |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,20 +1,19 @@ |
|||||
using Microsoft.JSInterop; |
using System.Threading.Tasks; |
||||
using System.Threading.Tasks; |
using Microsoft.JSInterop; |
||||
|
|
||||
namespace BlazorAdmin.JavaScript |
namespace BlazorAdmin.JavaScript; |
||||
|
|
||||
|
public class Route |
||||
{ |
{ |
||||
public class Route |
private readonly IJSRuntime _jsRuntime; |
||||
{ |
|
||||
private readonly IJSRuntime _jsRuntime; |
|
||||
|
|
||||
public Route(IJSRuntime jsRuntime) |
public Route(IJSRuntime jsRuntime) |
||||
{ |
{ |
||||
_jsRuntime = jsRuntime; |
_jsRuntime = jsRuntime; |
||||
} |
} |
||||
|
|
||||
public async Task RouteOutside(string path) |
public async Task RouteOutside(string path) |
||||
{ |
{ |
||||
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.RouteOutside, path); |
await _jsRuntime.InvokeAsync<string>(JSInteropConstants.RouteOutside, path); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,69 +1,68 @@ |
|||||
using BlazorAdmin.Helpers; |
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using BlazorAdmin.Helpers; |
||||
using BlazorShared.Interfaces; |
using BlazorShared.Interfaces; |
||||
using BlazorShared.Models; |
using BlazorShared.Models; |
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Pages.CatalogItemPage |
namespace BlazorAdmin.Pages.CatalogItemPage; |
||||
|
|
||||
|
public partial class List : BlazorComponent |
||||
{ |
{ |
||||
public partial class List : BlazorComponent |
[Microsoft.AspNetCore.Components.Inject] |
||||
{ |
public ICatalogItemService CatalogItemService { get; set; } |
||||
[Microsoft.AspNetCore.Components.Inject] |
|
||||
public ICatalogItemService CatalogItemService { get; set; } |
|
||||
|
|
||||
[Microsoft.AspNetCore.Components.Inject] |
[Microsoft.AspNetCore.Components.Inject] |
||||
public ICatalogLookupDataService<CatalogBrand> CatalogBrandService { get; set; } |
public ICatalogLookupDataService<CatalogBrand> CatalogBrandService { get; set; } |
||||
|
|
||||
[Microsoft.AspNetCore.Components.Inject] |
[Microsoft.AspNetCore.Components.Inject] |
||||
public ICatalogLookupDataService<CatalogType> CatalogTypeService { get; set; } |
public ICatalogLookupDataService<CatalogType> CatalogTypeService { get; set; } |
||||
|
|
||||
private List<CatalogItem> catalogItems = new List<CatalogItem>(); |
private List<CatalogItem> catalogItems = new List<CatalogItem>(); |
||||
private List<CatalogType> catalogTypes = new List<CatalogType>(); |
private List<CatalogType> catalogTypes = new List<CatalogType>(); |
||||
private List<CatalogBrand> catalogBrands = new List<CatalogBrand>(); |
private List<CatalogBrand> catalogBrands = new List<CatalogBrand>(); |
||||
|
|
||||
private Edit EditComponent { get; set; } |
private Edit EditComponent { get; set; } |
||||
private Delete DeleteComponent { get; set; } |
private Delete DeleteComponent { get; set; } |
||||
private Details DetailsComponent { get; set; } |
private Details DetailsComponent { get; set; } |
||||
private Create CreateComponent { get; set; } |
private Create CreateComponent { get; set; } |
||||
|
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) |
protected override async Task OnAfterRenderAsync(bool firstRender) |
||||
|
{ |
||||
|
if (firstRender) |
||||
{ |
{ |
||||
if (firstRender) |
catalogItems = await CatalogItemService.List(); |
||||
{ |
catalogTypes = await CatalogTypeService.List(); |
||||
catalogItems = await CatalogItemService.List(); |
catalogBrands = await CatalogBrandService.List(); |
||||
catalogTypes = await CatalogTypeService.List(); |
|
||||
catalogBrands = await CatalogBrandService.List(); |
|
||||
|
|
||||
CallRequestRefresh(); |
|
||||
} |
|
||||
|
|
||||
await base.OnAfterRenderAsync(firstRender); |
CallRequestRefresh(); |
||||
} |
} |
||||
|
|
||||
private async void DetailsClick(int id) |
await base.OnAfterRenderAsync(firstRender); |
||||
{ |
} |
||||
await DetailsComponent.Open(id); |
|
||||
} |
|
||||
|
|
||||
private async Task CreateClick() |
private async void DetailsClick(int id) |
||||
{ |
{ |
||||
await CreateComponent.Open(); |
await DetailsComponent.Open(id); |
||||
} |
} |
||||
|
|
||||
private async Task EditClick(int id) |
private async Task CreateClick() |
||||
{ |
{ |
||||
await EditComponent.Open(id); |
await CreateComponent.Open(); |
||||
} |
} |
||||
|
|
||||
private async Task DeleteClick(int id) |
private async Task EditClick(int id) |
||||
{ |
{ |
||||
await DeleteComponent.Open(id); |
await EditComponent.Open(id); |
||||
} |
} |
||||
|
|
||||
private async Task ReloadCatalogItems() |
private async Task DeleteClick(int id) |
||||
{ |
{ |
||||
catalogItems = await CatalogItemService.List(); |
await DeleteComponent.Open(id); |
||||
StateHasChanged(); |
} |
||||
} |
|
||||
|
private async Task ReloadCatalogItems() |
||||
|
{ |
||||
|
catalogItems = await CatalogItemService.List(); |
||||
|
StateHasChanged(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,19 +1,18 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace BlazorAdmin.Services |
namespace BlazorAdmin.Services; |
||||
|
|
||||
|
public class CacheEntry<T> |
||||
{ |
{ |
||||
public class CacheEntry<T> |
public CacheEntry(T item) |
||||
|
{ |
||||
|
Value = item; |
||||
|
} |
||||
|
public CacheEntry() |
||||
{ |
{ |
||||
public CacheEntry(T item) |
|
||||
{ |
|
||||
Value = item; |
|
||||
} |
|
||||
public CacheEntry() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public T Value { get; set; } |
|
||||
public DateTime DateCreated { get; set; } = DateTime.UtcNow; |
|
||||
} |
} |
||||
|
|
||||
|
public T Value { get; set; } |
||||
|
public DateTime DateCreated { get; set; } = DateTime.UtcNow; |
||||
} |
} |
||||
|
|||||
@ -1,114 +1,113 @@ |
|||||
using Blazored.LocalStorage; |
using System; |
||||
using BlazorShared.Interfaces; |
|
||||
using BlazorShared.Models; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.Linq; |
using System.Linq; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Blazored.LocalStorage; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
namespace BlazorAdmin.Services |
namespace BlazorAdmin.Services; |
||||
|
|
||||
|
public class CachedCatalogItemServiceDecorator : ICatalogItemService |
||||
{ |
{ |
||||
public class CachedCatalogItemServiceDecorator : ICatalogItemService |
private readonly ILocalStorageService _localStorageService; |
||||
{ |
private readonly CatalogItemService _catalogItemService; |
||||
private readonly ILocalStorageService _localStorageService; |
private ILogger<CachedCatalogItemServiceDecorator> _logger; |
||||
private readonly CatalogItemService _catalogItemService; |
|
||||
private ILogger<CachedCatalogItemServiceDecorator> _logger; |
|
||||
|
|
||||
public CachedCatalogItemServiceDecorator(ILocalStorageService localStorageService, |
public CachedCatalogItemServiceDecorator(ILocalStorageService localStorageService, |
||||
CatalogItemService catalogItemService, |
CatalogItemService catalogItemService, |
||||
ILogger<CachedCatalogItemServiceDecorator> logger) |
ILogger<CachedCatalogItemServiceDecorator> logger) |
||||
{ |
{ |
||||
_localStorageService = localStorageService; |
_localStorageService = localStorageService; |
||||
_catalogItemService = catalogItemService; |
_catalogItemService = catalogItemService; |
||||
_logger = logger; |
_logger = logger; |
||||
} |
} |
||||
|
|
||||
public async Task<List<CatalogItem>> ListPaged(int pageSize) |
public async Task<List<CatalogItem>> ListPaged(int pageSize) |
||||
|
{ |
||||
|
string key = "items"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
||||
|
if (cacheEntry != null) |
||||
{ |
{ |
||||
string key = "items"; |
_logger.LogInformation("Loading items from local storage."); |
||||
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
if (cacheEntry != null) |
|
||||
{ |
{ |
||||
_logger.LogInformation("Loading items from local storage."); |
return cacheEntry.Value; |
||||
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
} |
||||
{ |
else |
||||
return cacheEntry.Value; |
{ |
||||
} |
_logger.LogInformation($"Loading {key} from local storage."); |
||||
else |
await _localStorageService.RemoveItemAsync(key); |
||||
{ |
|
||||
_logger.LogInformation($"Loading {key} from local storage."); |
|
||||
await _localStorageService.RemoveItemAsync(key); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
var items = await _catalogItemService.ListPaged(pageSize); |
|
||||
var entry = new CacheEntry<List<CatalogItem>>(items); |
|
||||
await _localStorageService.SetItemAsync(key, entry); |
|
||||
return items; |
|
||||
} |
} |
||||
|
|
||||
public async Task<List<CatalogItem>> List() |
var items = await _catalogItemService.ListPaged(pageSize); |
||||
|
var entry = new CacheEntry<List<CatalogItem>>(items); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
|
return items; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogItem>> List() |
||||
|
{ |
||||
|
string key = "items"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
||||
|
if (cacheEntry != null) |
||||
{ |
{ |
||||
string key = "items"; |
_logger.LogInformation("Loading items from local storage."); |
||||
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
if (cacheEntry != null) |
|
||||
{ |
{ |
||||
_logger.LogInformation("Loading items from local storage."); |
return cacheEntry.Value; |
||||
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
} |
||||
{ |
else |
||||
return cacheEntry.Value; |
{ |
||||
} |
_logger.LogInformation($"Loading {key} from local storage."); |
||||
else |
await _localStorageService.RemoveItemAsync(key); |
||||
{ |
|
||||
_logger.LogInformation($"Loading {key} from local storage."); |
|
||||
await _localStorageService.RemoveItemAsync(key); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
var items = await _catalogItemService.List(); |
|
||||
var entry = new CacheEntry<List<CatalogItem>>(items); |
|
||||
await _localStorageService.SetItemAsync(key, entry); |
|
||||
return items; |
|
||||
} |
} |
||||
|
|
||||
public async Task<CatalogItem> GetById(int id) |
var items = await _catalogItemService.List(); |
||||
{ |
var entry = new CacheEntry<List<CatalogItem>>(items); |
||||
return (await List()).FirstOrDefault(x => x.Id == id); |
await _localStorageService.SetItemAsync(key, entry); |
||||
} |
return items; |
||||
|
} |
||||
|
|
||||
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
public async Task<CatalogItem> GetById(int id) |
||||
{ |
{ |
||||
var result = await _catalogItemService.Create(catalogItem); |
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
await RefreshLocalStorageList(); |
} |
||||
|
|
||||
return result; |
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
||||
} |
{ |
||||
|
var result = await _catalogItemService.Create(catalogItem); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
return result; |
||||
{ |
} |
||||
var result = await _catalogItemService.Edit(catalogItem); |
|
||||
await RefreshLocalStorageList(); |
|
||||
|
|
||||
return result; |
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
||||
} |
{ |
||||
|
var result = await _catalogItemService.Edit(catalogItem); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
public async Task<string> Delete(int id) |
return result; |
||||
{ |
} |
||||
var result = await _catalogItemService.Delete(id); |
|
||||
await RefreshLocalStorageList(); |
|
||||
|
|
||||
return result; |
public async Task<string> Delete(int id) |
||||
} |
{ |
||||
|
var result = await _catalogItemService.Delete(id); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
private async Task RefreshLocalStorageList() |
return result; |
||||
{ |
} |
||||
string key = "items"; |
|
||||
|
|
||||
await _localStorageService.RemoveItemAsync(key); |
private async Task RefreshLocalStorageList() |
||||
var items = await _catalogItemService.List(); |
{ |
||||
var entry = new CacheEntry<List<CatalogItem>>(items); |
string key = "items"; |
||||
await _localStorageService.SetItemAsync(key, entry); |
|
||||
} |
await _localStorageService.RemoveItemAsync(key); |
||||
|
var items = await _catalogItemService.List(); |
||||
|
var entry = new CacheEntry<List<CatalogItem>>(items); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,53 +1,52 @@ |
|||||
using Blazored.LocalStorage; |
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Blazored.LocalStorage; |
||||
using BlazorShared.Interfaces; |
using BlazorShared.Interfaces; |
||||
using BlazorShared.Models; |
using BlazorShared.Models; |
||||
using Microsoft.Extensions.Logging; |
using Microsoft.Extensions.Logging; |
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services |
namespace BlazorAdmin.Services; |
||||
|
|
||||
|
public class CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse> |
||||
|
: ICatalogLookupDataService<TLookupData> |
||||
|
where TLookupData : LookupData |
||||
|
where TReponse : ILookupDataResponse<TLookupData> |
||||
{ |
{ |
||||
public class CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse> |
private readonly ILocalStorageService _localStorageService; |
||||
: ICatalogLookupDataService<TLookupData> |
private readonly CatalogLookupDataService<TLookupData, TReponse> _catalogTypeService; |
||||
where TLookupData : LookupData |
private ILogger<CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse>> _logger; |
||||
where TReponse : ILookupDataResponse<TLookupData> |
|
||||
{ |
|
||||
private readonly ILocalStorageService _localStorageService; |
|
||||
private readonly CatalogLookupDataService<TLookupData, TReponse> _catalogTypeService; |
|
||||
private ILogger<CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse>> _logger; |
|
||||
|
|
||||
public CachedCatalogLookupDataServiceDecorator(ILocalStorageService localStorageService, |
public CachedCatalogLookupDataServiceDecorator(ILocalStorageService localStorageService, |
||||
CatalogLookupDataService<TLookupData, TReponse> catalogTypeService, |
CatalogLookupDataService<TLookupData, TReponse> catalogTypeService, |
||||
ILogger<CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse>> logger) |
ILogger<CachedCatalogLookupDataServiceDecorator<TLookupData, TReponse>> logger) |
||||
{ |
{ |
||||
_localStorageService = localStorageService; |
_localStorageService = localStorageService; |
||||
_catalogTypeService = catalogTypeService; |
_catalogTypeService = catalogTypeService; |
||||
_logger = logger; |
_logger = logger; |
||||
} |
} |
||||
|
|
||||
public async Task<List<TLookupData>> List() |
public async Task<List<TLookupData>> List() |
||||
|
{ |
||||
|
string key = typeof(TLookupData).Name; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<TLookupData>>>(key); |
||||
|
if (cacheEntry != null) |
||||
{ |
{ |
||||
string key = typeof(TLookupData).Name; |
_logger.LogInformation($"Loading {key} from local storage."); |
||||
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<TLookupData>>>(key); |
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
if (cacheEntry != null) |
|
||||
{ |
{ |
||||
_logger.LogInformation($"Loading {key} from local storage."); |
return cacheEntry.Value; |
||||
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
} |
||||
{ |
else |
||||
return cacheEntry.Value; |
{ |
||||
} |
_logger.LogInformation($"Cache expired; removing {key} from local storage."); |
||||
else |
await _localStorageService.RemoveItemAsync(key); |
||||
{ |
|
||||
_logger.LogInformation($"Cache expired; removing {key} from local storage."); |
|
||||
await _localStorageService.RemoveItemAsync(key); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
var types = await _catalogTypeService.List(); |
|
||||
var entry = new CacheEntry<List<TLookupData>>(types); |
|
||||
await _localStorageService.SetItemAsync(key, entry); |
|
||||
return types; |
|
||||
} |
} |
||||
|
|
||||
|
var types = await _catalogTypeService.List(); |
||||
|
var entry = new CacheEntry<List<TLookupData>>(types); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
|
return types; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,97 +1,96 @@ |
|||||
using BlazorShared.Interfaces; |
using System.Collections.Generic; |
||||
using BlazorShared.Models; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
using System.Linq; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
|
||||
namespace BlazorAdmin.Services |
namespace BlazorAdmin.Services; |
||||
|
|
||||
|
public class CatalogItemService : ICatalogItemService |
||||
{ |
{ |
||||
public class CatalogItemService : ICatalogItemService |
private readonly ICatalogLookupDataService<CatalogBrand> _brandService; |
||||
|
private readonly ICatalogLookupDataService<CatalogType> _typeService; |
||||
|
private readonly HttpService _httpService; |
||||
|
private readonly ILogger<CatalogItemService> _logger; |
||||
|
|
||||
|
public CatalogItemService(ICatalogLookupDataService<CatalogBrand> brandService, |
||||
|
ICatalogLookupDataService<CatalogType> typeService, |
||||
|
HttpService httpService, |
||||
|
ILogger<CatalogItemService> logger) |
||||
{ |
{ |
||||
private readonly ICatalogLookupDataService<CatalogBrand> _brandService; |
_brandService = brandService; |
||||
private readonly ICatalogLookupDataService<CatalogType> _typeService; |
_typeService = typeService; |
||||
private readonly HttpService _httpService; |
_httpService = httpService; |
||||
private readonly ILogger<CatalogItemService> _logger; |
_logger = logger; |
||||
|
} |
||||
|
|
||||
public CatalogItemService(ICatalogLookupDataService<CatalogBrand> brandService, |
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
||||
ICatalogLookupDataService<CatalogType> typeService, |
{ |
||||
HttpService httpService, |
var response = await _httpService.HttpPost<CreateCatalogItemResponse>("catalog-items", catalogItem); |
||||
ILogger<CatalogItemService> logger) |
return response?.CatalogItem; |
||||
{ |
} |
||||
_brandService = brandService; |
|
||||
_typeService = typeService; |
|
||||
_httpService = httpService; |
|
||||
_logger = logger; |
|
||||
} |
|
||||
|
|
||||
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
||||
{ |
{ |
||||
var response = await _httpService.HttpPost<CreateCatalogItemResponse>("catalog-items", catalogItem); |
return (await _httpService.HttpPut<EditCatalogItemResult>("catalog-items", catalogItem)).CatalogItem; |
||||
return response?.CatalogItem; |
} |
||||
} |
|
||||
|
|
||||
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
public async Task<string> Delete(int catalogItemId) |
||||
{ |
{ |
||||
return (await _httpService.HttpPut<EditCatalogItemResult>("catalog-items", catalogItem)).CatalogItem; |
return (await _httpService.HttpDelete<DeleteCatalogItemResponse>("catalog-items", catalogItemId)).Status; |
||||
} |
} |
||||
|
|
||||
public async Task<string> Delete(int catalogItemId) |
public async Task<CatalogItem> GetById(int id) |
||||
{ |
{ |
||||
return (await _httpService.HttpDelete<DeleteCatalogItemResponse>("catalog-items", catalogItemId)).Status; |
var brandListTask = _brandService.List(); |
||||
} |
var typeListTask = _typeService.List(); |
||||
|
var itemGetTask = _httpService.HttpGet<EditCatalogItemResult>($"catalog-items/{id}"); |
||||
|
await Task.WhenAll(brandListTask, typeListTask, itemGetTask); |
||||
|
var brands = brandListTask.Result; |
||||
|
var types = typeListTask.Result; |
||||
|
var catalogItem = itemGetTask.Result.CatalogItem; |
||||
|
catalogItem.CatalogBrand = brands.FirstOrDefault(b => b.Id == catalogItem.CatalogBrandId)?.Name; |
||||
|
catalogItem.CatalogType = types.FirstOrDefault(t => t.Id == catalogItem.CatalogTypeId)?.Name; |
||||
|
return catalogItem; |
||||
|
} |
||||
|
|
||||
public async Task<CatalogItem> GetById(int id) |
public async Task<List<CatalogItem>> ListPaged(int pageSize) |
||||
{ |
{ |
||||
var brandListTask = _brandService.List(); |
_logger.LogInformation("Fetching catalog items from API."); |
||||
var typeListTask = _typeService.List(); |
|
||||
var itemGetTask = _httpService.HttpGet<EditCatalogItemResult>($"catalog-items/{id}"); |
|
||||
await Task.WhenAll(brandListTask, typeListTask, itemGetTask); |
|
||||
var brands = brandListTask.Result; |
|
||||
var types = typeListTask.Result; |
|
||||
var catalogItem = itemGetTask.Result.CatalogItem; |
|
||||
catalogItem.CatalogBrand = brands.FirstOrDefault(b => b.Id == catalogItem.CatalogBrandId)?.Name; |
|
||||
catalogItem.CatalogType = types.FirstOrDefault(t => t.Id == catalogItem.CatalogTypeId)?.Name; |
|
||||
return catalogItem; |
|
||||
} |
|
||||
|
|
||||
public async Task<List<CatalogItem>> ListPaged(int pageSize) |
var brandListTask = _brandService.List(); |
||||
|
var typeListTask = _typeService.List(); |
||||
|
var itemListTask = _httpService.HttpGet<PagedCatalogItemResponse>($"catalog-items?PageSize=10"); |
||||
|
await Task.WhenAll(brandListTask, typeListTask, itemListTask); |
||||
|
var brands = brandListTask.Result; |
||||
|
var types = typeListTask.Result; |
||||
|
var items = itemListTask.Result.CatalogItems; |
||||
|
foreach (var item in items) |
||||
{ |
{ |
||||
_logger.LogInformation("Fetching catalog items from API."); |
item.CatalogBrand = brands.FirstOrDefault(b => b.Id == item.CatalogBrandId)?.Name; |
||||
|
item.CatalogType = types.FirstOrDefault(t => t.Id == item.CatalogTypeId)?.Name; |
||||
var brandListTask = _brandService.List(); |
|
||||
var typeListTask = _typeService.List(); |
|
||||
var itemListTask = _httpService.HttpGet<PagedCatalogItemResponse>($"catalog-items?PageSize=10"); |
|
||||
await Task.WhenAll(brandListTask, typeListTask, itemListTask); |
|
||||
var brands = brandListTask.Result; |
|
||||
var types = typeListTask.Result; |
|
||||
var items = itemListTask.Result.CatalogItems; |
|
||||
foreach (var item in items) |
|
||||
{ |
|
||||
item.CatalogBrand = brands.FirstOrDefault(b => b.Id == item.CatalogBrandId)?.Name; |
|
||||
item.CatalogType = types.FirstOrDefault(t => t.Id == item.CatalogTypeId)?.Name; |
|
||||
} |
|
||||
return items; |
|
||||
} |
} |
||||
|
return items; |
||||
|
} |
||||
|
|
||||
public async Task<List<CatalogItem>> List() |
public async Task<List<CatalogItem>> List() |
||||
{ |
{ |
||||
_logger.LogInformation("Fetching catalog items from API."); |
_logger.LogInformation("Fetching catalog items from API."); |
||||
|
|
||||
var brandListTask = _brandService.List(); |
var brandListTask = _brandService.List(); |
||||
var typeListTask = _typeService.List(); |
var typeListTask = _typeService.List(); |
||||
var itemListTask = _httpService.HttpGet<PagedCatalogItemResponse>($"catalog-items"); |
var itemListTask = _httpService.HttpGet<PagedCatalogItemResponse>($"catalog-items"); |
||||
await Task.WhenAll(brandListTask, typeListTask, itemListTask); |
await Task.WhenAll(brandListTask, typeListTask, itemListTask); |
||||
var brands = brandListTask.Result; |
var brands = brandListTask.Result; |
||||
var types = typeListTask.Result; |
var types = typeListTask.Result; |
||||
var items = itemListTask.Result.CatalogItems; |
var items = itemListTask.Result.CatalogItems; |
||||
foreach (var item in items) |
foreach (var item in items) |
||||
{ |
{ |
||||
item.CatalogBrand = brands.FirstOrDefault(b => b.Id == item.CatalogBrandId)?.Name; |
item.CatalogBrand = brands.FirstOrDefault(b => b.Id == item.CatalogBrandId)?.Name; |
||||
item.CatalogType = types.FirstOrDefault(t => t.Id == item.CatalogTypeId)?.Name; |
item.CatalogType = types.FirstOrDefault(t => t.Id == item.CatalogTypeId)?.Name; |
||||
} |
|
||||
return items; |
|
||||
} |
} |
||||
|
return items; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,43 +1,42 @@ |
|||||
using BlazorShared; |
using System.Collections.Generic; |
||||
using BlazorShared.Attributes; |
|
||||
using BlazorShared.Interfaces; |
|
||||
using BlazorShared.Models; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
using System.Linq; |
||||
using System.Net.Http; |
using System.Net.Http; |
||||
using System.Net.Http.Json; |
using System.Net.Http.Json; |
||||
using System.Reflection; |
using System.Reflection; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared; |
||||
|
using BlazorShared.Attributes; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace BlazorAdmin.Services; |
||||
|
|
||||
namespace BlazorAdmin.Services |
public class CatalogLookupDataService<TLookupData, TReponse> |
||||
|
: ICatalogLookupDataService<TLookupData> |
||||
|
where TLookupData : LookupData |
||||
|
where TReponse : ILookupDataResponse<TLookupData> |
||||
{ |
{ |
||||
public class CatalogLookupDataService<TLookupData, TReponse> |
|
||||
: ICatalogLookupDataService<TLookupData> |
|
||||
where TLookupData : LookupData |
|
||||
where TReponse : ILookupDataResponse<TLookupData> |
|
||||
{ |
|
||||
|
|
||||
private readonly HttpClient _httpClient; |
private readonly HttpClient _httpClient; |
||||
private readonly ILogger<CatalogLookupDataService<TLookupData, TReponse>> _logger; |
private readonly ILogger<CatalogLookupDataService<TLookupData, TReponse>> _logger; |
||||
private readonly string _apiUrl; |
private readonly string _apiUrl; |
||||
|
|
||||
public CatalogLookupDataService(HttpClient httpClient, |
public CatalogLookupDataService(HttpClient httpClient, |
||||
BaseUrlConfiguration baseUrlConfiguration, |
BaseUrlConfiguration baseUrlConfiguration, |
||||
ILogger<CatalogLookupDataService<TLookupData, TReponse>> logger) |
ILogger<CatalogLookupDataService<TLookupData, TReponse>> logger) |
||||
{ |
{ |
||||
_httpClient = httpClient; |
_httpClient = httpClient; |
||||
_logger = logger; |
_logger = logger; |
||||
_apiUrl = baseUrlConfiguration.ApiBase; |
_apiUrl = baseUrlConfiguration.ApiBase; |
||||
} |
} |
||||
|
|
||||
public async Task<List<TLookupData>> List() |
public async Task<List<TLookupData>> List() |
||||
{ |
{ |
||||
var endpointName = typeof(TLookupData).GetCustomAttribute<EndpointAttribute>().Name; |
var endpointName = typeof(TLookupData).GetCustomAttribute<EndpointAttribute>().Name; |
||||
_logger.LogInformation($"Fetching {typeof(TLookupData).Name} from API. Enpoint : {endpointName}"); |
_logger.LogInformation($"Fetching {typeof(TLookupData).Name} from API. Enpoint : {endpointName}"); |
||||
|
|
||||
var response = await _httpClient.GetFromJsonAsync<TReponse>($"{_apiUrl}{endpointName}"); |
var response = await _httpClient.GetFromJsonAsync<TReponse>($"{_apiUrl}{endpointName}"); |
||||
return response.List; |
return response.List; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,96 +1,95 @@ |
|||||
using BlazorShared; |
using System.Net.Http; |
||||
using BlazorShared.Models; |
|
||||
using System.Net.Http; |
|
||||
using System.Text; |
using System.Text; |
||||
using System.Text.Json; |
using System.Text.Json; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared; |
||||
|
using BlazorShared.Models; |
||||
|
|
||||
|
namespace BlazorAdmin.Services; |
||||
|
|
||||
namespace BlazorAdmin.Services |
public class HttpService |
||||
{ |
{ |
||||
public class HttpService |
private readonly HttpClient _httpClient; |
||||
{ |
private readonly ToastService _toastService; |
||||
private readonly HttpClient _httpClient; |
private readonly string _apiUrl; |
||||
private readonly ToastService _toastService; |
|
||||
private readonly string _apiUrl; |
|
||||
|
|
||||
|
public HttpService(HttpClient httpClient, BaseUrlConfiguration baseUrlConfiguration, ToastService toastService) |
||||
|
{ |
||||
|
_httpClient = httpClient; |
||||
|
_toastService = toastService; |
||||
|
_apiUrl = baseUrlConfiguration.ApiBase; |
||||
|
} |
||||
|
|
||||
public HttpService(HttpClient httpClient, BaseUrlConfiguration baseUrlConfiguration, ToastService toastService) |
public async Task<T> HttpGet<T>(string uri) |
||||
|
where T : class |
||||
|
{ |
||||
|
var result = await _httpClient.GetAsync($"{_apiUrl}{uri}"); |
||||
|
if (!result.IsSuccessStatusCode) |
||||
{ |
{ |
||||
_httpClient = httpClient; |
return null; |
||||
_toastService = toastService; |
|
||||
_apiUrl = baseUrlConfiguration.ApiBase; |
|
||||
} |
} |
||||
|
|
||||
public async Task<T> HttpGet<T>(string uri) |
return await FromHttpResponseMessage<T>(result); |
||||
where T : class |
} |
||||
{ |
|
||||
var result = await _httpClient.GetAsync($"{_apiUrl}{uri}"); |
|
||||
if (!result.IsSuccessStatusCode) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return await FromHttpResponseMessage<T>(result); |
public async Task<T> HttpDelete<T>(string uri, int id) |
||||
|
where T : class |
||||
|
{ |
||||
|
var result = await _httpClient.DeleteAsync($"{_apiUrl}{uri}/{id}"); |
||||
|
if (!result.IsSuccessStatusCode) |
||||
|
{ |
||||
|
return null; |
||||
} |
} |
||||
|
|
||||
public async Task<T> HttpDelete<T>(string uri, int id) |
return await FromHttpResponseMessage<T>(result); |
||||
where T : class |
} |
||||
{ |
|
||||
var result = await _httpClient.DeleteAsync($"{_apiUrl}{uri}/{id}"); |
|
||||
if (!result.IsSuccessStatusCode) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return await FromHttpResponseMessage<T>(result); |
public async Task<T> HttpPost<T>(string uri, object dataToSend) |
||||
} |
where T : class |
||||
|
{ |
||||
|
var content = ToJson(dataToSend); |
||||
|
|
||||
public async Task<T> HttpPost<T>(string uri, object dataToSend) |
var result = await _httpClient.PostAsync($"{_apiUrl}{uri}", content); |
||||
where T : class |
if (!result.IsSuccessStatusCode) |
||||
{ |
{ |
||||
var content = ToJson(dataToSend); |
var exception = JsonSerializer.Deserialize<ErrorDetails>(await result.Content.ReadAsStringAsync(), new JsonSerializerOptions |
||||
|
|
||||
var result = await _httpClient.PostAsync($"{_apiUrl}{uri}", content); |
|
||||
if (!result.IsSuccessStatusCode) |
|
||||
{ |
{ |
||||
var exception = JsonSerializer.Deserialize<ErrorDetails>(await result.Content.ReadAsStringAsync(), new JsonSerializerOptions |
PropertyNameCaseInsensitive = true |
||||
{ |
}); |
||||
PropertyNameCaseInsensitive = true |
_toastService.ShowToast($"Error : {exception.Message}", ToastLevel.Error); |
||||
}); |
|
||||
_toastService.ShowToast($"Error : {exception.Message}", ToastLevel.Error); |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return await FromHttpResponseMessage<T>(result); |
return null; |
||||
} |
} |
||||
|
|
||||
public async Task<T> HttpPut<T>(string uri, object dataToSend) |
return await FromHttpResponseMessage<T>(result); |
||||
where T : class |
} |
||||
{ |
|
||||
var content = ToJson(dataToSend); |
|
||||
|
|
||||
var result = await _httpClient.PutAsync($"{_apiUrl}{uri}", content); |
|
||||
if (!result.IsSuccessStatusCode) |
|
||||
{ |
|
||||
_toastService.ShowToast("Error", ToastLevel.Error); |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return await FromHttpResponseMessage<T>(result); |
public async Task<T> HttpPut<T>(string uri, object dataToSend) |
||||
} |
where T : class |
||||
|
{ |
||||
|
var content = ToJson(dataToSend); |
||||
|
|
||||
private StringContent ToJson(object obj) |
var result = await _httpClient.PutAsync($"{_apiUrl}{uri}", content); |
||||
|
if (!result.IsSuccessStatusCode) |
||||
{ |
{ |
||||
return new StringContent(JsonSerializer.Serialize(obj), Encoding.UTF8, "application/json"); |
_toastService.ShowToast("Error", ToastLevel.Error); |
||||
|
return null; |
||||
} |
} |
||||
|
|
||||
private async Task<T> FromHttpResponseMessage<T>(HttpResponseMessage result) |
return await FromHttpResponseMessage<T>(result); |
||||
|
} |
||||
|
|
||||
|
private StringContent ToJson(object obj) |
||||
|
{ |
||||
|
return new StringContent(JsonSerializer.Serialize(obj), Encoding.UTF8, "application/json"); |
||||
|
} |
||||
|
|
||||
|
private async Task<T> FromHttpResponseMessage<T>(HttpResponseMessage result) |
||||
|
{ |
||||
|
return JsonSerializer.Deserialize<T>(await result.Content.ReadAsStringAsync(), new JsonSerializerOptions |
||||
{ |
{ |
||||
return JsonSerializer.Deserialize<T>(await result.Content.ReadAsStringAsync(), new JsonSerializerOptions |
PropertyNameCaseInsensitive = true |
||||
{ |
}); |
||||
PropertyNameCaseInsensitive = true |
|
||||
}); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,55 +1,54 @@ |
|||||
using System; |
using System; |
||||
using System.Timers; |
using System.Timers; |
||||
|
|
||||
namespace BlazorAdmin.Services |
namespace BlazorAdmin.Services; |
||||
|
|
||||
|
public enum ToastLevel |
||||
|
{ |
||||
|
Info, |
||||
|
Success, |
||||
|
Warning, |
||||
|
Error |
||||
|
} |
||||
|
|
||||
|
public class ToastService : IDisposable |
||||
{ |
{ |
||||
public enum ToastLevel |
public event Action<string, ToastLevel> OnShow; |
||||
|
public event Action OnHide; |
||||
|
private Timer Countdown; |
||||
|
public void ShowToast(string message, ToastLevel level) |
||||
{ |
{ |
||||
Info, |
OnShow?.Invoke(message, level); |
||||
Success, |
StartCountdown(); |
||||
Warning, |
|
||||
Error |
|
||||
} |
} |
||||
|
private void StartCountdown() |
||||
public class ToastService : IDisposable |
|
||||
{ |
{ |
||||
public event Action<string, ToastLevel> OnShow; |
SetCountdown(); |
||||
public event Action OnHide; |
if (Countdown.Enabled) |
||||
private Timer Countdown; |
|
||||
public void ShowToast(string message, ToastLevel level) |
|
||||
{ |
|
||||
OnShow?.Invoke(message, level); |
|
||||
StartCountdown(); |
|
||||
} |
|
||||
private void StartCountdown() |
|
||||
{ |
{ |
||||
SetCountdown(); |
Countdown.Stop(); |
||||
if (Countdown.Enabled) |
Countdown.Start(); |
||||
{ |
|
||||
Countdown.Stop(); |
|
||||
Countdown.Start(); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
Countdown.Start(); |
|
||||
} |
|
||||
} |
} |
||||
private void SetCountdown() |
else |
||||
{ |
{ |
||||
if (Countdown == null) |
Countdown.Start(); |
||||
{ |
|
||||
Countdown = new Timer(3000); |
|
||||
Countdown.Elapsed += HideToast; |
|
||||
Countdown.AutoReset = false; |
|
||||
} |
|
||||
} |
} |
||||
private void HideToast(object source, ElapsedEventArgs args) |
} |
||||
{ |
private void SetCountdown() |
||||
OnHide?.Invoke(); |
{ |
||||
} |
if (Countdown == null) |
||||
public void Dispose() |
|
||||
{ |
{ |
||||
Countdown?.Dispose(); |
Countdown = new Timer(3000); |
||||
|
Countdown.Elapsed += HideToast; |
||||
|
Countdown.AutoReset = false; |
||||
} |
} |
||||
} |
} |
||||
|
private void HideToast(object source, ElapsedEventArgs args) |
||||
|
{ |
||||
|
OnHide?.Invoke(); |
||||
|
} |
||||
|
public void Dispose() |
||||
|
{ |
||||
|
Countdown?.Dispose(); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -1,38 +1,37 @@ |
|||||
using Microsoft.AspNetCore.Components.Forms; |
using Microsoft.AspNetCore.Components.Forms; |
||||
|
|
||||
namespace BlazorAdmin.Shared |
namespace BlazorAdmin.Shared; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This is needed until 5.0 ships with native support
|
||||
|
/// https://www.pragimtech.com/blog/blazor/inputselect-does-not-support-system.int32/
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TValue"></typeparam>
|
||||
|
public class CustomInputSelect<TValue> : InputSelect<TValue> |
||||
{ |
{ |
||||
/// <summary>
|
protected override bool TryParseValueFromString(string value, out TValue result, |
||||
/// This is needed until 5.0 ships with native support
|
out string validationErrorMessage) |
||||
/// https://www.pragimtech.com/blog/blazor/inputselect-does-not-support-system.int32/
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TValue"></typeparam>
|
|
||||
public class CustomInputSelect<TValue> : InputSelect<TValue> |
|
||||
{ |
{ |
||||
protected override bool TryParseValueFromString(string value, out TValue result, |
if (typeof(TValue) == typeof(int)) |
||||
out string validationErrorMessage) |
|
||||
{ |
{ |
||||
if (typeof(TValue) == typeof(int)) |
if (int.TryParse(value, out var resultInt)) |
||||
{ |
{ |
||||
if (int.TryParse(value, out var resultInt)) |
result = (TValue)(object)resultInt; |
||||
{ |
validationErrorMessage = null; |
||||
result = (TValue)(object)resultInt; |
return true; |
||||
validationErrorMessage = null; |
|
||||
return true; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
result = default; |
|
||||
validationErrorMessage = |
|
||||
$"The selected value {value} is not a valid number."; |
|
||||
return false; |
|
||||
} |
|
||||
} |
} |
||||
else |
else |
||||
{ |
{ |
||||
return base.TryParseValueFromString(value, out result, |
result = default; |
||||
out validationErrorMessage); |
validationErrorMessage = |
||||
|
$"The selected value {value} is not a valid number."; |
||||
|
return false; |
||||
} |
} |
||||
} |
} |
||||
|
else |
||||
|
{ |
||||
|
return base.TryParseValueFromString(value, out result, |
||||
|
out validationErrorMessage); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace BlazorShared.Attributes |
namespace BlazorShared.Attributes; |
||||
|
|
||||
|
public class EndpointAttribute : Attribute |
||||
{ |
{ |
||||
public class EndpointAttribute : Attribute |
public string Name { get; set; } |
||||
{ |
|
||||
public string Name { get; set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,18 +1,17 @@ |
|||||
namespace BlazorShared.Authorization |
namespace BlazorShared.Authorization; |
||||
|
|
||||
|
public class ClaimValue |
||||
{ |
{ |
||||
public class ClaimValue |
public ClaimValue() |
||||
{ |
{ |
||||
public ClaimValue() |
} |
||||
{ |
|
||||
} |
|
||||
|
|
||||
public ClaimValue(string type, string value) |
|
||||
{ |
|
||||
Type = type; |
|
||||
Value = value; |
|
||||
} |
|
||||
|
|
||||
public string Type { get; set; } |
public ClaimValue(string type, string value) |
||||
public string Value { get; set; } |
{ |
||||
|
Type = type; |
||||
|
Value = value; |
||||
} |
} |
||||
|
|
||||
|
public string Type { get; set; } |
||||
|
public string Value { get; set; } |
||||
} |
} |
||||
|
|||||
@ -1,10 +1,9 @@ |
|||||
namespace BlazorShared.Authorization |
namespace BlazorShared.Authorization; |
||||
|
|
||||
|
public static class Constants |
||||
{ |
{ |
||||
public static class Constants |
public static class Roles |
||||
{ |
{ |
||||
public static class Roles |
public const string ADMINISTRATORS = "Administrators"; |
||||
{ |
|
||||
public const string ADMINISTRATORS = "Administrators"; |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,14 +1,13 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace BlazorShared.Authorization |
namespace BlazorShared.Authorization; |
||||
|
|
||||
|
public class UserInfo |
||||
{ |
{ |
||||
public class UserInfo |
public static readonly UserInfo Anonymous = new UserInfo(); |
||||
{ |
public bool IsAuthenticated { get; set; } |
||||
public static readonly UserInfo Anonymous = new UserInfo(); |
public string NameClaimType { get; set; } |
||||
public bool IsAuthenticated { get; set; } |
public string RoleClaimType { get; set; } |
||||
public string NameClaimType { get; set; } |
public string Token { get; set; } |
||||
public string RoleClaimType { get; set; } |
public IEnumerable<ClaimValue> Claims { get; set; } |
||||
public string Token { get; set; } |
|
||||
public IEnumerable<ClaimValue> Claims { get; set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,10 +1,9 @@ |
|||||
namespace BlazorShared |
namespace BlazorShared; |
||||
|
|
||||
|
public class BaseUrlConfiguration |
||||
{ |
{ |
||||
public class BaseUrlConfiguration |
public const string CONFIG_NAME = "baseUrls"; |
||||
{ |
|
||||
public const string CONFIG_NAME = "baseUrls"; |
|
||||
|
|
||||
public string ApiBase { get; set; } |
public string ApiBase { get; set; } |
||||
public string WebBase { get; set; } |
public string WebBase { get; set; } |
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,11 +1,10 @@ |
|||||
using BlazorShared.Models; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using BlazorShared.Models; |
||||
|
|
||||
namespace BlazorShared.Interfaces |
namespace BlazorShared.Interfaces; |
||||
|
|
||||
|
public interface ICatalogLookupDataService<TLookupData> where TLookupData : LookupData |
||||
{ |
{ |
||||
public interface ICatalogLookupDataService<TLookupData> where TLookupData : LookupData |
Task<List<TLookupData>> List(); |
||||
{ |
|
||||
Task<List<TLookupData>> List(); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,10 +1,9 @@ |
|||||
using BlazorShared.Models; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
using BlazorShared.Models; |
||||
|
|
||||
namespace BlazorShared.Interfaces |
namespace BlazorShared.Interfaces; |
||||
|
|
||||
|
public interface ILookupDataResponse<TLookupData> where TLookupData : LookupData |
||||
{ |
{ |
||||
public interface ILookupDataResponse<TLookupData> where TLookupData : LookupData |
List<TLookupData> List { get; set; } |
||||
{ |
|
||||
List<TLookupData> List { get; set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
using BlazorShared.Attributes; |
using BlazorShared.Attributes; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
[Endpoint(Name = "catalog-brands")] |
||||
|
public class CatalogBrand : LookupData |
||||
{ |
{ |
||||
[Endpoint(Name = "catalog-brands")] |
|
||||
public class CatalogBrand : LookupData |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,12 +1,11 @@ |
|||||
using BlazorShared.Interfaces; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Text.Json.Serialization; |
using System.Text.Json.Serialization; |
||||
|
using BlazorShared.Interfaces; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class CatalogBrandResponse : ILookupDataResponse<CatalogBrand> |
||||
{ |
{ |
||||
public class CatalogBrandResponse : ILookupDataResponse<CatalogBrand> |
[JsonPropertyName("CatalogBrands")] |
||||
{ |
public List<CatalogBrand> List { get; set; } = new List<CatalogBrand>(); |
||||
[JsonPropertyName("CatalogBrands")] |
|
||||
public List<CatalogBrand> List { get; set; } = new List<CatalogBrand>(); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,9 +1,8 @@ |
|||||
using BlazorShared.Attributes; |
using BlazorShared.Attributes; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
[Endpoint(Name = "catalog-types")] |
||||
|
public class CatalogType : LookupData |
||||
{ |
{ |
||||
[Endpoint(Name = "catalog-types")] |
|
||||
public class CatalogType : LookupData |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,13 +1,12 @@ |
|||||
using BlazorShared.Interfaces; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Text.Json.Serialization; |
using System.Text.Json.Serialization; |
||||
|
using BlazorShared.Interfaces; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class CatalogTypeResponse : ILookupDataResponse<CatalogType> |
||||
{ |
{ |
||||
public class CatalogTypeResponse : ILookupDataResponse<CatalogType> |
|
||||
{ |
|
||||
|
|
||||
[JsonPropertyName("CatalogTypes")] |
[JsonPropertyName("CatalogTypes")] |
||||
public List<CatalogType> List { get; set; } = new List<CatalogType>(); |
public List<CatalogType> List { get; set; } = new List<CatalogType>(); |
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,28 +1,27 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class CreateCatalogItemRequest |
||||
{ |
{ |
||||
public class CreateCatalogItemRequest |
public int CatalogTypeId { get; set; } |
||||
{ |
|
||||
public int CatalogTypeId { get; set; } |
|
||||
|
|
||||
public int CatalogBrandId { get; set; } |
public int CatalogBrandId { get; set; } |
||||
|
|
||||
[Required(ErrorMessage = "The Name field is required")] |
[Required(ErrorMessage = "The Name field is required")] |
||||
public string Name { get; set; } = string.Empty; |
public string Name { get; set; } = string.Empty; |
||||
|
|
||||
[Required(ErrorMessage = "The Description field is required")] |
[Required(ErrorMessage = "The Description field is required")] |
||||
public string Description { get; set; } = string.Empty; |
public string Description { get; set; } = string.Empty; |
||||
|
|
||||
// decimal(18,2)
|
// decimal(18,2)
|
||||
[RegularExpression(@"^\d+(\.\d{0,2})*$", ErrorMessage = "The field Price must be a positive number with maximum two decimals.")] |
[RegularExpression(@"^\d+(\.\d{0,2})*$", ErrorMessage = "The field Price must be a positive number with maximum two decimals.")] |
||||
[Range(0.01, 1000)] |
[Range(0.01, 1000)] |
||||
[DataType(DataType.Currency)] |
[DataType(DataType.Currency)] |
||||
public decimal Price { get; set; } = 0; |
public decimal Price { get; set; } = 0; |
||||
|
|
||||
public string PictureUri { get; set; } = string.Empty; |
public string PictureUri { get; set; } = string.Empty; |
||||
public string PictureBase64 { get; set; } = string.Empty; |
public string PictureBase64 { get; set; } = string.Empty; |
||||
public string PictureName { get; set; } = string.Empty; |
public string PictureName { get; set; } = string.Empty; |
||||
|
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,7 +1,6 @@ |
|||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class CreateCatalogItemResponse |
||||
{ |
{ |
||||
public class CreateCatalogItemResponse |
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
||||
{ |
|
||||
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,7 +1,6 @@ |
|||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class DeleteCatalogItemResponse |
||||
{ |
{ |
||||
public class DeleteCatalogItemResponse |
public string Status { get; set; } = "Deleted"; |
||||
{ |
|
||||
public string Status { get; set; } = "Deleted"; |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,7 +1,6 @@ |
|||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class EditCatalogItemResult |
||||
{ |
{ |
||||
public class EditCatalogItemResult |
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
||||
{ |
|
||||
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,14 +1,13 @@ |
|||||
using System.Text.Json; |
using System.Text.Json; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class ErrorDetails |
||||
{ |
{ |
||||
public class ErrorDetails |
public int StatusCode { get; set; } |
||||
|
public string Message { get; set; } |
||||
|
public override string ToString() |
||||
{ |
{ |
||||
public int StatusCode { get; set; } |
return JsonSerializer.Serialize(this); |
||||
public string Message { get; set; } |
|
||||
public override string ToString() |
|
||||
{ |
|
||||
return JsonSerializer.Serialize(this); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,8 +1,7 @@ |
|||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public abstract class LookupData |
||||
{ |
{ |
||||
public abstract class LookupData |
public int Id { get; set; } |
||||
{ |
public string Name { get; set; } |
||||
public int Id { get; set; } |
|
||||
public string Name { get; set; } |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,10 +1,9 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace BlazorShared.Models |
namespace BlazorShared.Models; |
||||
|
|
||||
|
public class PagedCatalogItemResponse |
||||
{ |
{ |
||||
public class PagedCatalogItemResponse |
public List<CatalogItem> CatalogItems { get; set; } = new List<CatalogItem>(); |
||||
{ |
public int PageCount { get; set; } = 0; |
||||
public List<CatalogItem> CatalogItems { get; set; } = new List<CatalogItem>(); |
|
||||
public int PageCount { get; set; } = 0; |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -1,27 +1,26 @@ |
|||||
using Microsoft.EntityFrameworkCore; |
using System.Linq; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data |
namespace Microsoft.eShopWeb.Infrastructure.Data; |
||||
|
|
||||
|
public class BasketQueryService : IBasketQueryService |
||||
{ |
{ |
||||
public class BasketQueryService : IBasketQueryService |
private readonly CatalogContext _dbContext; |
||||
{ |
|
||||
private readonly CatalogContext _dbContext; |
|
||||
|
|
||||
public BasketQueryService(CatalogContext dbContext) |
public BasketQueryService(CatalogContext dbContext) |
||||
{ |
{ |
||||
_dbContext = dbContext; |
_dbContext = dbContext; |
||||
} |
} |
||||
|
|
||||
public async Task<int> CountTotalBasketItems(string username) |
public async Task<int> CountTotalBasketItems(string username) |
||||
{ |
{ |
||||
var totalItems = await _dbContext.Baskets |
var totalItems = await _dbContext.Baskets |
||||
.Where(basket => basket.BuyerId == username) |
.Where(basket => basket.BuyerId == username) |
||||
.SelectMany(item => item.Items) |
.SelectMany(item => item.Items) |
||||
.SumAsync(sum => sum.Quantity); |
.SumAsync(sum => sum.Quantity); |
||||
|
|
||||
return totalItems; |
return totalItems; |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,30 +1,28 @@ |
|||||
using Microsoft.EntityFrameworkCore; |
using System.Reflection; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
using Microsoft.eShopWeb.ApplicationCore.Entities; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; |
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; |
||||
using System.Reflection; |
|
||||
|
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data |
namespace Microsoft.eShopWeb.Infrastructure.Data; |
||||
{ |
|
||||
|
|
||||
public class CatalogContext : DbContext |
public class CatalogContext : DbContext |
||||
|
{ |
||||
|
public CatalogContext(DbContextOptions<CatalogContext> options) : base(options) |
||||
{ |
{ |
||||
public CatalogContext(DbContextOptions<CatalogContext> options) : base(options) |
} |
||||
{ |
|
||||
} |
|
||||
|
|
||||
public DbSet<Basket> Baskets { get; set; } |
public DbSet<Basket> Baskets { get; set; } |
||||
public DbSet<CatalogItem> CatalogItems { get; set; } |
public DbSet<CatalogItem> CatalogItems { get; set; } |
||||
public DbSet<CatalogBrand> CatalogBrands { get; set; } |
public DbSet<CatalogBrand> CatalogBrands { get; set; } |
||||
public DbSet<CatalogType> CatalogTypes { get; set; } |
public DbSet<CatalogType> CatalogTypes { get; set; } |
||||
public DbSet<Order> Orders { get; set; } |
public DbSet<Order> Orders { get; set; } |
||||
public DbSet<OrderItem> OrderItems { get; set; } |
public DbSet<OrderItem> OrderItems { get; set; } |
||||
public DbSet<BasketItem> BasketItems { get; set; } |
public DbSet<BasketItem> BasketItems { get; set; } |
||||
|
|
||||
protected override void OnModelCreating(ModelBuilder builder) |
protected override void OnModelCreating(ModelBuilder builder) |
||||
{ |
{ |
||||
base.OnModelCreating(builder); |
base.OnModelCreating(builder); |
||||
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); |
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,12 +1,11 @@ |
|||||
using Ardalis.Specification.EntityFrameworkCore; |
using Ardalis.Specification.EntityFrameworkCore; |
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
||||
|
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data |
namespace Microsoft.eShopWeb.Infrastructure.Data; |
||||
|
|
||||
|
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot |
||||
{ |
{ |
||||
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot |
public EfRepository(CatalogContext dbContext) : base(dbContext) |
||||
{ |
{ |
||||
public EfRepository(CatalogContext dbContext) : base(dbContext) |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,12 +1,11 @@ |
|||||
namespace Microsoft.eShopWeb.Infrastructure.Data |
namespace Microsoft.eShopWeb.Infrastructure.Data; |
||||
|
|
||||
|
public class FileItem |
||||
{ |
{ |
||||
public class FileItem |
public string FileName { get; set; } |
||||
{ |
public string Url { get; set; } |
||||
public string FileName { get; set; } |
public long Size { get; set; } |
||||
public string Url { get; set; } |
public string Ext { get; set; } |
||||
public long Size { get; set; } |
public string Type { get; set; } |
||||
public string Ext { get; set; } |
public string DataBase64 { get; set; } |
||||
public string Type { get; set; } |
} |
||||
public string DataBase64 { get; set; } |
|
||||
} |
|
||||
} |
|
||||
|
|||||
@ -1,207 +1,206 @@ |
|||||
using System; |
using System; |
||||
using Microsoft.EntityFrameworkCore.Migrations; |
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data.Migrations |
namespace Microsoft.eShopWeb.Infrastructure.Data.Migrations; |
||||
|
|
||||
|
public partial class InitialModel : Migration |
||||
{ |
{ |
||||
public partial class InitialModel : Migration |
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.CreateSequence( |
||||
|
name: "catalog_brand_hilo", |
||||
|
incrementBy: 10); |
||||
|
|
||||
|
migrationBuilder.CreateSequence( |
||||
|
name: "catalog_hilo", |
||||
|
incrementBy: 10); |
||||
|
|
||||
|
migrationBuilder.CreateSequence( |
||||
|
name: "catalog_type_hilo", |
||||
|
incrementBy: 10); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "Baskets", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false) |
||||
|
.Annotation("SqlServer:Identity", "1, 1"), |
||||
|
BuyerId = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_Baskets", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "CatalogBrands", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false), |
||||
|
Brand = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_CatalogBrands", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "CatalogTypes", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false), |
||||
|
Type = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_CatalogTypes", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "Orders", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false) |
||||
|
.Annotation("SqlServer:Identity", "1, 1"), |
||||
|
BuyerId = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
OrderDate = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false), |
||||
|
ShipToAddress_Street = table.Column<string>(type: "nvarchar(180)", maxLength: 180, nullable: true), |
||||
|
ShipToAddress_City = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true), |
||||
|
ShipToAddress_State = table.Column<string>(type: "nvarchar(60)", maxLength: 60, nullable: true), |
||||
|
ShipToAddress_Country = table.Column<string>(type: "nvarchar(90)", maxLength: 90, nullable: true), |
||||
|
ShipToAddress_ZipCode = table.Column<string>(type: "nvarchar(18)", maxLength: 18, nullable: true) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_Orders", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "BasketItems", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false) |
||||
|
.Annotation("SqlServer:Identity", "1, 1"), |
||||
|
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
||||
|
Quantity = table.Column<int>(type: "int", nullable: false), |
||||
|
CatalogItemId = table.Column<int>(type: "int", nullable: false), |
||||
|
BasketId = table.Column<int>(type: "int", nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_BasketItems", x => x.Id); |
||||
|
table.ForeignKey( |
||||
|
name: "FK_BasketItems_Baskets_BasketId", |
||||
|
column: x => x.BasketId, |
||||
|
principalTable: "Baskets", |
||||
|
principalColumn: "Id", |
||||
|
onDelete: ReferentialAction.Cascade); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "Catalog", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false), |
||||
|
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), |
||||
|
Description = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
||||
|
PictureUri = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
CatalogTypeId = table.Column<int>(type: "int", nullable: false), |
||||
|
CatalogBrandId = table.Column<int>(type: "int", nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_Catalog", x => x.Id); |
||||
|
table.ForeignKey( |
||||
|
name: "FK_Catalog_CatalogBrands_CatalogBrandId", |
||||
|
column: x => x.CatalogBrandId, |
||||
|
principalTable: "CatalogBrands", |
||||
|
principalColumn: "Id", |
||||
|
onDelete: ReferentialAction.Cascade); |
||||
|
table.ForeignKey( |
||||
|
name: "FK_Catalog_CatalogTypes_CatalogTypeId", |
||||
|
column: x => x.CatalogTypeId, |
||||
|
principalTable: "CatalogTypes", |
||||
|
principalColumn: "Id", |
||||
|
onDelete: ReferentialAction.Cascade); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "OrderItems", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<int>(type: "int", nullable: false) |
||||
|
.Annotation("SqlServer:Identity", "1, 1"), |
||||
|
ItemOrdered_CatalogItemId = table.Column<int>(type: "int", nullable: true), |
||||
|
ItemOrdered_ProductName = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true), |
||||
|
ItemOrdered_PictureUri = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
||||
|
Units = table.Column<int>(type: "int", nullable: false), |
||||
|
OrderId = table.Column<int>(type: "int", nullable: true) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_OrderItems", x => x.Id); |
||||
|
table.ForeignKey( |
||||
|
name: "FK_OrderItems_Orders_OrderId", |
||||
|
column: x => x.OrderId, |
||||
|
principalTable: "Orders", |
||||
|
principalColumn: "Id", |
||||
|
onDelete: ReferentialAction.Restrict); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_BasketItems_BasketId", |
||||
|
table: "BasketItems", |
||||
|
column: "BasketId"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_Catalog_CatalogBrandId", |
||||
|
table: "Catalog", |
||||
|
column: "CatalogBrandId"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_Catalog_CatalogTypeId", |
||||
|
table: "Catalog", |
||||
|
column: "CatalogTypeId"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_OrderItems_OrderId", |
||||
|
table: "OrderItems", |
||||
|
column: "OrderId"); |
||||
|
} |
||||
|
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
migrationBuilder.DropTable( |
||||
{ |
name: "BasketItems"); |
||||
migrationBuilder.CreateSequence( |
|
||||
name: "catalog_brand_hilo", |
migrationBuilder.DropTable( |
||||
incrementBy: 10); |
name: "Catalog"); |
||||
|
|
||||
migrationBuilder.CreateSequence( |
migrationBuilder.DropTable( |
||||
name: "catalog_hilo", |
name: "OrderItems"); |
||||
incrementBy: 10); |
|
||||
|
migrationBuilder.DropTable( |
||||
migrationBuilder.CreateSequence( |
name: "Baskets"); |
||||
name: "catalog_type_hilo", |
|
||||
incrementBy: 10); |
migrationBuilder.DropTable( |
||||
|
name: "CatalogBrands"); |
||||
migrationBuilder.CreateTable( |
|
||||
name: "Baskets", |
migrationBuilder.DropTable( |
||||
columns: table => new |
name: "CatalogTypes"); |
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false) |
migrationBuilder.DropTable( |
||||
.Annotation("SqlServer:Identity", "1, 1"), |
name: "Orders"); |
||||
BuyerId = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false) |
|
||||
}, |
migrationBuilder.DropSequence( |
||||
constraints: table => |
name: "catalog_brand_hilo"); |
||||
{ |
|
||||
table.PrimaryKey("PK_Baskets", x => x.Id); |
migrationBuilder.DropSequence( |
||||
}); |
name: "catalog_hilo"); |
||||
|
|
||||
migrationBuilder.CreateTable( |
migrationBuilder.DropSequence( |
||||
name: "CatalogBrands", |
name: "catalog_type_hilo"); |
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false), |
|
||||
Brand = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_CatalogBrands", x => x.Id); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateTable( |
|
||||
name: "CatalogTypes", |
|
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false), |
|
||||
Type = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_CatalogTypes", x => x.Id); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateTable( |
|
||||
name: "Orders", |
|
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false) |
|
||||
.Annotation("SqlServer:Identity", "1, 1"), |
|
||||
BuyerId = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|
||||
OrderDate = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false), |
|
||||
ShipToAddress_Street = table.Column<string>(type: "nvarchar(180)", maxLength: 180, nullable: true), |
|
||||
ShipToAddress_City = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true), |
|
||||
ShipToAddress_State = table.Column<string>(type: "nvarchar(60)", maxLength: 60, nullable: true), |
|
||||
ShipToAddress_Country = table.Column<string>(type: "nvarchar(90)", maxLength: 90, nullable: true), |
|
||||
ShipToAddress_ZipCode = table.Column<string>(type: "nvarchar(18)", maxLength: 18, nullable: true) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_Orders", x => x.Id); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateTable( |
|
||||
name: "BasketItems", |
|
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false) |
|
||||
.Annotation("SqlServer:Identity", "1, 1"), |
|
||||
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
|
||||
Quantity = table.Column<int>(type: "int", nullable: false), |
|
||||
CatalogItemId = table.Column<int>(type: "int", nullable: false), |
|
||||
BasketId = table.Column<int>(type: "int", nullable: false) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_BasketItems", x => x.Id); |
|
||||
table.ForeignKey( |
|
||||
name: "FK_BasketItems_Baskets_BasketId", |
|
||||
column: x => x.BasketId, |
|
||||
principalTable: "Baskets", |
|
||||
principalColumn: "Id", |
|
||||
onDelete: ReferentialAction.Cascade); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateTable( |
|
||||
name: "Catalog", |
|
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false), |
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), |
|
||||
Description = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|
||||
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
|
||||
PictureUri = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|
||||
CatalogTypeId = table.Column<int>(type: "int", nullable: false), |
|
||||
CatalogBrandId = table.Column<int>(type: "int", nullable: false) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_Catalog", x => x.Id); |
|
||||
table.ForeignKey( |
|
||||
name: "FK_Catalog_CatalogBrands_CatalogBrandId", |
|
||||
column: x => x.CatalogBrandId, |
|
||||
principalTable: "CatalogBrands", |
|
||||
principalColumn: "Id", |
|
||||
onDelete: ReferentialAction.Cascade); |
|
||||
table.ForeignKey( |
|
||||
name: "FK_Catalog_CatalogTypes_CatalogTypeId", |
|
||||
column: x => x.CatalogTypeId, |
|
||||
principalTable: "CatalogTypes", |
|
||||
principalColumn: "Id", |
|
||||
onDelete: ReferentialAction.Cascade); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateTable( |
|
||||
name: "OrderItems", |
|
||||
columns: table => new |
|
||||
{ |
|
||||
Id = table.Column<int>(type: "int", nullable: false) |
|
||||
.Annotation("SqlServer:Identity", "1, 1"), |
|
||||
ItemOrdered_CatalogItemId = table.Column<int>(type: "int", nullable: true), |
|
||||
ItemOrdered_ProductName = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true), |
|
||||
ItemOrdered_PictureUri = table.Column<string>(type: "nvarchar(max)", nullable: true), |
|
||||
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false), |
|
||||
Units = table.Column<int>(type: "int", nullable: false), |
|
||||
OrderId = table.Column<int>(type: "int", nullable: true) |
|
||||
}, |
|
||||
constraints: table => |
|
||||
{ |
|
||||
table.PrimaryKey("PK_OrderItems", x => x.Id); |
|
||||
table.ForeignKey( |
|
||||
name: "FK_OrderItems_Orders_OrderId", |
|
||||
column: x => x.OrderId, |
|
||||
principalTable: "Orders", |
|
||||
principalColumn: "Id", |
|
||||
onDelete: ReferentialAction.Restrict); |
|
||||
}); |
|
||||
|
|
||||
migrationBuilder.CreateIndex( |
|
||||
name: "IX_BasketItems_BasketId", |
|
||||
table: "BasketItems", |
|
||||
column: "BasketId"); |
|
||||
|
|
||||
migrationBuilder.CreateIndex( |
|
||||
name: "IX_Catalog_CatalogBrandId", |
|
||||
table: "Catalog", |
|
||||
column: "CatalogBrandId"); |
|
||||
|
|
||||
migrationBuilder.CreateIndex( |
|
||||
name: "IX_Catalog_CatalogTypeId", |
|
||||
table: "Catalog", |
|
||||
column: "CatalogTypeId"); |
|
||||
|
|
||||
migrationBuilder.CreateIndex( |
|
||||
name: "IX_OrderItems_OrderId", |
|
||||
table: "OrderItems", |
|
||||
column: "OrderId"); |
|
||||
} |
|
||||
|
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
|
||||
{ |
|
||||
migrationBuilder.DropTable( |
|
||||
name: "BasketItems"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "Catalog"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "OrderItems"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "Baskets"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "CatalogBrands"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "CatalogTypes"); |
|
||||
|
|
||||
migrationBuilder.DropTable( |
|
||||
name: "Orders"); |
|
||||
|
|
||||
migrationBuilder.DropSequence( |
|
||||
name: "catalog_brand_hilo"); |
|
||||
|
|
||||
migrationBuilder.DropSequence( |
|
||||
name: "catalog_hilo"); |
|
||||
|
|
||||
migrationBuilder.DropSequence( |
|
||||
name: "catalog_type_hilo"); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,53 +1,52 @@ |
|||||
using Microsoft.EntityFrameworkCore.Migrations; |
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data.Migrations |
namespace Microsoft.eShopWeb.Infrastructure.Data.Migrations; |
||||
|
|
||||
|
public partial class FixBuyerId : Migration |
||||
{ |
{ |
||||
public partial class FixBuyerId : Migration |
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
migrationBuilder.AlterColumn<string>( |
||||
{ |
name: "BuyerId", |
||||
migrationBuilder.AlterColumn<string>( |
table: "Orders", |
||||
name: "BuyerId", |
type: "nvarchar(256)", |
||||
table: "Orders", |
maxLength: 256, |
||||
type: "nvarchar(256)", |
nullable: false, |
||||
maxLength: 256, |
defaultValue: "", |
||||
nullable: false, |
oldClrType: typeof(string), |
||||
defaultValue: "", |
oldType: "nvarchar(max)", |
||||
oldClrType: typeof(string), |
oldNullable: true); |
||||
oldType: "nvarchar(max)", |
|
||||
oldNullable: true); |
|
||||
|
|
||||
migrationBuilder.AlterColumn<string>( |
migrationBuilder.AlterColumn<string>( |
||||
name: "BuyerId", |
name: "BuyerId", |
||||
table: "Baskets", |
table: "Baskets", |
||||
type: "nvarchar(256)", |
type: "nvarchar(256)", |
||||
maxLength: 256, |
maxLength: 256, |
||||
nullable: false, |
nullable: false, |
||||
oldClrType: typeof(string), |
oldClrType: typeof(string), |
||||
oldType: "nvarchar(40)", |
oldType: "nvarchar(40)", |
||||
oldMaxLength: 40); |
oldMaxLength: 40); |
||||
} |
} |
||||
|
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
{ |
||||
migrationBuilder.AlterColumn<string>( |
migrationBuilder.AlterColumn<string>( |
||||
name: "BuyerId", |
name: "BuyerId", |
||||
table: "Orders", |
table: "Orders", |
||||
type: "nvarchar(max)", |
type: "nvarchar(max)", |
||||
nullable: true, |
nullable: true, |
||||
oldClrType: typeof(string), |
oldClrType: typeof(string), |
||||
oldType: "nvarchar(256)", |
oldType: "nvarchar(256)", |
||||
oldMaxLength: 256); |
oldMaxLength: 256); |
||||
|
|
||||
migrationBuilder.AlterColumn<string>( |
migrationBuilder.AlterColumn<string>( |
||||
name: "BuyerId", |
name: "BuyerId", |
||||
table: "Baskets", |
table: "Baskets", |
||||
type: "nvarchar(40)", |
type: "nvarchar(40)", |
||||
maxLength: 40, |
maxLength: 40, |
||||
nullable: false, |
nullable: false, |
||||
oldClrType: typeof(string), |
oldClrType: typeof(string), |
||||
oldType: "nvarchar(256)", |
oldType: "nvarchar(256)", |
||||
oldMaxLength: 256); |
oldMaxLength: 256); |
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue