using System; using System.Collections.Generic; using System.Linq; using GraphQL.Server; using GraphQL.Server.Ui.Playground; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MySql.EntityFrameworkCore.Extensions; using xCommons.Extensions; using xDataService.Configuration; using xDataService.Constants; using xDataService.Db; using xDataService.Extensions; using xDataService.Interfaces; using xExceptions.Constants; using xModels.Base; namespace xDataService.DI { public static class XDIHelperExtension { /// /// Extract Connection String From IConfiguration /// /// /// /// public static string GetXConnectionString ( this IConfiguration config, string connectionName = null ) { // if (connectionName.IsNullOrEmpty ()) { connectionName = XDbProviderConfigurations.DEFAULT_CONNECTION_NAME; } // return config.GetConnectionString (connectionName); } /// /// Retrieve Data Provider Type from Configurations /// /// /// public static XDbProviders GetXDbProviderType (this IConfiguration source) { // var provider = (source[$"{ConfigurationNodeNames.DB_PROVIDER_NODE}"]) .ToNormalString (); // return provider.ToDbProvider (); } /// /// Retrive XDataService Configurations /// /// /// /// public static XDataServiceConfiguration GetXDataServiceConfiguration ( this IConfiguration source, string connectionName = null ) { // var xDataServiceConfigSection = source .GetSection (ConfigurationNodeNames.DATA_SERVICE_NODE); var result = xDataServiceConfigSection.Get (); // result.Provider = source.GetXDbProviderType (); result.ConnectionString = source.GetXConnectionString (connectionName); // return result; } /// /// Register XDataService Configuration /// /// /// /// public static void AddXDataServiceConfiguration ( this IServiceCollection services, IConfiguration configuration, string connectionName = null ) { // var dataServiceConfiguration = configuration .GetXDataServiceConfiguration (connectionName); if (dataServiceConfiguration.IsNull ()) { dataServiceConfiguration = new XDataServiceConfiguration (); } // services.AddSingleton (dataServiceConfiguration); } /// /// Register XDataService Configuration /// /// /// public static void AddXDataServiceConfiguration ( this IServiceCollection services, XDataServiceConfiguration configuration ) { // if (configuration.IsNull ()) { configuration = new XDataServiceConfiguration (); } // services.AddSingleton (configuration); } /// /// Register XDataService on DI /// Only Used when EFCore Provider configured to use ... /// /// /// /// /// /// public static void AddXDataService ( this IServiceCollection services, IConfiguration config, ServiceLifetime lifetime, string connectionName = null, Action optionsBuilder = null ) where TDbContext : XDbContext where TDbSeeder : IXDbSeeder { // // Register DataService Configuration ... if (services.GetRegisteredService ().IsNull ()) { Console.WriteLine ($"XDataService: there is no provided DataService Config, try to register default ..."); services.AddXDataServiceConfiguration (config, connectionName); } // // prevent from going forward if there is no Provider configured ... var providerType = config.GetXDbProviderType (); Console.WriteLine ($"XDataService: registered db provider type is => {providerType} ..."); if (providerType == XDbProviders.None) { return; } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (!dataServiceHelper.IsNull ()) { // // Use Db Context Helper ... Console.WriteLine ($"XDataService: use provided IXDbContextHelper ..."); // // Retrieve Connection String ... var addContext = true; var connectionString = config.GetXConnectionString (connectionName); switch (providerType) { // case XDbProviders.MySQL: addContext = true; services.AddEntityFrameworkMySQL (); break; // case XDbProviders.SQLite: addContext = true; services.AddEntityFrameworkSqlite (); break; // case XDbProviders.SQLServer: addContext = true; services.AddEntityFrameworkSqlServer (); break; // case XDbProviders.MongoDB: addContext = false; break; } // // Register DbContext in DI ... if (addContext) { dataServiceHelper.AddDbContext ( services, connectionString, providerType, lifetime, optionsBuilder ); // // Register Unit Of Works ... services.Add (new ServiceDescriptor (typeof (IXUnitOfWorks), typeof (XUnitOfWorks), lifetime)); } // // Comment this in related to Task no. 27 ... // Register IXSequentialGuid for handle XBaseGuidEntities ... // services.AddSingleton (); // // Register All Repository Patterns ... AddRepositories (services, config, lifetime, providerType); } else { Console.WriteLine ($"XDataService: there is no provided IXDbContextHelper, data service registration failed ..."); } } /// /// Register XDataService on DI /// Only Used when non EFCore Provider configured to use ... /// /// /// /// /// public static void AddXDataService ( this IServiceCollection services, IConfiguration config, ServiceLifetime lifetime, string connectionName = null ) where TDbSeeder : IXDbSeeder { // // Register DataService Configuration ... if (services.GetRegisteredService ().IsNull ()) { Console.WriteLine ($"XDataService: there is no provided DataService Config, try to register default ..."); services.AddXDataServiceConfiguration (config, connectionName); } // // prevent from going forward if there is no Provider configured ... var providerType = config.GetXDbProviderType (); Console.WriteLine ($"XDataService: registered db provider type is => {providerType} ..."); if (providerType == XDbProviders.None) { return; } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (!dataServiceHelper.IsNull ()) { // // Use Db Context Helper ... Console.WriteLine ($"XDataService: use provided IXDataServiceHelper ..."); // // Retrieve Connection String ... var connectionString = config.GetXConnectionString (connectionName); switch (providerType) { // case XDbProviders.MySQL: case XDbProviders.SQLite: case XDbProviders.SQLServer: Console.WriteLine ($"XDataService: for EF Provider Types use AddXDataService instead of AddXDataService ..."); XException.InvalidConfiguration.Throw (); break; // case XDbProviders.MongoDB: // #region XBaseEntity Mappers ... // // Map ID as BsonId here ... BsonClassMap.RegisterClassMap> (cm => { // cm.AutoMap (); cm.MapIdMember (c => c.Id); }); BsonClassMap.RegisterClassMap> (cm => { // cm.AutoMap (); cm.MapIdMember (c => c.Id); }); BsonClassMap.RegisterClassMap> (cm => { // cm.AutoMap (); cm.MapIdMember (c => c.Id); }); #endregion // var conventionPacks = dataServiceHelper.MongoConventionPacks (); if (!conventionPacks.IsNull ()) { ConventionRegistry.Register ( nameof ( dataServiceHelper.MongoConventionPacks ), conventionPacks, type => !type.FullName .IsNullOrEmpty () ); } // dataServiceHelper.RegisterMongoExtras (); break; } // // Comment this in related to Task no. 27 ... // Register IXSequentialGuid for handle XBaseGuidEntities ... // services.AddSingleton (); // // Register All Repository Patterns ... AddRepositories (services, config, lifetime, providerType); } else { Console.WriteLine ($"XDataService: there is no provided IXDbContextHelper, data service registration failed ..."); } } /// /// Register XGraphQL service ... /// /// /// public static void AddXGraphQL ( this IServiceCollection services, Action options = null ) { // var xGraphQLHelper = services.GetRegisteredService (); if (!xGraphQLHelper.IsNull ()) { // xGraphQLHelper.AddXGraphEnumTypes (services); xGraphQLHelper.AddXGraphObjectTypes (services); xGraphQLHelper.AddXGraphInputTypes (services); xGraphQLHelper.AddXGraphQueries (services); xGraphQLHelper.AddXGraphMutations (services); xGraphQLHelper.AddXGraphSubscriptions (services); xGraphQLHelper.AddXGraphSchemas (services); // // Add GraphQL Server ... if (options.IsNull ()) { // options = x => { }; Console.WriteLine ($"XDataService: there is no provided GraphQLOption, use default ..."); } // var xGraphQlBuilder = services.AddGraphQL (options) .AddNewtonsoftJson (deserializerSettings => { }, serializerSettings => { }) .AddWebSockets () .AddDataLoader () .AddGraphTypes (); // xGraphQLHelper.AddXGraphTypes (xGraphQlBuilder); } else { Console.WriteLine ($"XDataService: there is no provided IXGraphQLHelper, data service registration failed ..."); } } /// /// Use XDataService MiddleWare /// /// public static void UseXDataService ( this IApplicationBuilder app ) { app.SeedData (); } /// /// Use XGraphQL Middleware ... /// /// /// /// public static void UseXGraphQL ( this IApplicationBuilder app, GraphQLPlaygroundOptions options = null, bool withPlayground = true ) { // // Use GraphQl WebSockets ... app.UseWebSockets (); // // Registered Graph Types ... using (var scope = app.ApplicationServices.CreateScope ()) { // var xGraphQLHelper = scope.ServiceProvider.GetService (); if (!xGraphQLHelper.IsNull ()) { xGraphQLHelper.UseXGraph (app); } else { Console.WriteLine ($"XDataService: there is no provided IXGraphQLHelper, data service GraphQL not using ..."); } } // // Use GraphQL Playground UI ... if (withPlayground) { app.UseGraphQLPlayground (options); } } // #region Private ... /// /// Register Repositories on DI as Services /// /// /// /// /// private static void AddRepositories ( IServiceCollection services, IConfiguration config, ServiceLifetime lifetime, XDbProviders provider ) where TDbContext : XDbContext where TDbSeeder : IXDbSeeder { // // Add Repositories Based On Provider Here ... switch (provider) { case XDbProviders.MySQL: case XDbProviders.SQLite: case XDbProviders.SQLServer: AddEFRepositories (services, lifetime); break; case XDbProviders.MongoDB: Console.WriteLine ($"XDataService: for Mongo Provider Types use AddXDataService instead of AddXDataService ..."); XException.InvalidConfiguration.Throw (); break; } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (dataServiceHelper.IsNull ()) { // Console.WriteLine ($"XDataService: there is no provided IXDataServiceHelper, db seeder registration failed ..."); return; } // // Add DbSeeder Configuration ... dataServiceHelper.AddDbSeederConfiguration (services, config); // // Add Db Seeder ... dataServiceHelper.AddDbSeeder (services, config, lifetime); } /// /// Register Repositories on DI as Services /// /// /// /// /// private static void AddRepositories ( IServiceCollection services, IConfiguration config, ServiceLifetime lifetime, XDbProviders provider ) where TDbSeeder : IXDbSeeder { // // Add Repositories Based On Provider Here ... switch (provider) { // case XDbProviders.MySQL: case XDbProviders.SQLite: case XDbProviders.SQLServer: Console.WriteLine ($"XDataService: for EF Provider Types use AddXDataService instead of AddXDataService ..."); XException.InvalidConfiguration.Throw (); break; // case XDbProviders.MongoDB: AddMongoRepositories (services, lifetime); break; } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (dataServiceHelper.IsNull ()) { // Console.WriteLine ($"XDataService: there is no provided IXDataServiceHelper, db seeder registration failed ..."); return; } // // Add DbSeeder Configuration ... dataServiceHelper.AddDbSeederConfiguration (services, config); // // Add Db Seeder ... dataServiceHelper.AddDbSeeder (services, config, lifetime); } /// /// Add Entity Framework Repositories /// /// /// private static void AddEFRepositories ( this IServiceCollection services, ServiceLifetime lifetime ) where TDbContext : XDbContext { // var repoServices = new List (); // var dataServiceConfig = services.GetRegisteredService (); if (!dataServiceConfig.IsNull ()) { // // Register Base Repositories if Required ... } // // Adding Services to DI ... if (repoServices.Count > 0) { repoServices .ToList () .ForEach (s => services.Add (s)); } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (!dataServiceHelper.IsNull ()) { // // Register Repositories ... dataServiceHelper.AddRepositories (services, lifetime); // // Register KeyGenerators ... dataServiceHelper.AddKeyGenerators (services); } } /// /// Add MongoDb Repositories /// /// /// private static void AddMongoRepositories ( this IServiceCollection services, ServiceLifetime lifetime ) { // var repoServices = new List (); // var dataServiceConfig = services.GetRegisteredService (); if (!dataServiceConfig.IsNull ()) { // // Register Base Repositories if Required ... } // // Adding Services to DI ... if (repoServices.Count > 0) { repoServices .ToList () .ForEach (s => services.Add (s)); } // // Retrieve IXDataServiceHelper ... var dataServiceHelper = services.GetRegisteredService (); if (!dataServiceHelper.IsNull ()) { // // Register Repositories ... dataServiceHelper.AddRepositories (services, lifetime); // // Register KeyGenerators ... dataServiceHelper.AddKeyGenerators (services); } } /// /// Do Seeding Initialization Data on DbContext /// /// private static void SeedData ( this IApplicationBuilder app ) { // using (var scope = app.ApplicationServices.CreateScope ()) { // var dbSeeder = scope.ServiceProvider.GetService (); Console.WriteLine ($"XDataService: dbSeeder retrieved from DI is => {!dbSeeder.IsNull()}"); // if (!dbSeeder.IsNull ()) { try { // dbSeeder.Seed () .GetAwaiter () .GetResult (); } catch (Exception ex) { // Console.WriteLine (" "); Console.WriteLine ($"XDataService: Seeding Error: {ex.Message}"); XException.InvalidConfiguration.Throw (); } } } } #endregion } }