IdentityServer — ConfigurationDbContext でのクロスコンテキストトランザクション
Tags: identityserver4, aspnetcore, dotnet
Published: 2019-05-21 16:29:42

---
title: IdentityServer — ConfigurationDbContext でのクロスコンテキストトランザクション
published: true
tags: identityserver4,aspnetcore,dotnet
canonical_url: https://medium.com/@joni2nja/identityserver-configurationdbcontext-%E3%81%A7%E3%81%AE%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3-8b40f5019afc
---
This post originally appeared on [Medium](https://medium.com/@joni2nja/identityserver-configurationdbcontext-%E3%81%A7%E3%81%AE%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3-8b40f5019afc)

___

### IdentityServer - ConfigurationDbContext でのクロスコンテキストトランザクション

#### ConfigurationDbContext を使ってクロスコンテキストトランザクションを処理するには？

![](https://cdn-images-1.medium.com/max/980/1*W94KJYyivaOCXCRJEo-gqA.png)

IdentityServer とは？

> IdentityServer is a free, open source OpenID Connect and OAuth 2.0 framework for ASP.NET Core. Founded and maintained by Dominick Baier and Brock Allen, IdentityServer4 incorporates all the protocol implementations and extensibility points needed to integrate token-based authentication, single-sign-on and API access control in your applications.

詳細はこちらのリンク↓↓↓

[Welcome to IdentityServer4 - IdentityServer4 1.0.0 documentation](https://identityserver4.readthedocs.io/en/latest/)

IdentityServer4 の構成データ (Configuration Data) を EF Core を使って DB に保存することはできます。構成データは「[リソース](http://docs.identityserver.io/en/latest/intro/terminology.html#resources)」と「[クライアント](http://docs.identityserver.io/en/latest/intro/terminology.html#client)」を管理します。

EF Core での構成データの詳細についてはこちら↓↓↓

[Using EntityFramework Core for configuration and operational data - IdentityServer4 1.0.0 documentation](http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html)

本題に入ります。

例えば、ビジネスルールのニーズで、アプリケーションの DB Context でデータを追加する必要があり、それと同時にクライアントを追加する必要があるとします。つまり、セットで追加で処理する必要があります。

クライアントのクラスの定義は [ConfigurationDbContext](https://github.com/IdentityServer/IdentityServer4/blob/8f5a4ed926c5c76bf76d7397fae3ce2f4795fd74/src/EntityFramework.Storage/src/DbContexts/ConfigurationDbContext.cs) に存在します。ctor の定義はこんな感じ：

```cs
public ConfigurationDbContext(DbContextOptions<TContext> options, ConfigurationStoreOptions storeOptions)
 : base(options)
```

この ConfigurationDbContext は IdentityServer のもので、アプリケーションの DB Context と異なるため、それぞれを dbContext.SaveChanges() （あるいは await dbContext.SaveChangesAsync() ）で処理すると、仮に例外が発生した場合に整合性がとれなくなってしまいます。

EF Core でクロスコンテキストトランザクションはサポートされていますので、実現可能です。

[Transactions - EF Core](https://docs.microsoft.com/en-us/ef/core/saving/transactions#cross-context-transaction-relational-databases-only)

条件としては、

> Sharing a DbConnection requires the ability to pass a connection into a context when constructing it.

> The easiest way to allow DbConnection to be externally provided, is to stop using the DbContext.OnConfiguring method to configure the context and externally create DbContextOptions and pass them to the context constructor.

そして、

> DbContextOptionsBuilder is the API you used in DbContext.OnConfiguring to configure the context, you are now going to use it externally to create DbContextOptions.

だそうです。

簡単そうですね！

サンプルコードはこんな感じで DbContextOptions を生成します。

```cs
var options = new DbContextOptionsBuilder<BloggingContext>()
 .UseSqlServer(new SqlConnection(connectionString))
 .Options;
```

それを ConfigurationDbContext ctor に渡せばいいよね～！！と喜ぶのも束の間・・・

ctor の2番目のパラメータって、 ConfigurationStoreOptions を渡しますよね。DI でこれを気にする必要がなく、やってくれていますので、正しいパラメータはわかりません。。。適当に渡してみてエラーが発生します。デバッグとかで少し時間があればできそうですが、簡単な方法でやりたいです！  
そういえば、アプリケーションの DB Context って我々が自由に触れるので、まずそれを使いましょう！ctor は DbContextOptions を渡せるようにします。

こちらの[サンプル](https://docs.microsoft.com/en-us/ef/core/saving/transactions#share-connection-and-transaction)で話しますと、 context1 は ConfigurationDbContext に例えて、それをそのまま DI からのインスタンスを使い、14行目の：

```cs
using (var context2 = new BloggingContext(options))
```

をこんな感じで context1 の DB コネクションを context2 と共有させます↓

```cs
using (var context2 = new ApplicationDbContext(
 new DbContextOptionsBuilder<ApplicationDbContext>()
 .UseSqlServer(context1.Database.GetDbConnection())
 .Options))
```

はい、これでシンプルで問題解決！