ASP.NET Core 2.0にアップグレードした後、移行を作成できなくなったようです。
なってます
「クラス「Program」でメソッド「BuildWebHost」の呼び出し中にエラーが発生しました。アプリケーションサービスプロバイダを使用せずに続行します。エラー:1つ以上のエラーが発生しました。ユーザー '...'で失敗しました
そして
"'MyContext'型のオブジェクトを作成できません。 'IDesignTimeDbContextFactory'の実装をプロジェクトに追加するか、 https://go.Microsoft.com/fwlink/?linkid=851728を参照してください。設計時にサポートされる追加のパターンについては を参照してください。」
私が以前に実行したコマンドは$ dotnet ef migrations add InitialCreate --startup-project "..\Web"
でした(DBContextを持つプロジェクト/フォルダーから)。
接続文字列:"Server=(localdb)\\mssqllocaldb;Database=database;Trusted_Connection=True;MultipleActiveResultSets=true"
これは私のProgram.csです
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
Webプロジェクト内にIDesignTimeDbContextFactoryを実装するクラスを追加できます。
これがサンプルコードです。
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<CodingBlastDbContext>
{
public CodingBlastDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<CodingBlastDbContext>();
var connectionString = configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
return new CodingBlastDbContext(builder.Options);
}
}
次に、データベースプロジェクトに移動して、コマンドラインから次のコマンドを実行します。
dotnet ef migrations add InitialMigration -s ../Web/
dotnet ef database update -s ../Web/
-s stands for startup project and ../Web/ is the location of my web/startup project.
_ IDesignTimeDbContextFactory
は必要ありません。
実行する
add-migration initial -verbose
それはの下の詳細を明らかにするでしょう
クラス 'Program'のIWebHostにアクセス中にエラーが発生しました。アプリケーションサービスプロバイダなしで続行します。
これは問題の根本的な原因です。
私の場合、問題はApplicationRole : IdentityRole<int>
を持っていてservices.AddIdentity<ApplicationUser, IdentityRole>()
を呼び出すことでした。
System.ArgumentException: GenericArguments[1], 'Microsoft.AspNetCore.Identity.IdentityRole',
on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,
TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type 'TRole'.
---> System.TypeLoadException: GenericArguments[1], 'Microsoft.AspNetCore.Identity.IdentityRole',
on 'Microsoft.AspNetCore.Identity.UserStoreBase`8[TUser,TRole,TKey,TUserClaim,
TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type parameter 'TRole'.
私の場合、問題の原因は複数のスタートアッププロジェクトでした。私のソリューションにはMvc、Api、Dalの3つのプロジェクトがあります。 DalプロジェクトのDbContextとMigrations。
複数のスタートアッププロジェクトを設定しました。 [スタート]をクリックしたときに、MvcプロジェクトとApiプロジェクトの両方が実行されていました。しかし、この場合私はこのエラーを受けていました。
"'MyContext'型のオブジェクトを作成できません。 'IDesignTimeDbContextFactory'の実装をプロジェクトに追加するか、 https://go.Microsoft.com/fwlink/?linkid=851728を参照してください。設計時にサポートされる追加のパターンについては を参照してください。」
Mvcを唯一のスタートアッププロジェクトとして設定し、Package ManagerコンソールでDalを選択した後、移行を追加することに成功しました。
より良い解決策:
スタートアッププロジェクトがASP.NET Core
アプリの場合、ツールはアプリケーションのサービスプロバイダーからDbContext
オブジェクトを取得しようとします。
ツールは、最初にProgram.BuildWebHost()
を呼び出してIWebHost.Services
プロパティにアクセスして、サービスプロバイダーの取得を試みます。
program.csのMain Methodの後にこのメソッドを追加します
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
。netコア2.2の更新
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
その他の可能な解決策:
依存関係の注入にDbcontext
を追加したことを確認してください:AddDbContext<TContext>
は、DbContext型TContext
と、対応するDbContextOptions<TContext>
の両方をサービスコンテナから注入できるようにします。これには、DbContextOptions<TContext>
を受け入れるDbContext
型にコンストラクター引数を追加する必要があります。
例:Startup.csで
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
}
AppDbContextコード:
public class AppDbContext: DbContext
{
public AppDbContext(DbContextOptions<BloggingContext> options)
:base(options)
{ }
}
更新: Webアプリケーションプロジェクトを「スタートアッププロジェクトとして設定」に設定
Visual StudioのメニューTools
-> NuGet Package Manger
-> Package Manager Console
からパッケージマネージャーコンソールを開き、次のコマンドを実行します。
Add-Migration Init -Verbose
注:
–verbose
オプションを使用して、ターゲットデータベースに適用されているSQLステートメントを表示します。詳細なエラーが含まれています。
AppContextクラス以外のAppContext.csに別のクラスを追加します。
// required when local database deleted
public class ToDoContextFactory : IDesignTimeDbContextFactory<AppContext>
{
public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseSqlServer("Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true");
return new AppContext(builder.Options);
}
}
これで2番目の問題が解決します。
「タイプ 'MyContext'のオブジェクトを作成できません。 'IDesignTimeDbContextFactory'の実装をプロジェクトに追加してください。
その後、add-migration Initialを実行し、update-databaseコマンドを実行して実行できます。ただし、ローカルSqlServerにまだデータベースがないときにこれらのコマンドを実行すると、最初のエラーのような警告が表示されます。
クラス 'Program'でメソッド 'BuildWebHost'の呼び出し中に発生しました...ログインに失敗しました。ユーザー '...'のログインに失敗しました
しかし、移行が作成され実行されるため、エラーではありません。そのため、このエラーを最初に無視してください。後者はDbが存在するため、再び発生することはありません。
本当に役に立ったのはこの記事です: https://elanderson.net/2017/09/unable-to-create-an-object-of-type-applicationdbcontext-add-an- idesigntimedbcontextfactoryの実装/
基本的な考え方は、.netコア1から2への切り替えでは、すべてのdb初期化をStartUp.csからProgram.csに移動する必要があるということです。そうでなければ、EFタスクはタスクを実行するときにDB initsを実行しようとします。
"公式の移行ドキュメントにNiceセクションがあります( https://docs.Microsoft.com/ja-jp/ef/core/miscellaneous/1x-2x-upgrade )「移動データベース初期化コード」と題していますが、私が見逃していたようです。IdesignTimeDbContextFactoryの実装を追加する必要があるのは、これが原因ではないことを確認します。
参照があることを確認してください
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
マイグレーションではデフォルトでこのメソッドが使用されるため、BuildWebHost()
をCreateWebHostBuilder()
に名前変更するだけです。
私はこの問題を抱えていて、これをセット - > Webアプリケーション(含まれているProgram.cs)プロジェクト - > "スタートアッププロジェクトとして設定"で解決しました。
それから - > add-migration initial -verboseを実行します。
パッケージマネージャコンソールで
この記事による に触発された このディスカッション からこの解決策を試すことができます。
public static IWebHost MigrateDatabase(this IWebHost webHost)
{
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var db = services.GetRequiredService<MyContext>();
db.Database.Migrate();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while migrating the database.");
}
}
return webHost;
}
public static void Main(string[] args)
{
BuildWebHost(args)
.MigrateDatabase()
.Run();
}
私の場合は、SeedData.EnsurePopulated()という名前のメソッドが自分のスタートアップで呼び出されていたため、問題が発生しました.csファイル.
public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
//
});
SeedData.EnsurePopulated(app);
}
}
SeedDataクラスの働きは、データベーステーブルに初期データを追加することです。それはコードです:
public static void EnsurePopulated(IApplicationBuilder app)
{
ApplicationDbContext context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
if (!context.Products.Any())
{
context.Products.AddRange(
new Product
{
Name = "Kayak",
Description = "A boat for one person",
Category = "Watersports",
Price = 275
},
....
);
context.SaveChanges();
}
}
解決策
移行を行う前に、単にStartup.csファイルのSeedDataクラスの呼び出しをコメントアウトします。
// SeedData.EnsurePopulated(app);
これで私の問題は解決し、あなたの問題も同じように解決されることを願っています。
以前は、Startup.csのConfigureメソッドでシードデータを設定しました。リクエストパイプラインを設定するためだけにConfigureメソッドを使用することをお勧めします。アプリケーション起動コードはMainメソッドに属します。
リファクタリングされたMainメソッドProgram.csに次の参照を追加します。
microsoft.Extensions.DependencyInjectionを使用します。
myProject.MyDbContextFolderを使用する。
public static void Main(string[] args)
{
var Host = BuildWebHost(args);
using (var scope = Host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<MyDbConext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
Host.Run();
}
これらのIDesignTimeDbContextFactoryを避けたい場合は、起動時にSeedメソッドを使用しないでください。起動時に静的シードメソッドを使用していたため、このエラーが発生していました。
2.0でStartup.Configureからdbをefシードすることに問題があります...あなたはまだこの回避策でそれを行うことができます。テスト済みでうまく機能した
から
https://docs.Microsoft.com/ja-jp/ef/core/miscellaneous/cli/dbcontext-creation
新しいASP.NET Core 2.0アプリケーションを作成すると、このフックは既定で含まれています。以前のバージョンのEF CoreおよびASP.NET Coreでは、ツールはアプリケーションのサービスプロバイダを取得するためにStartup.ConfigureServicesを直接起動しようとしましたが、このパターンはASP.NET Core 2.0アプリケーションでは正しく機能しなくなりました。 ASP.NET Core 1.xアプリケーションを2.0にアップグレードする場合は、新しいパターンに従うようにプログラムクラスを変更できます。
.Net Core 2.xにFactoryを追加する
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
私は同じ問題に遭遇しました。ソリューションには2つのプロジェクトがあります。どれ
- API
- コンテキストモデルを保持するサービスとリポジトリ
当初、APIプロジェクトはスタートアッププロジェクトとして設定されていました。
スタートアッププロジェクトをコンテキストクラスを保持するものに変更しました。使用している場合Visual Studioスタートアッププロジェクトとしてプロジェクトを設定するには:
ソリューションエクスプローラーを開く>>コンテキストプロジェクトを右クリック>>スタートアッププロジェクトとして設定を選択
スタートアップクラスのコンストラクタでjsonファイル(接続文字列がある場所)を設定に追加することもできます。例:
IConfigurationRoot _config;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json");
_config = builder.Build();
}
私は古いMicrosoft.EntityFrameworkCore.Tools.DotNetを参照していたので、私は同じ問題を抱えていました
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
新しいバージョンにアップグレードした後、それは解決しました
まず、Startup.cs
でデータベースを設定していることを確認してください。私の場合、Startup.cs
で以下を指定しなかったため、このエラーが発生していました。
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"), x => x.MigrationsAssembly("<Your Project Assembly name where DBContext class resides>")));
私はこの問題を次のような解決策で抱えていました。
Blazorプロジェクトがスタートアッププロジェクトとして設定されているときに "オブジェクトを作成できません..."というメッセージが表示されますが、MVCプロジェクトがスタートアッププロジェクトとして設定されている場合は表示されません。
これは私を困惑させます。パッケージマネージャコンソール(ここでは移行を作成しています)で、Defaultプロジェクトを実際にDBコンテキストを含むC#クラスライブラリに設定し、さらにDBコンテキストをadd-migration add-migration MigrationName -context ContextName
を呼び出したので、Visual Studioがどのスタートアッププロジェクトが現在設定されているかを気にするのは奇妙に思えます。
Blazorプロジェクトがスタートアッププロジェクトである場合、PMCは.NETのバージョンをスタートアッププロジェクトからCore 3.0に決定し、それを使用して.NET Standard 2.0クラスで移行を実行しようとしているのではないかと思います。ライブラリとある種の衝突を打つ。
原因が何であれ、スタートアッププロジェクトをBlazorプロジェクトではなくCore 2.2をターゲットとするMVCプロジェクトに変更することで問題を解決しました
私は同じ問題を抱えていました。 ap.jasonをapplication.jasonに変更するだけで問題が解決しました
私にとっては、私のスタートアッププロジェクトのOutput Type
をConsole Application
からClass Library
に変更したからです。
Console Application
に戻ることがトリックでした。
メインプロジェクトのappsettings.jsonファイルで、 'Copy to Output directory'を "Copy always"に設定していましたが、うまくいきました。
.netコアコンソールアプリケーション用のサンプルDBコンテキストクラス
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;
namespace EmailServerConsole.Data
{
public class EmailDBContext : DbContext
{
public EmailDBContext(DbContextOptions<EmailDBContext> options) : base(options) { }
public DbSet<EmailQueue> EmailsQueue { get; set; }
}
public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<EmailDBContext>
{
EmailDBContext IDesignTimeDbContextFactory<EmailDBContext>.CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<EmailDBContext>();
var connectionString = configuration.GetConnectionString("connection_string");
builder.UseSqlServer(connectionString);
return new EmailDBContext(builder.Options);
}
}
}