質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

DrylocにDbContextを設定したい。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 848
退会済みユーザー

退会済みユーザー

前提・実現したいこと

DrylocにDbContextを設定したいです、ASP.NET Core MVCはデフォルトのコンテナを利用しましたが、
WPFアプリ(.NET 5)の場合はなかったので、Drylocを使用したいですが、ネットで調べてもやり方がわかりませんでした。

// App.xaml.cs

protected override void RegisterTypes(IContainerRegistry containerRegistry) {
    // appsettings.jsonから接続文字列を取得
    IConfiguration configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: true)
        .Build();

    string connectionString = configuration.GetConnectionString("DbConnection");

    // コンテナのインスタンスを取得する(Dryloc)
    IContainer container = containerRegistry.GetContainer();

    // TestDbContext ※Drylocの場合のやり方がわからない。
    // container.Register<TestDbContext>(ifAlreadyRegistered: IfAlreadyRegistered.AppendNotKeyed);

    /*
    ASP.NET Core MVC(.NET 5)の場合
    services.AddDbContext<TestDbContext>(options => {
        options.UseLazyLoadingProxies();
        options.UseSqlServer(Configuration.GetConnectionString("DbConnection"))
    };
     */ 
}
public class TestDbContext : DbContext {
    public TestDbContext(DbContextOptions<AddDbContext> options) : base(options) {

    }
}

(追記)
Microsoft.Extensions.DependencyInjectionにてDbContextを使用する場合。

// Microsoft.Extensions.DependencyInjection の場合
IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())   
    .AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: true)
    .Build();

IServiceCollection services = new ServiceCollection();
services.AddDbContext<TestDbContext>(options => {
    options.UseLazyLoadingProxies();
    options.UseSqlServer(configuration.GetConnectionString("DbConnection"));
});

ただし、WPFで使用しているPrismフレームワークがDrylocを使用していて、上記のMicrosoft.Extensions.DependencyInjectionが使えないため、Dryloc(またはUnity)が使えればよいのですが。

どなたかご教授お願いします。

(追記 修正) ※元のコードは間違いのため削除しました。
BluOxyさんの回答を元に実際のコードを記載しました。

// ITestDbContext

using Microsoft.EntityFrameworkCore;
using System.Threading;
using System.Threading.Tasks;

namespace DomainModel {
    public interface ITestDbContext {
        // インターフェースのプロパティ・メソッドを使うわけではなさそうなので、
        // DbContextに追加したメソッドは全て定義しなければいけないのかは不明

        // public Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken());

        // DbSet<Department> Departments { get; set; }
    }
}
// TestDbContext

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace DomainModel {
    public class TestDbContext : DbContext, ITestDbContext {

        public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) {

        }

        public async override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) {
            // ...
        }

        /// <summary>
        /// Override OnModelCreating
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            // ...

            base.OnModelCreating(modelBuilder);
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
            string connectionString = "Data Source=...";

            optionsBuilder.UseSqlServer(connectionString);
            optionsBuilder.UseLazyLoadingProxies();

            base.OnConfiguring(optionsBuilder);
        }

        // Test用の適当なクラス
        public DbSet<Department> Departments { get; set; }
    }
}
// App.xaml

using DomainModel;
using DryIoc;
using Microsoft.Extensions.Configuration;
using Prism.DryIoc;
using Prism.Ioc;
using System.IO;
using System.Windows;
using UserInterface.Views;

namespace UserInterface {
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App {
        protected override Window CreateShell() {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry) {
            // appsettings.jsonはDbContextのDomainModelレイヤーに用意して読み込ませるかも
            // (または依存関係が逆転しない他の方法)
            // IConfiguration configuration = new ConfigurationBuilder()
            //     .SetBasePath(Directory.GetCurrentDirectory())
            //     .AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: true)
            //     .Build();

            // Drylocを利用する場合
            var container = containerRegistry.GetContainer();
            container.Register<ITestDbContext, TestDbContext>();
        }
    }
}

appsettings.jsonはDbContextのDomainModelレイヤーに用意して読み込ませることを検討しようと思います。
(または依存関係が逆転しない他の方法)

DbContextインターフェースには、DbContextに追加したメソッドは全て定義しなければいけないのかはまだ不明ですが。

また、下記のPMのコマンドが使えなくなってしまいました。プロジェクト(レイヤー)の指定は間違っていないのですが。
※標準のDI(Microsoft.Extensions.DependencyInjectionの時)に使えていたPMコマンドではありますが。

PM > Add-Migration init -Context TestDbContext -o "Migrations/TestDb"
PM > Update-Database -Context TestDbContext

エラー内容

Build started...
Build succeeded.
Unable to create an object of type 'TestDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

(追記)PMコマンドでエラーしたので、デフォルトの引数無しコンストラクタを追加して対処しました。
PMコマンドが実行できるようになりました。

// TestDbContext

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace DomainModel {
    public class TestDbContext : DbContext, ITestDbContext {

        public TestDbContext() {

        }

        public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) {

        }

        public async override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) {
            // ...
        }

        /// <summary>
        /// Override OnModelCreating
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            // ...

            base.OnModelCreating(modelBuilder);
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
            string connectionString = "Data Source=...";

            optionsBuilder.UseSqlServer(connectionString);
            optionsBuilder.UseLazyLoadingProxies();

            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<Department> Departments { get; set; }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2021/04/06 20:59

    「もう少しだけ質問をオープン」ということですがもう十分では? 放置しておかないで、自分で回答欄に何か書いてクローズできませんか。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2021/04/07 15:28

    回答をクローズさせていただきました。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2021/04/08 16:52

    回答を再オープンさせていただきました。

    キャンセル

回答 3

checkベストアンサー

+1

下記リンクは今回の要件に沿うのではないでしょうか。DbContext を DI するには DbContext のインタフェースを定義する必要があります。

[C#][WPF][EF]Entity Framework で DB にアクセスする際コンテキストのオブジェクトが自動的に注入されるよう DI 機能を WPF アプリに実装したい


サービス層のプロジェクトにappsettings.jsonを置くのはどうかなと思い、悩み中です。

外からオブジェクトをもらっていきましょう。

public class TestDbContext : DbContext {
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
        optionsBuilder.UseSqlServer("Data Source=tests.db");
        base.OnConfiguring(optionsBuilder);
    }
}
// App.xaml

using DomainService;
using DryIoc;
using Prism.DryIoc;
using Prism.Ioc;
using System.Windows;
using UserInterface.Views;

namespace UserInterface {
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App {
        protected override Window CreateShell() {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry) {
            // Drylocを利用する場合
            var container = containerRegistry.GetContainer();
            container.Register<IDbContextService, DbContextService>(ifAlreadyRegistered: IfAlreadyRegistered.AppendNotKeyed);
            container.Register<ITestDbContext, TestDbContext>();
        }
    }
}
// DbContextService

using DomainModel;
using Microsoft.EntityFrameworkCore;

namespace DomainService {

    public class DbContextService : IDbContextService {
        private readonly ITestDbContext _context;
        public DbContextService(ITestDbContext context) {
            this._context = context;
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/04/09 09:49 編集

    昨日質問欄のコードの追記分について、誤りがありましたので訂正させていただきました。
    教えて頂いたDbContextインターフェースとOnConfiguringの方法で対応しました。

    DbContextインターフェースには、DbContextに追加したメソッドは全て定義しなければいけないのかは
    すみませんが理解できていないです。

    また、標準のDI(Microsoft.Extensions.DependencyInjectionの時)に
    使えていたPMコマンドが使えなくなってしまいました。

    PM > Add-Migration init -Context TestDbContext -o "Migrations/TestDb"
    PM > Update-Database -Context TestDbContext

    Build started...
    Build succeeded.
    Unable to create an object of type 'TestDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

    のエラーになってしまってます。もしご存じであればご教授お願いしたく。

    キャンセル

  • 2021/04/09 11:20

    https://stackoverflow.com/questions/55123853/unable-to-create-an-object-of-type-dbcontexts-name-for-the-different-patte

    > In Package Manager Console, set your data access layer (if any) as a default project

    を試すとどうでしょうか。EF を使っていて同じようなエラーにはまっていたことがありますが、そのときは上記のような対応をした記憶があります

    キャンセル

  • 2021/04/09 11:42 編集

    教えて頂いた記事を参考にし、TestDbContextにデフォルトのコンストラクタを作成するとエラーがでなくなりました。ありがとうございます。

    public TestDbContext() {

    }

    質問欄へデフォルトのコンストラクタについて追記しました。

    キャンセル

+1

ASP.NET Core MVCはデフォルトのコンテナを利用しましたが、WPFアプリ(.NET 5)の場合はなかったので、Drylocを使用したいですが

「WPFアプリ(.NET 5)の場合はなかった」というのは Visual Studio のテンプレートで作ったプロジェクトには実装されてなかったということだと理解していますが、そういう場合は Microsoft.Extensions.DependencyInjection 名前空間にあるクラス類を使って自力で実装できます。

具体例は、コンソールアプリと Windows Forms の場合ですが、以下の記事を見てください。

.NET Core での Dependency Injection
http://surferonwww.info/BlogEngine/post/2021/01/01/dependency-injection-for-dotnet-core-application.aspx

Windows Forms で IHttpClientFactory 利用 (CORE)
http://surferonwww.info/BlogEngine/post/2021/03/12/how-to-use-ihttpclientfactory-in-windows-forms-application.aspx

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/03/23 13:37

    ご回答ありがとうございます。
    .NET Core での Dependency Injectionの記事を読ませて頂きます。

    キャンセル

  • 2021/03/23 13:46 編集

    Microsoft.Extensions.DependencyInjection 名前空間にあるクラス類を使って自力で実装してみたところ、下記のコードでエラーが表示されなくなりました。実際に動作させて試してみたいと思います。

    IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: true)
    .Build();

    IServiceCollection services = new ServiceCollection();
    services.AddDbContext<TestDbContext>(options => {
    options.UseLazyLoadingProxies();
    options.UseSqlServer(configuration.GetConnectionString("DbConnection"));
    });

    キャンセル

  • 2021/03/23 13:58

    上記のコードでコンストラクタ注入が確認できました、ありがとうございます。

    Microsoft.Extensions.DependencyInjection は標準のDIなのでこれは良さそうですね。

    キャンセル

0

下記のように対応しました。

// Microsoft.Extensions.DependencyInjection の場合

using DomainModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Configuration;
using System.IO;
using System.Windows;
using UserInterface.Views;

namespace UserInterface {
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App {

        public IConfiguration Configuration { get; }
        public IServiceCollection services { get; }

        public App() {
            Configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: true)
                .Build();

            services = new ServiceCollection();
        }

        protected override Window CreateShell() {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry) {
            // Microsoft.Extensions.DependencyInjection の場合
            services.AddDbContext<TestDbContext>(options => {
                options.UseLazyLoadingProxies();
                options.UseSqlServer(Configuration.GetConnectionString("DbConnection"));
            });
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/04/07 19:24

    今この質問に気づきました。
    私はWPFのDIコンテナにPrism.Unityを使用しています。Prism.DryIocもあるので、Prismを使うという選択肢もあるということをお伝えしておきます。
    https://qiita.com/nori0__/items/ba9f4c84fd3818287ad4

    キャンセル

  • 2021/04/08 15:51 編集

    コメントありがとうございます。
    Prism.Unity か Prism.DryIocのどちらかと使いたいと考えていました。

    教えて頂いたURLの記事がとても参考になります。確認します。

    もしよろしければ、PrismのDI(Unityでも大丈夫です。) の場合で、
    DbContextを使う方法をご存じであれば、ご教授お願いしたいです。


    自己解決は未解決に戻させて頂きました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る