Reputation: 869
I using CleanArchitecture solution. I have Data layer where ApplicationDbContext and UnitOfWork are located :
namespace Portal.Data.MyDbContexts
{
internal class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
Database.EnsureCreated();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BaseEntity).Assembly);
}
// **********
public DbSet<WebsiteMonitoredCategory> WebsiteMonitoredCategories { get; set; }
// **********
}
unitofwork:
public abstract class BaseUnitOfWork : object, IBaseUnitOfWork
{
//public UnitOfWork() : base()
//{
//}
public BaseUnitOfWork(Options options) : base()
{
Options = options;
}
// **********
protected Options Options { get; set; }
// **********
// **********
// **********
// **********
private ApplicationDbContext _databaseContext;
// **********
// **********
/// <summary>
/// Lazy Loading = Lazy Initialization
/// </summary>
internal ApplicationDbContext DatabaseContext
{
get
{
if (_databaseContext == null)
{
var optionsBuilder =
new DbContextOptionsBuilder<ApplicationDbContext>();
switch (Options.Provider)
{
case Provider.SqlServer:
{
optionsBuilder.UseSqlServer
(connectionString: Options.ConnectionString);
break;
}
case Provider.MySql:
{
//optionsBuilder.UseMySql
// (connectionString: Options.ConnectionString);
break;
}
case Provider.Oracle:
{
//optionsBuilder.UseOracle
// (connectionString: Options.ConnectionString);
break;
}
case Provider.PostgreSQL:
{
//optionsBuilder.UsePostgreSQL
// (connectionString: Options.ConnectionString);
break;
}
case Provider.InMemory:
{
optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");
break;
}
default:
{
break;
}
}
_databaseContext =
new ApplicationDbContext(options: optionsBuilder.Options);
}
return _databaseContext;
}
}
and I have IoC Layer too for dependency injection to presentation layer:
public class DependencyContainer
{
public static void RegisterServices(IServiceCollection services,IConfiguration configuration)
{
//DataLayer
services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
{
Options options =
new Options
{
Provider =
(Provider)System.Convert.ToInt32(configuration.GetSection(key: "DatabaseProvider").Value),
ConnectionString =
configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
};
return new UnitOfWork(options: options);
});
}
}
and finally I Have an Windows Forms application Net 5.0 (All Projects are Net5.0)
namespace Portal.Desktop
{
public static class Program
{
private static IConfiguration Configuration { get; set; }
public static IServiceProvider ServiceProvider { get; set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
var services = ConfigureServices();
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
Configuration = builder.Build();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
RegisterServices(services, Configuration);
}
public static void RegisterServices(IServiceCollection services, IConfiguration configuration)
{
DependencyContainer.RegisterServices(services, configuration);
}
public static IServiceCollection ConfigureServices()
{
var services = new ServiceCollection();
//services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
//{
// Options options =
// new Options
// {
// Provider =
// (Provider)System.Convert.ToInt32(Configuration.GetSection(key: "DatabaseProvider").Value),
// //using Microsoft.EntityFrameworkCore;
// //ConnectionString =
// // Configuration.GetConnectionString().GetSection(key: "MyConnectionString").Value,
// ConnectionString =
// Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
// };
// return new Portal.Data.UoW.UnitOfWork(options: options);
//});
ServiceProvider = services.BuildServiceProvider();
return services;
}
}
}
I usage Ef core 5.0 , windows forms is set as startup project and package manager console set to Protal.Data (dbcontext and unitofwork in there) but when i run Add-Migration inti in PMC get me an error:
Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
installed this packages in data layer:
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
I don't know why, get me the error.
-----UPDATE----
I follow the https://go.microsoft.com/fwlink/?linkid=851728 and added ApplicationDbContextFactory.cs to Portal.Desktop (windows forms Net5.0) project:
namespace Portal.Desktop
{
public class ApplicationDbContextFactory:IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
var connectionString = Program.Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value;
var provider = Program.Configuration.GetSection(key: "DatabaseProvider").Value;
var optionsBuilder =
new DbContextOptionsBuilder<ApplicationDbContext>();
var options =
new Options
{
Provider =
(Provider)System.Convert.ToInt32(provider),
//using Microsoft.EntityFrameworkCore;
//ConnectionString =
// Configuration.GetConnectionString().GetSection(key: "MyConnectionString").Value,
ConnectionString = connectionString,
};
switch (options.Provider)
{
case Provider.SqlServer:
{
optionsBuilder.UseSqlServer
(connectionString: options.ConnectionString);
break;
}
case Provider.MySql:
{
//optionsBuilder.UseMySql
// (connectionString: Options.ConnectionString);
break;
}
case Provider.Oracle:
{
//optionsBuilder.UseOracle
// (connectionString: Options.ConnectionString);
break;
}
case Provider.PostgreSQL:
{
//optionsBuilder.UsePostgreSQL
// (connectionString: Options.ConnectionString);
break;
}
case Provider.InMemory:
{
optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");
break;
}
default:
{
break;
}
}
return
new ApplicationDbContext(options: optionsBuilder.Options);
}
}
}
When I want add a migration ef core throw Exception has been thrown by the target of an invocation. exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object. at Portal.Desktop.ApplicationDbContextFactory.CreateDbContext(String[] args) in C:\Users\Arman Es\source\repos\Spider\Portal.Desktop\ApplicationDbContextFactory.cs:line 20 --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContextFromFactory(Type factory, Type contextType) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_2.b__9() at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 factory) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0
1.b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) Exception has been thrown by the target of an invocation.
Upvotes: 0
Views: 2896
Reputation: 869
finally, I found my answers in this article https://snede.net/you-dont-need-a-idesigntimedbcontextfactory/
Create ApplicationDbContextFactory in Portal.Data project:
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using Portal.Domain.Tools;
using Portal.Domain.Tools.Enums;
namespace Portal.Data.MyDbContexts
{
public class ApplicationDbContextFactory:IDesignTimeDbContextFactory<ApplicationDbContext>
{
private IConfiguration Configuration { get; set; }
public ApplicationDbContext CreateDbContext(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
var optionsBuilder =
new DbContextOptionsBuilder<ApplicationDbContext>();
var options =
new Options
{
Provider =
(Provider)System.Convert.ToInt32(Configuration.GetSection(key: "DatabaseProvider").Value),
ConnectionString = Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value
};
switch (options.Provider)
{
case Provider.SqlServer:
{
optionsBuilder.UseSqlServer
(connectionString: options.ConnectionString);
break;
}
case Provider.MySql:
{
//optionsBuilder.UseMySql
// (connectionString: Options.ConnectionString);
break;
}
case Provider.Oracle:
{
//optionsBuilder.UseOracle
// (connectionString: Options.ConnectionString);
break;
}
case Provider.PostgreSQL:
{
//optionsBuilder.UsePostgreSQL
// (connectionString: Options.ConnectionString);
break;
}
case Provider.InMemory:
{
optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");
break;
}
default:
{
break;
}
}
return
new ApplicationDbContext(options: optionsBuilder.Options);
}
}
}
appsettings.json still in Portal.Desktop project:
namespace Portal.Desktop
{
public static class Program
{
public static IConfiguration Configuration { get; set; }
public static IServiceProvider ServiceProvider { get; set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
var services = ConfigureServices();
RegisterServices(services, Configuration);
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
public static void RegisterServices(IServiceCollection services, IConfiguration configuration)
{
DependencyContainer.RegisterServices(services, configuration);
}
public static IServiceCollection ConfigureServices()
{
var services = new ServiceCollection();
ServiceProvider = services.BuildServiceProvider();
return services;
}
}
}
and finally IoC project is:
namespace Portal.IoC
{
public class DependencyContainer
{
public static void RegisterServices(IServiceCollection services,IConfiguration configuration)
{
//DataLayer
services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
{
var options =
new Options
{
Provider =
(Provider)System.Convert.ToInt32(configuration.GetSection(key: "DatabaseProvider").Value),
ConnectionString =
configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
};
return new UnitOfWork(options: options);
});
}
}
}
Upvotes: 1