From 5d713db83f9ee97deddd6776bb7dbeac4f7b8ef5 Mon Sep 17 00:00:00 2001 From: Andre Beging Date: Mon, 23 May 2022 10:29:10 +0200 Subject: [PATCH] Audit Service --- FoodsharingSiegen.Contracts/Entity/Audit.cs | 49 +++++ .../Entity/AuditType.cs | 23 +++ FoodsharingSiegen.Server/Auth/AuthService.cs | 15 +- .../Auth/TokenAuthStateProvider.cs | 40 +++- .../BaseClasses/FsBase.cs | 6 + FoodsharingSiegen.Server/Data/FsContext.cs | 6 +- .../Data/Service/AuditService.cs | 95 +++++++++ .../Data/Service/ProspectService.cs | 10 +- .../Data/Service/ServiceBase.cs | 49 ++++- .../Data/Service/UserService.cs | 29 +-- .../20220523082612_Audit.Designer.cs | 195 ++++++++++++++++++ .../Migrations/20220523082612_Audit.cs | 45 ++++ .../Migrations/FsContextModelSnapshot.cs | 37 ++++ FoodsharingSiegen.Server/Program.cs | 2 + 14 files changed, 552 insertions(+), 49 deletions(-) create mode 100644 FoodsharingSiegen.Contracts/Entity/Audit.cs create mode 100644 FoodsharingSiegen.Contracts/Entity/AuditType.cs create mode 100644 FoodsharingSiegen.Server/Data/Service/AuditService.cs create mode 100644 FoodsharingSiegen.Server/Migrations/20220523082612_Audit.Designer.cs create mode 100644 FoodsharingSiegen.Server/Migrations/20220523082612_Audit.cs diff --git a/FoodsharingSiegen.Contracts/Entity/Audit.cs b/FoodsharingSiegen.Contracts/Entity/Audit.cs new file mode 100644 index 0000000..2646f2f --- /dev/null +++ b/FoodsharingSiegen.Contracts/Entity/Audit.cs @@ -0,0 +1,49 @@ +using System.ComponentModel.DataAnnotations; + +namespace FoodsharingSiegen.Contracts.Entity +{ + /// + /// The audit class (a. beging, 23.05.2022) + /// + public class Audit + { + #region Public Properties + + /// + /// Gets or sets the value of the created (ab) + /// + public DateTime? Created { get; set; } + + /// + /// Gets or sets the value of the data 1 (ab) + /// + public string? Data1 { get; set; } + + /// + /// Gets or sets the value of the data 2 (ab) + /// + public string? Data2 { get; set; } + + /// + /// Gets or sets the value of the id (ab) + /// + [Key] public Guid Id { get; set; } + + /// + /// Gets or sets the value of the type (ab) + /// + public AuditType Type { get; set; } + + /// + /// Gets or sets the value of the user (ab) + /// + public User? User { get; set; } + + /// + /// Gets or sets the value of the user id (ab) + /// + public Guid? UserID { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.Contracts/Entity/AuditType.cs b/FoodsharingSiegen.Contracts/Entity/AuditType.cs new file mode 100644 index 0000000..7284c2c --- /dev/null +++ b/FoodsharingSiegen.Contracts/Entity/AuditType.cs @@ -0,0 +1,23 @@ +namespace FoodsharingSiegen.Contracts.Entity +{ + public enum AuditType : int + { + None = 0, + + // Profile + SaveProfile = 10, + SetOwnPassword = 20, + + // Usermanagement + CreateUser = 30, + UpdateUser = 40, + RemoveUser = 50, + SetUserPassword = 60, + + // Prospect + CreateProspect = 70, + EditProspect = 80, + AddInteraction = 90, + RemoveInteraction = 100 + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Auth/AuthService.cs b/FoodsharingSiegen.Server/Auth/AuthService.cs index 6ff7bca..6472c26 100644 --- a/FoodsharingSiegen.Server/Auth/AuthService.cs +++ b/FoodsharingSiegen.Server/Auth/AuthService.cs @@ -13,8 +13,7 @@ namespace FoodsharingSiegen.Server.Auth /// /// The auth service class (a. beging, 04.04.2022) /// - /// - public class AuthService : ServiceBase + public class AuthService { #region Public Properties @@ -25,6 +24,15 @@ namespace FoodsharingSiegen.Server.Auth #endregion + #region Private Properties + + /// + /// Gets the value of the context (ab) + /// + private FsContext Context { get; } + + #endregion + #region Private Fields /// @@ -55,8 +63,9 @@ namespace FoodsharingSiegen.Server.Auth public AuthService( FsContext context, LocalStorageService localStorageService, - AuthenticationStateProvider authenticationStateProvider) : base(context) + AuthenticationStateProvider authenticationStateProvider) { + Context = context; _localStorageService = localStorageService; _authenticationStateProvider = authenticationStateProvider; } diff --git a/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs b/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs index cf1359c..42c9124 100644 --- a/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs +++ b/FoodsharingSiegen.Server/Auth/TokenAuthStateProvider.cs @@ -1,9 +1,11 @@ using System.Security.Claims; using FoodsharingSiegen.Contracts; -using FoodsharingSiegen.Server.Auth; +using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Server.Data; using FoodsharingSiegen.Server.Data.Service; using FoodsharingSiegen.Shared.Helper; using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.EntityFrameworkCore; namespace FoodsharingSiegen.Server.Service { @@ -13,13 +15,13 @@ namespace FoodsharingSiegen.Server.Service /// public class TokenAuthStateProvider : AuthenticationStateProvider { + private FsContext Context { get; } + #region Private Fields /// LocalStorageService private readonly LocalStorageService _localStorageService; - - private readonly UserService _userService; - + #endregion #region Setup/Teardown @@ -28,11 +30,11 @@ namespace FoodsharingSiegen.Server.Service /// Constructor /// /// - /// - public TokenAuthStateProvider(LocalStorageService localStorageService, UserService userService) + /// + public TokenAuthStateProvider(LocalStorageService localStorageService, FsContext context) { + Context = context; _localStorageService = localStorageService; - _userService = userService; } #endregion @@ -48,7 +50,7 @@ namespace FoodsharingSiegen.Server.Service var token = await _localStorageService.GetItem(StorageKeys.TokenKey); var tokenValid = AuthHelper.ValidateToken(token, out var user); - var checkR = await _userService.CheckForceLogout(user); + var checkR = await CheckForceLogout(user); if (checkR.Success && checkR.Data) tokenValid = false; @@ -75,6 +77,28 @@ namespace FoodsharingSiegen.Server.Service #endregion + #region Public Method CheckForceLogout + + /// + /// Checks the force logout using the specified user (a. beging, 11.04.2022) + /// + /// The user + /// A task containing an operation result of bool + public async Task> CheckForceLogout(User user) + { + try + { + var anyR = await Context.Users.AnyAsync(x => x.Id == user.Id && x.ForceLogout); + return new OperationResult(anyR); + } + catch (Exception e) + { + return new OperationResult(e); + } + } + + #endregion + #region Public Method MarkUserAsLoggedOut /// diff --git a/FoodsharingSiegen.Server/BaseClasses/FsBase.cs b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs index b3c8d2f..5720d38 100644 --- a/FoodsharingSiegen.Server/BaseClasses/FsBase.cs +++ b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs @@ -1,5 +1,6 @@ using FoodsharingSiegen.Contracts.Entity; using FoodsharingSiegen.Server.Auth; +using FoodsharingSiegen.Server.Data.Service; using Microsoft.AspNetCore.Components; namespace FoodsharingSiegen.Server.BaseClasses @@ -17,6 +18,11 @@ namespace FoodsharingSiegen.Server.BaseClasses /// [Inject] private AuthService? AuthService { get; set; } + /// + /// Gets or sets the value of the audit service (ab) + /// + [Inject] private AuditService? AuditService { get; set; } + #endregion #region Override OnInitializedAsync diff --git a/FoodsharingSiegen.Server/Data/FsContext.cs b/FoodsharingSiegen.Server/Data/FsContext.cs index c885ab8..b3147f2 100644 --- a/FoodsharingSiegen.Server/Data/FsContext.cs +++ b/FoodsharingSiegen.Server/Data/FsContext.cs @@ -1,6 +1,5 @@ using FoodsharingSiegen.Contracts.Entity; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; namespace FoodsharingSiegen.Server.Data { @@ -26,6 +25,11 @@ namespace FoodsharingSiegen.Server.Data /// Gets or sets the value of the users (ab) /// public DbSet? Users { get; set; } + + /// + /// Gets or sets the value of the audits (ab) + /// + public DbSet? Audits { get; set; } #endregion diff --git a/FoodsharingSiegen.Server/Data/Service/AuditService.cs b/FoodsharingSiegen.Server/Data/Service/AuditService.cs new file mode 100644 index 0000000..ad46c9b --- /dev/null +++ b/FoodsharingSiegen.Server/Data/Service/AuditService.cs @@ -0,0 +1,95 @@ +using FoodsharingSiegen.Contracts; +using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Server.Auth; + +namespace FoodsharingSiegen.Server.Data.Service +{ + /// + /// The audit service class (a. beging, 23.05.2022) + /// + /// + public class AuditService : ServiceBase + { + #region Setup/Teardown + + /// + /// Initializes a new instance of the class + /// + /// The context (ab) + /// + public AuditService(FsContext context, AuthService authService) : base(context, authService) { } + + #endregion + + #region Public Method Insert + + /// + /// Inserts the type (a. beging, 23.05.2022) + /// + /// The type + /// The data + /// The data + /// A task containing an operation result of audit + public async Task> Insert(AuditType type, string? data1 = null, string? data2 = null) + { + try + { + var audit = new Audit + { + Type = type, + UserID = CurrentUser?.Id, + Data1 = data1, + Data2 = data2 + }; + + Context.Audits?.Add(audit); + var saveR = await Context.SaveChangesAsync(); + + if (saveR > 0) + return new OperationResult(audit); + + return new OperationResult(new Exception("Couldn't add audit")); + } + catch (Exception e) + { + return new OperationResult(e); + } + } + + #endregion + + #region Public Method Load + + /// + /// Loads the count (a. beging, 23.05.2022) + /// + /// The count + /// The type + /// A task containing an operation result of list audit + public async Task>> Load(int count, AuditType? type) + { + try + { + var query = Context.Audits?.OrderBy(x => x.Created).AsQueryable(); + + if (count > 0) + query = query?.Take(count); + + if (type != null) + query = query?.Where(x => x.Type == type); + + var mat = query?.ToList(); + + if (mat != null) return new OperationResult>(mat); + + return new OperationResult>(new Exception("Couldn't load audits")); + } + catch (Exception e) + { + return new OperationResult>(e); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Data/Service/ProspectService.cs b/FoodsharingSiegen.Server/Data/Service/ProspectService.cs index e8a0fe8..7385771 100644 --- a/FoodsharingSiegen.Server/Data/Service/ProspectService.cs +++ b/FoodsharingSiegen.Server/Data/Service/ProspectService.cs @@ -1,5 +1,6 @@ using FoodsharingSiegen.Contracts; using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Server.Auth; using Microsoft.EntityFrameworkCore; namespace FoodsharingSiegen.Server.Data.Service @@ -10,13 +11,17 @@ namespace FoodsharingSiegen.Server.Data.Service /// public class ProspectService : ServiceBase { + public AuditService AuditService { get; } + #region Setup/Teardown /// /// Initializes a new instance of the class /// /// The context - public ProspectService(FsContext context) : base(context) { } + /// + /// + public ProspectService(FsContext context, AuthService authService, AuditService auditService) : base(context, authService) => AuditService = auditService; #endregion @@ -75,7 +80,10 @@ namespace FoodsharingSiegen.Server.Data.Service var saveR = await Context.SaveChangesAsync(); if (saveR > 0) + { + await AuditService.Insert(AuditType.CreateProspect, prospect.Name, prospect.FsId.ToString()); return new OperationResult(prospect); + } return new OperationResult(new Exception("Couldn't add prospect")); } diff --git a/FoodsharingSiegen.Server/Data/Service/ServiceBase.cs b/FoodsharingSiegen.Server/Data/Service/ServiceBase.cs index 4af4a00..36573d7 100644 --- a/FoodsharingSiegen.Server/Data/Service/ServiceBase.cs +++ b/FoodsharingSiegen.Server/Data/Service/ServiceBase.cs @@ -1,21 +1,50 @@ -namespace FoodsharingSiegen.Server.Data.Service +using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Server.Auth; + +namespace FoodsharingSiegen.Server.Data.Service { + /// + /// The service base class (a. beging, 23.05.2022) + /// public class ServiceBase { + #region Public Properties + + /// + /// Gets the value of the auth service (ab) + /// + public AuthService AuthService { get; } + + #endregion + + #region Setup/Teardown + + //////////////////////////////////////////////////////////////////////////////////////////////////// + /// Specialised constructor for use only by derived class. + /// + /// A Beging, 20.10.2021. + /// + /// The context. + /// + //////////////////////////////////////////////////////////////////////////////////////////////////// + protected ServiceBase(FsContext context, AuthService authService) + { + Context = context; + AuthService = authService; + } + + #endregion + + /// + /// Gets the value of the current user (ab) + /// + protected User? CurrentUser => AuthService.User; + //////////////////////////////////////////////////////////////////////////////////////////////////// /// Database Context /// /// The context. //////////////////////////////////////////////////////////////////////////////////////////////////// protected FsContext Context { get; } - - //////////////////////////////////////////////////////////////////////////////////////////////////// - /// Specialised constructor for use only by derived class. - /// - /// A Beging, 20.10.2021. - /// - /// The context. - //////////////////////////////////////////////////////////////////////////////////////////////////// - protected ServiceBase(FsContext context) => Context = context; } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Data/Service/UserService.cs b/FoodsharingSiegen.Server/Data/Service/UserService.cs index c335891..bd026d2 100644 --- a/FoodsharingSiegen.Server/Data/Service/UserService.cs +++ b/FoodsharingSiegen.Server/Data/Service/UserService.cs @@ -1,5 +1,6 @@ using FoodsharingSiegen.Contracts; using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Server.Auth; using Microsoft.EntityFrameworkCore; namespace FoodsharingSiegen.Server.Data.Service @@ -16,10 +17,8 @@ namespace FoodsharingSiegen.Server.Data.Service /// Initializes a new instance of the class /// /// The context - public UserService(FsContext context) : base(context) - { - - } + /// + public UserService(FsContext context, AuthService authService) : base(context, authService) { } #endregion @@ -58,28 +57,6 @@ namespace FoodsharingSiegen.Server.Data.Service #endregion - #region Public Method CheckForceLogout - - /// - /// Checks the force logout using the specified user (a. beging, 11.04.2022) - /// - /// The user - /// A task containing an operation result of bool - public async Task> CheckForceLogout(User user) - { - try - { - var anyR = await Context.Users.AnyAsync(x => x.Id == user.Id && x.ForceLogout); - return new OperationResult(anyR); - } - catch (Exception e) - { - return new OperationResult(e); - } - } - - #endregion - #region Public Method GetUsersAsync //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.Designer.cs b/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.Designer.cs new file mode 100644 index 0000000..9ea51d8 --- /dev/null +++ b/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.Designer.cs @@ -0,0 +1,195 @@ +// +using System; +using FoodsharingSiegen.Server.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace FoodsharingSiegen.Server.Migrations +{ + [DbContext(typeof(FsContext))] + [Migration("20220523082612_Audit")] + partial class Audit + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Data1") + .HasColumnType("TEXT"); + + b.Property("Data2") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserID") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserID"); + + b.ToTable("Audits"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Alert") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("Info") + .HasColumnType("TEXT"); + + b.Property("NotNeeded") + .HasColumnType("INTEGER"); + + b.Property("ProspectID") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserID") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProspectID"); + + b.HasIndex("UserID"); + + b.ToTable("Interactions"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FsId") + .HasColumnType("INTEGER"); + + b.Property("Memo") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Prospects"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("EncryptedPassword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ForceLogout") + .HasColumnType("INTEGER"); + + b.Property("Groups") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mail") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Memo") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Verified") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User") + .WithMany() + .HasForeignKey("UserID"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => + { + b.HasOne("FoodsharingSiegen.Contracts.Entity.Prospect", "Prospect") + .WithMany("Interactions") + .HasForeignKey("ProspectID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User") + .WithMany("Interactions") + .HasForeignKey("UserID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Prospect"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b => + { + b.Navigation("Interactions"); + }); + + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b => + { + b.Navigation("Interactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.cs b/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.cs new file mode 100644 index 0000000..25bada3 --- /dev/null +++ b/FoodsharingSiegen.Server/Migrations/20220523082612_Audit.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FoodsharingSiegen.Server.Migrations +{ + public partial class Audit : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Audits", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Created = table.Column(type: "TEXT", nullable: true), + Data1 = table.Column(type: "TEXT", nullable: true), + Data2 = table.Column(type: "TEXT", nullable: true), + Type = table.Column(type: "INTEGER", nullable: false), + UserID = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Audits", x => x.Id); + table.ForeignKey( + name: "FK_Audits_Users_UserID", + column: x => x.UserID, + principalTable: "Users", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Audits_UserID", + table: "Audits", + column: "UserID"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Audits"); + } + } +} diff --git a/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs b/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs index 4e46091..5b44231 100644 --- a/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs +++ b/FoodsharingSiegen.Server/Migrations/FsContextModelSnapshot.cs @@ -17,6 +17,34 @@ namespace FoodsharingSiegen.Server.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Data1") + .HasColumnType("TEXT"); + + b.Property("Data2") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserID") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserID"); + + b.ToTable("Audits"); + }); + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => { b.Property("Id") @@ -122,6 +150,15 @@ namespace FoodsharingSiegen.Server.Migrations b.ToTable("Users"); }); + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b => + { + b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User") + .WithMany() + .HasForeignKey("UserID"); + + b.Navigation("User"); + }); + modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b => { b.HasOne("FoodsharingSiegen.Contracts.Entity.Prospect", "Prospect") diff --git a/FoodsharingSiegen.Server/Program.cs b/FoodsharingSiegen.Server/Program.cs index 16d134f..630013a 100644 --- a/FoodsharingSiegen.Server/Program.cs +++ b/FoodsharingSiegen.Server/Program.cs @@ -23,10 +23,12 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddBlazorise( options => { options.Immediate = true; }).AddMaterialProviders().AddMaterialIcons(); var app = builder.Build();