Compare commits
1 commit
dev
...
11-add-wis
| Author | SHA1 | Date | |
|---|---|---|---|
| e0cbf86fc8 |
16 changed files with 510 additions and 0 deletions
|
|
@ -6,8 +6,26 @@ namespace Wishlist.Data;
|
|||
|
||||
public class AppDataContext : IdentityDbContext<User>
|
||||
{
|
||||
|
||||
public DbSet<Entities.Wishlist> Wishlists { get; set; }
|
||||
public DbSet<Wish> Wishes { get; set; }
|
||||
public AppDataContext() { }
|
||||
|
||||
public AppDataContext(DbContextOptions<AppDataContext> options) : base(options) { }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
builder.Entity<Entities.Wishlist>()
|
||||
.HasMany(e => e.Wishes)
|
||||
.WithOne(e => e.Wishlist)
|
||||
.HasForeignKey(e => e.WishlistId)
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
builder.Entity<User>()
|
||||
.HasMany(e => e.Wishlists)
|
||||
.WithMany(e => e.Owners)
|
||||
.UsingEntity(j => j.ToTable("OwnerWishlists"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
using Wishlist.Data.Entities;
|
||||
|
||||
namespace Wishlist.Data;
|
||||
|
||||
public class Constants
|
||||
|
|
@ -7,4 +9,5 @@ public class Constants
|
|||
public const string MemberRole = "Member";
|
||||
// Static Readonly (Runtime const)
|
||||
public static readonly string[] Roles = [AdminRole, MemberRole];
|
||||
public static readonly CurrencyInfo DefaultCurrency = CurrencyInfo.DKK;
|
||||
}
|
||||
38
Wishlist/Data/Entities/CurrencyInfo.cs
Normal file
38
Wishlist/Data/Entities/CurrencyInfo.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public struct CurrencyInfo
|
||||
{
|
||||
public CurrencyInfo()
|
||||
{
|
||||
CurrencyCode = string.Empty;
|
||||
CurrencyName = string.Empty;
|
||||
Symbol = string.Empty;
|
||||
}
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
public static readonly CurrencyInfo DKK = new()
|
||||
{
|
||||
CurrencyCode = "DKK",
|
||||
CurrencyName = "Danish Crowns",
|
||||
Symbol = "Kr",
|
||||
};
|
||||
public static readonly CurrencyInfo EURO = new()
|
||||
{
|
||||
CurrencyCode = "EURO",
|
||||
CurrencyName = "Euros",
|
||||
Symbol = "€"
|
||||
};
|
||||
public static readonly CurrencyInfo USD = new()
|
||||
{
|
||||
CurrencyCode = "USD",
|
||||
CurrencyName = "US Dollars",
|
||||
Symbol = "$"
|
||||
};
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
|
||||
|
||||
public string CurrencyCode { get; set; }
|
||||
public string CurrencyName { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
}
|
||||
24
Wishlist/Data/Entities/PriceInfo.cs
Normal file
24
Wishlist/Data/Entities/PriceInfo.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public struct PriceInfo
|
||||
{
|
||||
public double Price { get; set; }
|
||||
public CurrencyInfo CurrencyInfo { get; set; }
|
||||
|
||||
public PriceInfo()
|
||||
{
|
||||
Price = 0;
|
||||
CurrencyInfo = new CurrencyInfo();
|
||||
}
|
||||
|
||||
public PriceInfo(double price)
|
||||
{
|
||||
Price = price;
|
||||
CurrencyInfo = new CurrencyInfo();
|
||||
}
|
||||
public PriceInfo(double price, CurrencyInfo currencyInfo)
|
||||
{
|
||||
Price = price;
|
||||
CurrencyInfo = currencyInfo;
|
||||
}
|
||||
}
|
||||
23
Wishlist/Data/Entities/ReserveStatus.cs
Normal file
23
Wishlist/Data/Entities/ReserveStatus.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public struct ReserveStatus
|
||||
{
|
||||
public User? ReserveUser { get; set; }
|
||||
|
||||
public static readonly ReserveStatus NotReserve = new ();
|
||||
|
||||
public ReserveStatus()
|
||||
{
|
||||
ReserveUser = null;
|
||||
}
|
||||
|
||||
public ReserveStatus(User? reserveUser)
|
||||
{
|
||||
ReserveUser = reserveUser;
|
||||
}
|
||||
|
||||
public bool IsReserved()
|
||||
{
|
||||
return ReserveUser is not null;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,5 +4,6 @@ namespace Wishlist.Data.Entities;
|
|||
|
||||
public class User : IdentityUser
|
||||
{
|
||||
public List<Wishlist> Wishlists { get; set; }
|
||||
|
||||
}
|
||||
31
Wishlist/Data/Entities/VisibilityStatus.cs
Normal file
31
Wishlist/Data/Entities/VisibilityStatus.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public struct VisibilityStatus
|
||||
{
|
||||
public VisibilityStatus() { }
|
||||
|
||||
public List<User> VisibleTo { get; set; } = [];
|
||||
public bool Published { get; set; }
|
||||
public bool Public { get; set; }
|
||||
|
||||
public bool IsVisibleForUSer(User user)
|
||||
{
|
||||
return Public || Published && VisibleTo.Contains(user);
|
||||
}
|
||||
|
||||
public void AddUser(User user)
|
||||
{
|
||||
VisibleTo.Add(user);
|
||||
}
|
||||
|
||||
public void RemoveUser(User user)
|
||||
{
|
||||
VisibleTo.Remove(user);
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return VisibleTo.Count == 0;
|
||||
}
|
||||
|
||||
}
|
||||
35
Wishlist/Data/Entities/Wish.cs
Normal file
35
Wishlist/Data/Entities/Wish.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public class Wish
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
[MaxLength(50)]
|
||||
public string Name { get; set; }
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
public bool IsVisible { get; set; }
|
||||
public ReserveStatus ReserveStatus { get; set; }
|
||||
public PriceInfo Price { get; set; }
|
||||
public Uri ImageUrl { get; set; }
|
||||
public Uri StoreLink { get; set; }
|
||||
public Guid WishlistId { get; set; }
|
||||
public Wishlist Wishlist { get; set; } = null!;
|
||||
|
||||
public Wish()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Created = DateTime.UtcNow;
|
||||
LastModified = DateTime.UtcNow;
|
||||
IsVisible = false;
|
||||
ReserveStatus = ReserveStatus.NotReserve;
|
||||
Price = new(0, Constants.DefaultCurrency);
|
||||
ImageUrl = new Uri(string.Empty);
|
||||
StoreLink = new Uri(string.Empty);
|
||||
Description = string.Empty;
|
||||
Name = string.Empty;
|
||||
}
|
||||
}
|
||||
28
Wishlist/Data/Entities/Wishlist.cs
Normal file
28
Wishlist/Data/Entities/Wishlist.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Wishlist.Data.Entities;
|
||||
|
||||
public class Wishlist
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
[MaxLength(50)]
|
||||
public string Title { get; set; }
|
||||
[MaxLength(2000)]
|
||||
public string Description { get; set; }
|
||||
public List<Wish> Wishes { get; set; }
|
||||
public List<User> Owners { get; set; }
|
||||
public VisibilityStatus VisibilityStatus { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public Wishlist()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Title = string.Empty;
|
||||
Description = string.Empty;
|
||||
Wishes = [];
|
||||
VisibilityStatus = new VisibilityStatus();
|
||||
Created = DateTime.UtcNow;
|
||||
LastModified = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
12
Wishlist/Data/Services/Interfaces/ICrud.cs
Normal file
12
Wishlist/Data/Services/Interfaces/ICrud.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using CSharpFunctionalExtensions;
|
||||
|
||||
namespace Wishlist.Data.Services.Interfaces;
|
||||
|
||||
|
||||
public interface ICrud<in TKey, TEntity>
|
||||
{
|
||||
Task<Result<TEntity>> Create(TEntity entity);
|
||||
Task<Maybe<TEntity>> Read(TKey entityId);
|
||||
Task<Result<TEntity>> Update(TEntity entity);
|
||||
Task<Result<TEntity>> Delete(TKey entityId);
|
||||
}
|
||||
17
Wishlist/Data/Services/Interfaces/IWishService.cs
Normal file
17
Wishlist/Data/Services/Interfaces/IWishService.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using CSharpFunctionalExtensions;
|
||||
using Wishlist.Data.Entities;
|
||||
|
||||
namespace Wishlist.Data.Services.Interfaces;
|
||||
|
||||
public interface IWishService : ICrud<Guid, Wish>
|
||||
{
|
||||
Task<Result<List<Wish>>> GetAllWishes(Guid listId);
|
||||
Task<Result<Wish>> UpdateReservedStatus(Guid wishId, User? reservedBy);
|
||||
Task<Result<Wish>> UpdatePriceInfo(Guid wishId, PriceInfo priceInfo);
|
||||
Task<Result<Wish>> UpdateImage(Guid wishId, Uri imageUri);
|
||||
Task<Result<Wish>> UpdateStore(Guid wishId, Uri storeUri);
|
||||
Task<Result<Wish>> UpdateName(Guid wishId, string name);
|
||||
Task<Result<Wish>> UpdateDescription(Guid wishId, string description);
|
||||
Task<Result<Wish>> UpdateVisibility(Guid wishId, bool isVisible);
|
||||
Task<Result<Wish>> UpdatePrice(Guid wishId, double price);
|
||||
}
|
||||
9
Wishlist/Data/Services/Interfaces/IWishlistService.cs
Normal file
9
Wishlist/Data/Services/Interfaces/IWishlistService.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using CSharpFunctionalExtensions;
|
||||
using Wishlist.Data.Entities;
|
||||
|
||||
namespace Wishlist.Data.Services.Interfaces;
|
||||
|
||||
public interface IWishlistService : ICrud<Guid, Entities.Wishlist>
|
||||
{
|
||||
Task<Result<Wish>> AddWish(Guid id, Wish wish);
|
||||
}
|
||||
176
Wishlist/Data/Services/WishService.cs
Normal file
176
Wishlist/Data/Services/WishService.cs
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
using CSharpFunctionalExtensions;
|
||||
using Wishlist.Data.Entities;
|
||||
using Wishlist.Data.Services.Interfaces;
|
||||
|
||||
namespace Wishlist.Data.Services;
|
||||
|
||||
public class WishService : IWishService
|
||||
{
|
||||
private readonly AppDataContext _context;
|
||||
private readonly ILogger<WishService> _logger;
|
||||
private readonly IWishlistService _wishlistService;
|
||||
|
||||
public WishService(AppDataContext context, ILogger<WishService> logger, IWishlistService wishlistService)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_wishlistService = wishlistService;
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> Create(Wish entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation($"Creating Wish {entity.Id}");
|
||||
entity.Created = DateTime.UtcNow;
|
||||
entity.LastModified = entity.Created;
|
||||
var createdEntity = await _context.Wishes.AddAsync(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return createdEntity.Entity;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("An error occurred while creating the Wish. {Entity} - {Error}", entity, e.Message);
|
||||
return Result.Failure<Wish>($"An error occurred while creating the Wish. {e}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Maybe<Wish>> Read(Guid entityId)
|
||||
{
|
||||
var entity = await _context.Wishes.FindAsync(entityId);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> Update(Wish entity)
|
||||
{
|
||||
var oldEntity = await Read(entity.Id);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
entity.LastModified = DateTime.UtcNow;
|
||||
_context.Wishes.Update(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return Result.Success(entity);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> Delete(Guid entityId)
|
||||
{
|
||||
var entity = await Read(entityId);
|
||||
if (entity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var deletedEntity = _context.Wishes.Remove(entity.Value);
|
||||
await _context.SaveChangesAsync();
|
||||
return Result.Success(deletedEntity.Entity);
|
||||
}
|
||||
|
||||
public async Task<Result<List<Wish>>> GetAllWishes(Guid listId)
|
||||
{
|
||||
var listMaybe = await _wishlistService.Read(listId);
|
||||
if (listMaybe.HasNoValue)
|
||||
{
|
||||
return Result.Failure<List<Wish>>("The given list was not found.");
|
||||
}
|
||||
return listMaybe.Value.Wishes;
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateReservedStatus(Guid wishId, User? reservedBy)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.ReserveStatus = new ReserveStatus(reservedBy);
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdatePriceInfo(Guid wishId, PriceInfo priceInfo)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.Price = priceInfo;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateImage(Guid wishId, Uri imageUri)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.ImageUrl = imageUri;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateStore(Guid wishId, Uri storeUri)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.StoreLink = storeUri;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateName(Guid wishId, string name)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.Name = name;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateDescription(Guid wishId, string description)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.Description = description;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdateVisibility(Guid wishId, bool isVisible)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
wish.IsVisible = isVisible;
|
||||
return await Update(wish);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> UpdatePrice(Guid wishId, double price)
|
||||
{
|
||||
var oldEntity = await Read(wishId);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>("The given entity was not found.");
|
||||
}
|
||||
var wish = oldEntity.Value;
|
||||
var oldPrice = wish.Price;
|
||||
oldPrice.Price = price;
|
||||
wish.Price = oldPrice;
|
||||
return await Update(wish);
|
||||
}
|
||||
}
|
||||
86
Wishlist/Data/Services/WishlistService.cs
Normal file
86
Wishlist/Data/Services/WishlistService.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
using CSharpFunctionalExtensions;
|
||||
using Wishlist.Data.Entities;
|
||||
using Wishlist.Data.Services.Interfaces;
|
||||
|
||||
namespace Wishlist.Data.Services;
|
||||
|
||||
public class WishlistService : IWishlistService
|
||||
{
|
||||
private readonly AppDataContext _context;
|
||||
private readonly ILogger<WishlistService> _logger;
|
||||
|
||||
public WishlistService(AppDataContext context, ILogger<WishlistService> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<Result<Entities.Wishlist>> Create(Entities.Wishlist entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation($"Creating Wishlist {entity.Id}");
|
||||
entity.Created = DateTime.UtcNow;
|
||||
entity.LastModified = entity.Created;
|
||||
var createdEntity = await _context.Wishlists.AddAsync(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return createdEntity.Entity;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("An error occurred while creating the Wishlist. {Entity} - {Error}", entity, e.Message);
|
||||
return Result.Failure<Entities.Wishlist>($"An error occurred while creating the Wishlist. {e}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Maybe<Entities.Wishlist>> Read(Guid entityId)
|
||||
{
|
||||
var entity = await _context.Wishlists.FindAsync(entityId);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public async Task<Result<Entities.Wishlist>> Update(Entities.Wishlist entity)
|
||||
{
|
||||
var oldEntity = await Read(entity.Id);
|
||||
if (oldEntity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Entities.Wishlist>("The given entity was not found.");
|
||||
}
|
||||
entity.LastModified = DateTime.UtcNow;
|
||||
_context.Wishlists.Update(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return Result.Success(entity);
|
||||
}
|
||||
|
||||
public async Task<Result<Entities.Wishlist>> Delete(Guid entityId)
|
||||
{
|
||||
var entity = await Read(entityId);
|
||||
if (entity.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Entities.Wishlist>("The given entity was not found.");
|
||||
}
|
||||
var deletedEntity = _context.Wishlists.Remove(entity.Value);
|
||||
await _context.SaveChangesAsync();
|
||||
return Result.Success(deletedEntity.Entity);
|
||||
}
|
||||
|
||||
public async Task<Result<Wish>> AddWish(Guid id, Wish wish)
|
||||
{
|
||||
var listMaybe = await Read(id);
|
||||
if (listMaybe.HasNoValue)
|
||||
{
|
||||
return Result.Failure<Wish>($"Wishlist '{id}' was not found. Wish '{wish.Id}' not added");
|
||||
}
|
||||
var wishlist = listMaybe.Value;
|
||||
|
||||
wish.WishlistId = wishlist.Id;
|
||||
wishlist.Wishes.Add(wish);
|
||||
var update = await Update(wishlist);
|
||||
if (update.IsFailure)
|
||||
{
|
||||
return Result.Failure<Wish>(update.Error);
|
||||
}
|
||||
await _context.SaveChangesAsync();
|
||||
return Result.Success(wish);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Wishlist.Components;
|
||||
using Wishlist.Data;
|
||||
using Wishlist.Data.Entities;
|
||||
using Wishlist.Data.Services;
|
||||
using Wishlist.Data.Services.Interfaces;
|
||||
|
||||
namespace Wishlist;
|
||||
|
||||
|
|
@ -26,6 +28,8 @@ public class Program
|
|||
builder.Services.AddScoped<IdentityUserAccessor>();
|
||||
builder.Services.AddScoped<IdentityRedirectManager>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
|
||||
builder.Services.AddScoped<IWishlistService, WishlistService>();
|
||||
builder.Services.AddScoped<IWishService, WishService>();
|
||||
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CSharpFunctionalExtensions" Version="3.7.0" />
|
||||
<PackageReference Include="CSharpFunctionalExtensions.Analyzers" Version="1.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DotNetEnv" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.12"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.12"/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue