internal static IServiceCollection AddDbContextAs <TContext>(
            [NotNull] this IServiceCollection services,
            [NotNull] Func <ContextConnection.Builder, IServiceProvider, DbContextOptionsBuilder, DbContextOptionsBuilder> dbContextOptionsBuilderCallback,
            [AllowNull] Action <ContextConnection.Builder> builderAction = null,
            [AllowNull] Action <IContextServiceCollection> serviceAction = null,
            [NotNull] ServiceLifetime contextLifetime       = ServiceLifetime.Scoped,
            [NotNull] ServiceLifetime optionsLifetime       = ServiceLifetime.Scoped,
            [AllowNull, CallerMemberName] string memberName = null,
            [AllowNull, CallerFilePath] string filePath     = null)
            where TContext : ContextBase
        {
            CheckAndWriteNoBuilderActionWarning <TContext>(builderAction is null, memberName, filePath);

            var service = new ContextServiceCollection <TContext>(services);

            serviceAction?.Invoke(service);
            service.Dispose();

            return(services.AddDbContext <TContext>(
                       optionsAction: (prov, opt) =>
            {
                var builder = new ContextConnection.Builder().Database <TContext>();
                builderAction?.Invoke(builder);
                dbContextOptionsBuilderCallback.Invoke(builder, prov, opt);
            },
                       contextLifetime: contextLifetime,
                       optionsLifetime: optionsLifetime));
        }
        private static bool OnBuildFromConnectionStringCallback(ContextConnection.Builder builder, out ContextConnection conn)
        {
            var  aux     = new ContextConnectionString(builder);
            bool isValid = aux.IsValid();

            conn = isValid ? aux : default;
            return(isValid);
        }
 /// <summary>
 /// Mark to build context connection as a NoSql cosmoDB.
 /// <para>
 /// To load by ConnectionString in appsettings.json use the follow format:<br/>
 /// <i>
 ///  "ConnectionStringKey" : "
 ///  AccountEndpoint=https://accountname.documents.azure.com:443/‌​;
 ///  AccountKey=accountk‌​ey==;
 ///  Database=database"
 /// </i>
 /// </para>
 /// Otherwise, inform connection credentials.
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <param name="provider">service provider</param>
 /// <param name="options">DbContext options builder</param>
 /// <returns>DbContext options builder</returns>
 public static DbContextOptionsBuilder AsCosmosDbContextOptionsBuilder(
     [NotNull] this ContextConnection.Builder builder,
     [NotNull] IServiceProvider provider,
     [NotNull] DbContextOptionsBuilder options)
 {
     return(builder
            .AsCosmos()
            .Configuration(provider)
            .Build()
            .Attach(options));
 }
        internal static IServiceCollection AddDbContextAs(
            [NotNull] this IServiceCollection services,
            [NotNull] Func <ContextConnection.Builder, IServiceProvider, DbContextOptionsBuilder, DbContextOptionsBuilder> dbContextOptionsBuilderCallback,
            [AllowNull] Action <ContextConnection.Builder> builderAction = null,
            [AllowNull] Action <IContextServiceCollection> serviceAction = null,
            [NotNull] ServiceLifetime contextLifetime       = ServiceLifetime.Scoped,
            [NotNull] ServiceLifetime optionsLifetime       = ServiceLifetime.Scoped,
            [AllowNull, CallerMemberName] string memberName = null,
            [AllowNull, CallerFilePath] string filePath     = null)
        {
            if (serviceAction is null)
            {
                throw new InvalidOperationException("Service action not set!\n" +
                                                    "When using DbContext generation by dynamic type, you must set " +
                                                    "services in serviceAction parameter to identify and recover all entities " +
                                                    "target binding to dbContext.");
            }

            using (var service = new ContextServiceTypeCollection())
            {
                var builder = new ContextConnection.Builder().GrantDynamicContext();
                builderAction?.Invoke(builder);
                Action <ContextConnection.Builder> auxBuilderAction = builderAction;
                builderAction = (b) =>
                {
                    b.GrantDynamicContext();
                    auxBuilderAction?.Invoke(b);
                };

                serviceAction.Invoke(service);

                using (var ctBuilder = new ContextTypeBuilder(builder, service))
                {
                    Type dbContextType = ctBuilder.Build();
                    typeof(ContextConnectionExtensions)
                    .GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
                    .First(m => m.Name == nameof(AddDbContextAs) && m.IsGenericMethod)
                    .MakeGenericMethod(dbContextType)
                    .Invoke(null, new object[] {
                        services,
                        dbContextOptionsBuilderCallback,
                        builderAction,
                        serviceAction,
                        contextLifetime,
                        optionsLifetime,
                        memberName,
                        filePath
                    });

                    return(services);
                }
            }
        }
 /// <summary>
 /// Define connection string key to recovery connection string from configurations (appsetings.json).
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <param name="connectionStringKey">connection string access key</param>
 /// <returns>current builder</returns>
 public static ContextConnection.Builder ConnectionStringKey(this ContextConnection.Builder builder, string connectionStringKey)
 {
     return(builder
            .AddConnectionStringKey(connectionStringKey)
            .AddBuildCallback(OnBuildFromConnectionStringCallback));
 }
 /// <summary>
 /// Define configuration from service provider and add callback to build it
 /// as connection string explicit for defined database structure in appseting.json.
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <param name="provider">service provider that contains IConfiguration</param>
 /// <returns>current builder</returns>
 public static ContextConnection.Builder Configuration(this ContextConnection.Builder builder, IServiceProvider provider)
 {
     return(builder.Configuration((provider != null ? provider.GetService <IConfiguration>() :
                                   throw new ArgumentNullException(nameof(provider), "Service provider can not be null!")) /* ??
                                                                                                                            * throw new ArgumentException("Service provider is do not attaching IConfiguration!")*/));
 }
 /// <summary>
 /// Define configuration and add callback to build it
 /// as connection string explicit for defined database structure in appseting.json.
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <param name="configuration">configuration values</param>
 /// <returns>current buider</returns>
 public static ContextConnection.Builder Configuration(this ContextConnection.Builder builder, IConfiguration configuration)
 {
     return(builder
            .AddConfiguration(configuration)
            .AddBuildCallback(OnBuildFromConnectionStringCallback));
 }
 /// <summary>
 /// Mark to build context connection as a NoSql cosmoDB.
 /// <para>
 /// To load by ConnectionString in appsettings.json use the follow format:<br/>
 /// <i>
 ///  "ConnectionStringKey" : "AccountEndpoint=https://accountname.documents.azure.com:443/‌​;AccountKey=accountk‌​ey==;Database=database"
 /// </i>
 /// </para>
 /// Otherwise, inform connection credentials.
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <returns>current builder</returns>
 public static ContextConnection.Builder AsCosmos(this ContextConnection.Builder builder)
 {
     return(builder.AddBuildCallback(OnBuildAsCosmosCallback));
 }
 private static bool OnBuildAsCosmosCallback(ContextConnection.Builder builder, out ContextConnection conn)
 {
     conn = new ContextConnectionCosmos(builder);
     return(true);
 }
 /// <summary>
 /// Mark to build context connection as a PostgresSQL.
 /// <para>
 /// To load by ConnectionString in appsettings.json use the default postgressql format connection
 /// string. Otherwise, inform connection credentials.
 /// </para>
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <returns>current builder</returns>
 public static ContextConnection.Builder AsPostgres([NotNull] this ContextConnection.Builder builder)
 {
     return(builder
            .AddDefaultConnectionStringOperation((b, c) => b.UseNpgsql(o => o.SetPostgresVersion(9, 6)).UseNpgsql(c))
            .AddBuildCallback(OnBuildAsPostgresCallback));
 }
 /// <summary>
 /// Mark to build context connection as a SQLite.
 /// <para>
 /// This context can not be loaded by ConnectionString,
 /// always, inform connection credentials, otherwise will be created a memory database.
 /// </para>
 /// </summary>
 /// <param name="builder">current builder</param>
 /// <returns>current builder</returns>
 public static ContextConnection.Builder AsSqlite([NotNull] this ContextConnection.Builder builder)
 {
     return(builder
            .AddDefaultConnectionStringOperation((b, c) => b.UseSqlite(c))
            .AddBuildCallback(OnBuildAsSqliteCallback));
 }
 private static bool OnBuildAsSqliteCallback(ContextConnection.Builder builder, out ContextConnection conn)
 {
     conn = new ContextConnectionSqlite(builder);
     return(true);
 }
 public ContextTypeBuilder(ContextConnection.Builder builder, IContextServiceTypes service)
 {
     this.builder = builder;
     this.service = service;
 }
 void IDisposable.Dispose()
 {
     this.builder = null;
     this.service = null;
 }