Browse Source
* Updating Blazor services * Adding Settings and Refactoring Services * WIP - Fighting with DI * Configuring dependencies in both Web Startup and BlazorAdmin Program.cs has them working again. * Everything works; need to optimize calls to ListBrands * LocalStorageBrandService decorator working * Added cache duration of 1 minute * Refactoring to reduce token storage Fixed issue with dropdowns binding to int * Remove token stuff from login; moved to CustomAuthStateProvider * Migrated CatalogTypes to separate service Implemented cache decorator * Ardalis/blazor refactor (#440) * 1. Migrate CatalogItemServices -> CatalogItemService. 3. Add caching to CatalogItemService. * change to $"Loading {key} from local storage" ? * docker settings added. (#441) * docker settings added. * InDocker Removed * InDocker removed from web startup. * removed unused using * no reload list if close without save * startup patch for localhost * file name fixed * removed docker from launchSettings. * Configure logging via appsettings Co-authored-by: Shady Nagy <info@shadynagy.com>main
committed by
GitHub
77 changed files with 866 additions and 534 deletions
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CacheEntry<T> |
||||
|
{ |
||||
|
public CacheEntry(T item) |
||||
|
{ |
||||
|
Value = item; |
||||
|
} |
||||
|
public CacheEntry() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public T Value { get; set; } |
||||
|
public DateTime DateCreated { get; set; } = DateTime.UtcNow; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
using Blazored.LocalStorage; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CachedCatalogBrandServiceDecorator : ICatalogBrandService |
||||
|
{ |
||||
|
// TODO: Make a generic decorator for any LookupData type
|
||||
|
private readonly ILocalStorageService _localStorageService; |
||||
|
private readonly CatalogBrandService _catalogBrandService; |
||||
|
private ILogger<CachedCatalogBrandServiceDecorator> _logger; |
||||
|
|
||||
|
public CachedCatalogBrandServiceDecorator(ILocalStorageService localStorageService, |
||||
|
CatalogBrandService catalogBrandService, |
||||
|
ILogger<CachedCatalogBrandServiceDecorator> logger) |
||||
|
{ |
||||
|
_localStorageService = localStorageService; |
||||
|
_catalogBrandService = catalogBrandService; |
||||
|
_logger = logger; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogBrand> GetById(int id) |
||||
|
{ |
||||
|
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogBrand>> List() |
||||
|
{ |
||||
|
string key = "brands"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogBrand>>>(key); |
||||
|
if (cacheEntry != null) |
||||
|
{ |
||||
|
_logger.LogInformation("Loading brands from local storage."); |
||||
|
// TODO: Get Default Cache Duration from Config
|
||||
|
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
|
{ |
||||
|
return cacheEntry.Value; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_logger.LogInformation("Cache expired; removing brands from local storage."); |
||||
|
await _localStorageService.RemoveItemAsync(key); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var brands = await _catalogBrandService.List(); |
||||
|
var entry = new CacheEntry<List<CatalogBrand>>(brands); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
|
return brands; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,114 @@ |
|||||
|
using Blazored.LocalStorage; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CachedCatalogItemServiceDecorator : ICatalogItemService |
||||
|
{ |
||||
|
private readonly ILocalStorageService _localStorageService; |
||||
|
private readonly CatalogItemService _catalogItemService; |
||||
|
private ILogger<CachedCatalogItemServiceDecorator> _logger; |
||||
|
|
||||
|
public CachedCatalogItemServiceDecorator(ILocalStorageService localStorageService, |
||||
|
CatalogItemService catalogItemService, |
||||
|
ILogger<CachedCatalogItemServiceDecorator> logger) |
||||
|
{ |
||||
|
_localStorageService = localStorageService; |
||||
|
_catalogItemService = catalogItemService; |
||||
|
_logger = logger; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogItem>> ListPaged(int pageSize) |
||||
|
{ |
||||
|
string key = "items"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
||||
|
if (cacheEntry != null) |
||||
|
{ |
||||
|
_logger.LogInformation("Loading items from local storage."); |
||||
|
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
|
{ |
||||
|
return cacheEntry.Value; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_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() |
||||
|
{ |
||||
|
string key = "items"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogItem>>>(key); |
||||
|
if (cacheEntry != null) |
||||
|
{ |
||||
|
_logger.LogInformation("Loading items from local storage."); |
||||
|
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
|
{ |
||||
|
return cacheEntry.Value; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_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) |
||||
|
{ |
||||
|
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
||||
|
{ |
||||
|
var result = await _catalogItemService.Create(catalogItem); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
||||
|
{ |
||||
|
var result = await _catalogItemService.Edit(catalogItem); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public async Task<string> Delete(int id) |
||||
|
{ |
||||
|
var result = await _catalogItemService.Delete(id); |
||||
|
await RefreshLocalStorageList(); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private async Task RefreshLocalStorageList() |
||||
|
{ |
||||
|
string key = "items"; |
||||
|
|
||||
|
await _localStorageService.RemoveItemAsync(key); |
||||
|
var items = await _catalogItemService.List(); |
||||
|
var entry = new CacheEntry<List<CatalogItem>>(items); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using Blazored.LocalStorage; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CachedCatalogTypeServiceDecorator : ICatalogTypeService |
||||
|
{ |
||||
|
// TODO: Make a generic decorator for any LookupData type
|
||||
|
private readonly ILocalStorageService _localStorageService; |
||||
|
private readonly CatalogTypeService _catalogTypeService; |
||||
|
private ILogger<CachedCatalogTypeServiceDecorator> _logger; |
||||
|
|
||||
|
public CachedCatalogTypeServiceDecorator(ILocalStorageService localStorageService, |
||||
|
CatalogTypeService catalogTypeService, |
||||
|
ILogger<CachedCatalogTypeServiceDecorator> logger) |
||||
|
{ |
||||
|
_localStorageService = localStorageService; |
||||
|
_catalogTypeService = catalogTypeService; |
||||
|
_logger = logger; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogType> GetById(int id) |
||||
|
{ |
||||
|
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogType>> List() |
||||
|
{ |
||||
|
string key = "types"; |
||||
|
var cacheEntry = await _localStorageService.GetItemAsync<CacheEntry<List<CatalogType>>>(key); |
||||
|
if (cacheEntry != null) |
||||
|
{ |
||||
|
_logger.LogInformation("Loading types from local storage."); |
||||
|
if (cacheEntry.DateCreated.AddMinutes(1) > DateTime.UtcNow) |
||||
|
{ |
||||
|
return cacheEntry.Value; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_logger.LogInformation("Cache expired; removing types from local storage."); |
||||
|
await _localStorageService.RemoveItemAsync(key); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var types = await _catalogTypeService.List(); |
||||
|
var entry = new CacheEntry<List<CatalogType>>(types); |
||||
|
await _localStorageService.SetItemAsync(key, entry); |
||||
|
return types; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using BlazorShared; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Http.Json; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CatalogBrandService : ICatalogBrandService |
||||
|
{ |
||||
|
// TODO: Make a generic service for any LookupData type
|
||||
|
private readonly HttpClient _httpClient; |
||||
|
private readonly ILogger<CatalogBrandService> _logger; |
||||
|
private string _apiUrl; |
||||
|
|
||||
|
public CatalogBrandService(HttpClient httpClient, |
||||
|
BaseUrlConfiguration baseUrlConfiguration, |
||||
|
ILogger<CatalogBrandService> logger) |
||||
|
{ |
||||
|
_httpClient = httpClient; |
||||
|
_logger = logger; |
||||
|
_apiUrl = baseUrlConfiguration.ApiBase; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogBrand> GetById(int id) |
||||
|
{ |
||||
|
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogBrand>> List() |
||||
|
{ |
||||
|
_logger.LogInformation("Fetching brands from API."); |
||||
|
return (await _httpClient.GetFromJsonAsync<CatalogBrandResponse>($"{_apiUrl}catalog-brands"))?.CatalogBrands; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,8 +0,0 @@ |
|||||
namespace BlazorAdmin.Services.CatalogBrandServices |
|
||||
{ |
|
||||
public class CatalogBrand |
|
||||
{ |
|
||||
public int Id { get; set; } |
|
||||
public string Name { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Net.Http; |
|
||||
using System.Net.Http.Json; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogBrandServices |
|
||||
{ |
|
||||
public class List |
|
||||
{ |
|
||||
private readonly AuthService _authService; |
|
||||
private readonly HttpClient _httpClient; |
|
||||
|
|
||||
public List(AuthService authService, HttpClient httpClient) |
|
||||
{ |
|
||||
_authService = authService; |
|
||||
_httpClient = httpClient; |
|
||||
} |
|
||||
|
|
||||
public async Task<List<CatalogBrand>> HandleAsync() |
|
||||
{ |
|
||||
return (await _httpClient.GetFromJsonAsync<CatalogBrandResult>($"{_authService.ApiUrl}catalog-brands"))?.CatalogBrands; |
|
||||
} |
|
||||
|
|
||||
public static string GetBrandName(IEnumerable<CatalogBrand> brands, int brandId) |
|
||||
{ |
|
||||
var type = brands.FirstOrDefault(t => t.Id == brandId); |
|
||||
|
|
||||
return type == null ? "None" : type.Name; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,102 @@ |
|||||
|
using BlazorShared; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CatalogItemService : ICatalogItemService |
||||
|
{ |
||||
|
private readonly ICatalogBrandService _brandService; |
||||
|
private readonly ICatalogTypeService _typeService; |
||||
|
private readonly HttpService _httpService; |
||||
|
private readonly ILogger<CatalogItemService> _logger; |
||||
|
private string _apiUrl; |
||||
|
|
||||
|
public CatalogItemService(ICatalogBrandService brandService, |
||||
|
ICatalogTypeService typeService, |
||||
|
HttpService httpService, |
||||
|
BaseUrlConfiguration baseUrlConfiguration, |
||||
|
ILogger<CatalogItemService> logger) |
||||
|
{ |
||||
|
_brandService = brandService; |
||||
|
_typeService = typeService; |
||||
|
|
||||
|
_httpService = httpService; |
||||
|
_logger = logger; |
||||
|
_apiUrl = baseUrlConfiguration.ApiBase; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem) |
||||
|
{ |
||||
|
return (await _httpService.HttpPost<CreateCatalogItemResponse>("catalog-items", catalogItem)).CatalogItem; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogItem> Edit(CatalogItem catalogItem) |
||||
|
{ |
||||
|
return (await _httpService.HttpPut<EditCatalogItemResult>("catalog-items", catalogItem)).CatalogItem; |
||||
|
} |
||||
|
|
||||
|
public async Task<string> Delete(int catalogItemId) |
||||
|
{ |
||||
|
return (await _httpService.HttpDelete<DeleteCatalogItemResponse>("catalog-items", catalogItemId)).Status; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogItem> GetById(int id) |
||||
|
{ |
||||
|
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<List<CatalogItem>> ListPaged(int pageSize) |
||||
|
{ |
||||
|
_logger.LogInformation("Fetching catalog items from API."); |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogItem>> List() |
||||
|
{ |
||||
|
_logger.LogInformation("Fetching catalog items from API."); |
||||
|
|
||||
|
var brandListTask = _brandService.List(); |
||||
|
var typeListTask = _typeService.List(); |
||||
|
//TODO: Need to change the api to support full list
|
||||
|
var itemListTask = _httpService.HttpGet<PagedCatalogItemResponse>($"catalog-items?PageSize=100"); |
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,7 +0,0 @@ |
|||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class CreateCatalogItemResult |
|
||||
{ |
|
||||
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class Create |
|
||||
{ |
|
||||
private readonly HttpService _httpService; |
|
||||
|
|
||||
public Create(AuthService authService) |
|
||||
{ |
|
||||
_httpService = new HttpService(authService.GetHttpClient(), authService.ApiUrl); |
|
||||
} |
|
||||
|
|
||||
public async Task<CatalogItem> HandleAsync(CreateCatalogItemRequest catalogItem) |
|
||||
{ |
|
||||
return (await _httpService.HttpPost<CreateCatalogItemResult>("catalog-items", catalogItem)).CatalogItem; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class DeleteCatalogItemResult |
|
||||
{ |
|
||||
public string Status { get; set; } = "Deleted"; |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class Delete |
|
||||
{ |
|
||||
private readonly HttpService _httpService; |
|
||||
|
|
||||
public Delete(AuthService authService) |
|
||||
{ |
|
||||
_httpService = new HttpService(authService.GetHttpClient(), authService.ApiUrl); |
|
||||
} |
|
||||
|
|
||||
public async Task<string> HandleAsync(int catalogItemId) |
|
||||
{ |
|
||||
return (await _httpService.HttpDelete<DeleteCatalogItemResult>("catalog-items", catalogItemId)).Status; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class Edit |
|
||||
{ |
|
||||
private readonly HttpService _httpService; |
|
||||
|
|
||||
public Edit(AuthService authService) |
|
||||
{ |
|
||||
_httpService = new HttpService(authService.GetHttpClient(), authService.ApiUrl); |
|
||||
} |
|
||||
|
|
||||
public async Task<CatalogItem> HandleAsync(CatalogItem catalogItem) |
|
||||
{ |
|
||||
return (await _httpService.HttpPut<EditCatalogItemResult>("catalog-items", catalogItem)).CatalogItem; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class GetByIdCatalogItemResult |
|
||||
{ |
|
||||
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class GetById |
|
||||
{ |
|
||||
private readonly HttpService _httpService; |
|
||||
|
|
||||
public GetById(AuthService authService) |
|
||||
{ |
|
||||
_httpService = new HttpService(authService.GetHttpClient(), authService.ApiUrl); |
|
||||
} |
|
||||
|
|
||||
public async Task<CatalogItem> HandleAsync(int catalogItemId) |
|
||||
{ |
|
||||
return (await _httpService.HttpGet<EditCatalogItemResult>($"catalog-items/{catalogItemId}")).CatalogItem; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,21 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
|
||||
{ |
|
||||
public class ListPaged |
|
||||
{ |
|
||||
private readonly HttpService _httpService; |
|
||||
|
|
||||
public ListPaged(AuthService authService) |
|
||||
{ |
|
||||
_httpService = new HttpService(authService.GetHttpClient(), authService.ApiUrl); |
|
||||
} |
|
||||
|
|
||||
public async Task<List<CatalogItem>> HandleAsync(int pageSize) |
|
||||
{ |
|
||||
return (await _httpService.HttpGet<PagedCatalogItemResult>($"catalog-items?PageSize={pageSize}")).CatalogItems; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,40 @@ |
|||||
|
using BlazorShared; |
||||
|
using BlazorShared.Interfaces; |
||||
|
using BlazorShared.Models; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Http.Json; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace BlazorAdmin.Services |
||||
|
{ |
||||
|
public class CatalogTypeService : ICatalogTypeService |
||||
|
{ |
||||
|
// TODO: Make a generic service for any LookupData type
|
||||
|
private readonly HttpClient _httpClient; |
||||
|
private readonly ILogger<CatalogTypeService> _logger; |
||||
|
private string _apiUrl; |
||||
|
|
||||
|
public CatalogTypeService(HttpClient httpClient, |
||||
|
BaseUrlConfiguration baseUrlConfiguration, |
||||
|
ILogger<CatalogTypeService> logger) |
||||
|
{ |
||||
|
_httpClient = httpClient; |
||||
|
_logger = logger; |
||||
|
_apiUrl = baseUrlConfiguration.ApiBase; |
||||
|
} |
||||
|
|
||||
|
public async Task<CatalogType> GetById(int id) |
||||
|
{ |
||||
|
return (await List()).FirstOrDefault(x => x.Id == id); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<CatalogType>> List() |
||||
|
{ |
||||
|
_logger.LogInformation("Fetching types from API."); |
||||
|
return (await _httpClient.GetFromJsonAsync<CatalogTypeResponse>($"{_apiUrl}catalog-types"))?.CatalogTypes; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,8 +0,0 @@ |
|||||
namespace BlazorAdmin.Services.CatalogTypeServices |
|
||||
{ |
|
||||
public class CatalogType |
|
||||
{ |
|
||||
public int Id { get; set; } |
|
||||
public string Name { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Net.Http; |
|
||||
using System.Net.Http.Json; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogTypeServices |
|
||||
{ |
|
||||
public class List |
|
||||
{ |
|
||||
private readonly AuthService _authService; |
|
||||
private readonly HttpClient _httpClient; |
|
||||
|
|
||||
public List(AuthService authService, HttpClient httpClient) |
|
||||
{ |
|
||||
_authService = authService; |
|
||||
_httpClient = httpClient; |
|
||||
} |
|
||||
|
|
||||
public async Task<List<CatalogType>> HandleAsync() |
|
||||
{ |
|
||||
return (await _httpClient.GetFromJsonAsync<CatalogTypeResult>($"{_authService.ApiUrl}catalog-types"))?.CatalogTypes; |
|
||||
} |
|
||||
|
|
||||
public static string GetTypeName(IEnumerable<CatalogType> types, int typeId) |
|
||||
{ |
|
||||
var type = types.FirstOrDefault(t => t.Id == typeId); |
|
||||
|
|
||||
return type == null ? "None" : type.Name; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -1,22 +1,21 @@ |
|||||
using BlazorAdmin.Services.CatalogItemServices; |
using BlazorAdmin.Services; |
||||
|
using BlazorShared.Interfaces; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
namespace BlazorAdmin |
namespace BlazorAdmin |
||||
{ |
{ |
||||
public static class ServicesConfiguration |
public static class ServicesConfiguration |
||||
{ |
{ |
||||
public static IServiceCollection AddBlazorServices(this IServiceCollection service) |
public static IServiceCollection AddBlazorServices(this IServiceCollection services) |
||||
{ |
{ |
||||
service.AddScoped<Create>(); |
services.AddScoped<ICatalogBrandService, CachedCatalogBrandServiceDecorator>(); |
||||
service.AddScoped<ListPaged>(); |
services.AddScoped<CatalogBrandService>(); |
||||
service.AddScoped<Delete>(); |
services.AddScoped<ICatalogTypeService, CachedCatalogTypeServiceDecorator>(); |
||||
service.AddScoped<Edit>(); |
services.AddScoped<CatalogTypeService>(); |
||||
service.AddScoped<GetById>(); |
services.AddScoped<ICatalogItemService, CachedCatalogItemServiceDecorator>(); |
||||
|
services.AddScoped<CatalogItemService>(); |
||||
|
|
||||
service.AddScoped<BlazorAdmin.Services.CatalogBrandServices.List>(); |
return services; |
||||
service.AddScoped<BlazorAdmin.Services.CatalogTypeServices.List>(); |
|
||||
|
|
||||
return service; |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,38 @@ |
|||||
|
using Microsoft.AspNetCore.Components.Forms; |
||||
|
|
||||
|
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> |
||||
|
{ |
||||
|
protected override bool TryParseValueFromString(string value, out TValue result, |
||||
|
out string validationErrorMessage) |
||||
|
{ |
||||
|
if (typeof(TValue) == typeof(int)) |
||||
|
{ |
||||
|
if (int.TryParse(value, out var resultInt)) |
||||
|
{ |
||||
|
result = (TValue)(object)resultInt; |
||||
|
validationErrorMessage = null; |
||||
|
return true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
result = default; |
||||
|
validationErrorMessage = |
||||
|
$"The selected value {value} is not a valid number."; |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return base.TryParseValueFromString(value, out result, |
||||
|
out validationErrorMessage); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"baseUrls": { |
||||
|
"apiBase": "http://localhost:5200/api/", |
||||
|
"webBase": "http://host.docker.internal:5106/" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
{ |
||||
|
"baseUrls": { |
||||
|
"apiBase": "https://localhost:5099/api/", |
||||
|
"webBase": "https://localhost:44315/" |
||||
|
}, |
||||
|
"Logging": { |
||||
|
"IncludeScopes": false, |
||||
|
"LogLevel": { |
||||
|
"Default": "Information", |
||||
|
"Microsoft": "Warning", |
||||
|
"System": "Warning" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,27 +0,0 @@ |
|||||
[ |
|
||||
{ |
|
||||
"date": "2018-05-06", |
|
||||
"temperatureC": 1, |
|
||||
"summary": "Freezing" |
|
||||
}, |
|
||||
{ |
|
||||
"date": "2018-05-07", |
|
||||
"temperatureC": 14, |
|
||||
"summary": "Bracing" |
|
||||
}, |
|
||||
{ |
|
||||
"date": "2018-05-08", |
|
||||
"temperatureC": -13, |
|
||||
"summary": "Freezing" |
|
||||
}, |
|
||||
{ |
|
||||
"date": "2018-05-09", |
|
||||
"temperatureC": -16, |
|
||||
"summary": "Balmy" |
|
||||
}, |
|
||||
{ |
|
||||
"date": "2018-05-10", |
|
||||
"temperatureC": -2, |
|
||||
"summary": "Chilly" |
|
||||
} |
|
||||
] |
|
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace BlazorShared |
||||
|
{ |
||||
|
public class BaseUrlConfiguration |
||||
|
{ |
||||
|
public const string CONFIG_NAME = "baseUrls"; |
||||
|
|
||||
|
public string ApiBase { get; set; } |
||||
|
public string WebBase { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using BlazorShared.Models; |
||||
|
|
||||
|
namespace BlazorShared.Interfaces |
||||
|
{ |
||||
|
public interface ICatalogBrandService |
||||
|
{ |
||||
|
Task<List<CatalogBrand>> List(); |
||||
|
Task<CatalogBrand> GetById(int id); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using BlazorShared.Models; |
||||
|
|
||||
|
namespace BlazorShared.Interfaces |
||||
|
{ |
||||
|
public interface ICatalogItemService |
||||
|
{ |
||||
|
Task<CatalogItem> Create(CreateCatalogItemRequest catalogItem); |
||||
|
Task<CatalogItem> Edit(CatalogItem catalogItem); |
||||
|
Task<string> Delete(int id); |
||||
|
Task<CatalogItem> GetById(int id); |
||||
|
Task<List<CatalogItem>> ListPaged(int pageSize); |
||||
|
Task<List<CatalogItem>> List(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using BlazorShared.Models; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace BlazorShared.Interfaces |
||||
|
{ |
||||
|
public interface ICatalogTypeService |
||||
|
{ |
||||
|
Task<List<CatalogType>> List(); |
||||
|
Task<CatalogType> GetById(int id); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace BlazorShared.Models |
||||
|
{ |
||||
|
public class CatalogBrand : LookupData |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,8 +1,8 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogBrandServices |
namespace BlazorShared.Models |
||||
{ |
{ |
||||
public class CatalogBrandResult |
public class CatalogBrandResponse |
||||
{ |
{ |
||||
public List<CatalogBrand> CatalogBrands { get; set; } = new List<CatalogBrand>(); |
public List<CatalogBrand> CatalogBrands { get; set; } = new List<CatalogBrand>(); |
||||
} |
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace BlazorShared.Models |
||||
|
{ |
||||
|
public class CatalogType : LookupData |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,8 +1,8 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogTypeServices |
namespace BlazorShared.Models |
||||
{ |
{ |
||||
public class CatalogTypeResult |
public class CatalogTypeResponse |
||||
{ |
{ |
||||
public List<CatalogType> CatalogTypes { get; set; } = new List<CatalogType>(); |
public List<CatalogType> CatalogTypes { get; set; } = new List<CatalogType>(); |
||||
} |
} |
||||
@ -1,6 +1,6 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
namespace BlazorShared.Models |
||||
{ |
{ |
||||
public class CreateCatalogItemRequest |
public class CreateCatalogItemRequest |
||||
{ |
{ |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace BlazorShared.Models |
||||
|
{ |
||||
|
public class CreateCatalogItemResponse |
||||
|
{ |
||||
|
public CatalogItem CatalogItem { get; set; } = new CatalogItem(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace BlazorShared.Models |
||||
|
{ |
||||
|
public class DeleteCatalogItemResponse |
||||
|
{ |
||||
|
public string Status { get; set; } = "Deleted"; |
||||
|
} |
||||
|
} |
||||
@ -1,4 +1,4 @@ |
|||||
namespace BlazorAdmin.Services.CatalogItemServices |
namespace BlazorShared.Models |
||||
{ |
{ |
||||
public class EditCatalogItemResult |
public class EditCatalogItemResult |
||||
{ |
{ |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace BlazorShared.Models |
||||
|
{ |
||||
|
public abstract class LookupData |
||||
|
{ |
||||
|
public int Id { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,8 +1,8 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace BlazorAdmin.Services.CatalogItemServices |
namespace BlazorShared.Models |
||||
{ |
{ |
||||
public class PagedCatalogItemResult |
public class PagedCatalogItemResponse |
||||
{ |
{ |
||||
public List<CatalogItem> CatalogItems { get; set; } = new List<CatalogItem>(); |
public List<CatalogItem> CatalogItems { get; set; } = new List<CatalogItem>(); |
||||
public int PageCount { get; set; } = 0; |
public int PageCount { get; set; } = 0; |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"ConnectionStrings": { |
||||
|
"CatalogConnection": "Server=(localdb)\\mssqllocaldb;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.CatalogDb;", |
||||
|
"IdentityConnection": "Server=(localdb)\\mssqllocaldb;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.Identity;" |
||||
|
}, |
||||
|
"baseUrls": { |
||||
|
"apiBase": "http://localhost:5200/api/", |
||||
|
"webBase": "http://host.docker.internal:5106/" |
||||
|
}, |
||||
|
"Logging": { |
||||
|
"LogLevel": { |
||||
|
"Default": "Information", |
||||
|
"Microsoft": "Warning", |
||||
|
"Microsoft.Hosting.Lifetime": "Information" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"ConnectionStrings": { |
||||
|
"CatalogConnection": "Server=(localdb)\\mssqllocaldb;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.CatalogDb;", |
||||
|
"IdentityConnection": "Server=(localdb)\\mssqllocaldb;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.Identity;" |
||||
|
}, |
||||
|
"baseUrls": { |
||||
|
"apiBase": "http://localhost:5200/api/", |
||||
|
"webBase": "http://host.docker.internal:5106/" |
||||
|
}, |
||||
|
"Logging": { |
||||
|
"LogLevel": { |
||||
|
"Default": "Debug", |
||||
|
"System": "Information", |
||||
|
"Microsoft": "Information" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 27 KiB |
Loading…
Reference in new issue