From 42310765bfba74914adfaf909daa34f91e9e4101 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 31 Aug 2023 11:27:44 +0100 Subject: [PATCH] Add Sqlite and SqlServer --- ...dentity.EntityFrameworkCore.Sqlite.csproj} | 2 + ...ostBuilderEntityFrameworkCoreExtensions.cs | 125 ++++++++++++++++++ ...ntity.EntityFrameworkCore.SqlServer.csproj | 33 +++++ ...ostBuilderEntityFrameworkCoreExtensions.cs | 94 ++++++++++--- src/CP.Extensions.Hosting.sln | 8 +- 5 files changed, 242 insertions(+), 20 deletions(-) rename src/{CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.csproj => CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite.csproj} (88%) create mode 100644 src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/HostBuilderEntityFrameworkCoreExtensions.cs create mode 100644 src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer.csproj diff --git a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.csproj b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite.csproj similarity index 88% rename from src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.csproj rename to src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite.csproj index fe673a9..29a16ed 100644 --- a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.csproj +++ b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite.csproj @@ -14,6 +14,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -23,6 +24,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/HostBuilderEntityFrameworkCoreExtensions.cs b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/HostBuilderEntityFrameworkCoreExtensions.cs new file mode 100644 index 0000000..3cf6e5b --- /dev/null +++ b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite/HostBuilderEntityFrameworkCoreExtensions.cs @@ -0,0 +1,125 @@ +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace CP.Extensions.Hosting.Identity.EntityFrameworkCore; + +/// +/// Host Builder Entity Framework Core Extensions. +/// +public static class HostBuilderEntityFrameworkCoreExtensions +{ + /// + /// Uses the entity framework core with Sqlite. + /// + /// The type of the context. + /// The type of the user. + /// The type of the role. + /// The services. + /// The context. + /// Name of the connection string. + /// + /// IServiceCollection. + /// + /// services + /// or + /// context. + public static IServiceCollection UseEntityFrameworkCoreSqlite(this IServiceCollection services, WebHostBuilderContext context, string connectionStringName) + where TContext : DbContext + where TUser : class + where TRole : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrWhiteSpace(connectionStringName)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(connectionStringName)); + } + + var conString = context.Configuration.GetConnectionString(connectionStringName); + services.AddDbContext(options => + options.UseSqlite(conString ?? + throw new InvalidOperationException($"Connection string '{connectionStringName}' not found."))) + .AddDefaultIdentity() + .AddRoles() + .AddEntityFrameworkStores(); + return services; + } + + /// + /// Uses the entity framework core with Sqlite. + /// + /// The type of the context. + /// The type of the user. + /// The services. + /// The context. + /// Name of the connection string. + /// + /// IServiceCollection. + /// + /// services + /// or + /// context. + public static IServiceCollection UseEntityFrameworkCoreSqlite(this IServiceCollection services, WebHostBuilderContext context, string connectionStringName) + where TContext : DbContext + where TUser : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrWhiteSpace(connectionStringName)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(connectionStringName)); + } + + var conString = context.Configuration.GetConnectionString(connectionStringName); + services.AddDbContext(options => + options.UseSqlite(conString ?? + throw new InvalidOperationException($"Connection string '{connectionStringName}' not found."))) + .AddDefaultIdentity() + .AddEntityFrameworkStores(); + return services; + } + + /// + /// Uses the web host services. + /// + /// The host builder. + /// Adds a delegate for configuring additional services for the host or web application. + /// true to perform check verifying that scoped services never gets resolved from root provider; otherwise false. Defaults to false. + /// IHostBuilder. + /// hostBuilder. + public static IHostBuilder UseWebHostServices(this IHostBuilder hostBuilder, Action configureServices, bool validateScopes = false) + { + if (hostBuilder is null) + { + throw new ArgumentNullException(nameof(hostBuilder)); + } + + return hostBuilder.ConfigureWebHostDefaults(webBuilder => + webBuilder.UseDefaultServiceProvider(options => options.ValidateScopes = validateScopes) + .Configure(app => app.Run(async (_) => await Task.CompletedTask)) // Dummy app.Run to prevent 'No application service provider was found' error. + .ConfigureServices((context, services) => configureServices(context, services))); + } +} diff --git a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer.csproj b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer.csproj new file mode 100644 index 0000000..7b9340c --- /dev/null +++ b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer.csproj @@ -0,0 +1,33 @@ + + + + net6.0;net7.0 + enable + enable + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/HostBuilderEntityFrameworkCoreExtensions.cs b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/HostBuilderEntityFrameworkCoreExtensions.cs index e25deb4..ebfbc28 100644 --- a/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/HostBuilderEntityFrameworkCoreExtensions.cs +++ b/src/CP.Extensions.Hosting.Identity.EntityFrameworkCore/HostBuilderEntityFrameworkCoreExtensions.cs @@ -16,34 +16,90 @@ namespace CP.Extensions.Hosting.Identity.EntityFrameworkCore; public static class HostBuilderEntityFrameworkCoreExtensions { /// - /// Uses the entity framework core. + /// Uses the entity framework core with SqlServer. /// /// The type of the context. - /// The host builder. - /// The connection string Name. - /// An optional action to configure the for the context. This provides an - /// alternative to performing configuration of the context by overriding the - /// method in your derived context. - /// true to perform check verifying that scoped services never gets resolved from root provider; otherwise false. Defaults to false. + /// The type of the user. + /// The type of the role. + /// The services. + /// The context. + /// Name of the connection string. /// - /// IHostBuilder. + /// IServiceCollection. /// - /// hostBuilder. - public static IHostBuilder UseEntityFrameworkCore(this IHostBuilder hostBuilder, string? connectionStringName, Action configureDatabase, bool validateScopes = false) + /// services + /// or + /// context. + public static IServiceCollection UseEntityFrameworkCoreSqlServer(this IServiceCollection services, WebHostBuilderContext context, string connectionStringName) where TContext : DbContext + where TUser : class + where TRole : class { - if (hostBuilder is null) + if (services == null) { - throw new ArgumentNullException(nameof(hostBuilder)); + throw new ArgumentNullException(nameof(services)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrWhiteSpace(connectionStringName)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(connectionStringName)); + } + + var conString = context.Configuration.GetConnectionString(connectionStringName); + services.AddDbContext(options => + options.UseSqlServer(conString ?? + throw new InvalidOperationException($"Connection string '{connectionStringName}' not found."))) + .AddDefaultIdentity() + .AddRoles() + .AddEntityFrameworkStores(); + return services; + } + + /// + /// Uses the entity framework core with SqlServer. + /// + /// The type of the context. + /// The type of the user. + /// The services. + /// The context. + /// Name of the connection string. + /// + /// IServiceCollection. + /// + /// services + /// or + /// context. + public static IServiceCollection UseEntityFrameworkCoreSqlServer(this IServiceCollection services, WebHostBuilderContext context, string connectionStringName) + where TContext : DbContext + where TUser : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrWhiteSpace(connectionStringName)) + { + throw new ArgumentException("Value cannot be null or whitespace.", nameof(connectionStringName)); } - return hostBuilder.UseWebHostServices( - (context, services) => - { - var constring = context.Configuration.GetConnectionString(connectionStringName!) ?? throw new InvalidOperationException($"Connection string '{connectionStringName}' not found."); - services.AddDbContext(options => configureDatabase(context, services, options, constring)); - }, - validateScopes); + var conString = context.Configuration.GetConnectionString(connectionStringName); + services.AddDbContext(options => + options.UseSqlServer(conString ?? + throw new InvalidOperationException($"Connection string '{connectionStringName}' not found."))) + .AddDefaultIdentity() + .AddEntityFrameworkStores(); + return services; } /// diff --git a/src/CP.Extensions.Hosting.sln b/src/CP.Extensions.Hosting.sln index 06b4b15..306ebe3 100644 --- a/src/CP.Extensions.Hosting.sln +++ b/src/CP.Extensions.Hosting.sln @@ -40,7 +40,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CP.Extensions.Hosting.React EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CP.Extensions.Hosting.PluginService", "CP.Extensions.Hosting.PluginService\CP.Extensions.Hosting.PluginService.csproj", "{C4CC7AF8-E34E-4C5E-8E74-01946A7F97E4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CP.Extensions.Hosting.Identity.EntityFrameworkCore", "CP.Extensions.Hosting.Identity.EntityFrameworkCore\CP.Extensions.Hosting.Identity.EntityFrameworkCore.csproj", "{36D4DB90-256B-46E2-9BB3-EB0FC2C40175}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer", "CP.Extensions.Hosting.Identity.EntityFrameworkCore\CP.Extensions.Hosting.Identity.EntityFrameworkCore.SqlServer.csproj", "{36D4DB90-256B-46E2-9BB3-EB0FC2C40175}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite", "CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite\CP.Extensions.Hosting.Identity.EntityFrameworkCore.Sqlite.csproj", "{9D98227B-C97B-429C-AEAF-88A9514A2B0E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -94,6 +96,10 @@ Global {36D4DB90-256B-46E2-9BB3-EB0FC2C40175}.Debug|Any CPU.Build.0 = Debug|Any CPU {36D4DB90-256B-46E2-9BB3-EB0FC2C40175}.Release|Any CPU.ActiveCfg = Release|Any CPU {36D4DB90-256B-46E2-9BB3-EB0FC2C40175}.Release|Any CPU.Build.0 = Release|Any CPU + {9D98227B-C97B-429C-AEAF-88A9514A2B0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D98227B-C97B-429C-AEAF-88A9514A2B0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D98227B-C97B-429C-AEAF-88A9514A2B0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D98227B-C97B-429C-AEAF-88A9514A2B0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE