カスタムDbContext
を実装するクラスライブラリを開発しようとしています。 SaveChanges
のDbContext
メソッドでは、監査のために現在のユーザーの情報(部門、ユーザー名など)を取得する必要があります。 DbContext
コードの一部を以下に示します。
public override int SaveChanges()
{
// find all changed entities which is ICreateAuditedEntity
var addedAuditedEntities = ChangeTracker.Entries<ICreateAuditedEntity>()
.Where(p => p.State == EntityState.Added)
.Select(p => p.Entity);
var now = DateTime.Now;
foreach (var added in addedAuditedEntities)
{
added.CreatedAt = now;
added.CreatedBy = ?;
added.CreatedByDepartment = ?
}
return base.SaveChanges();
}
頭に浮かぶ2つのオプション:
HttpContext.Items
を使用してユーザー情報を保持し、IHttpContextAccessorを挿入してHttpContext.Items
から情報を取得します(この場合DbContext
はHttpContext
に依存しますが、正しいですか?)HttpContext.Items
の代わりにThreadStaticオブジェクトを使用し、オブジェクトから情報を取得する(ThreadStaticは安全ではないという投稿をいくつか読んだ)質問:私のケースに最適なのはどれですか?あなたが提案する別の方法はありますか?
私は このブログ投稿 でカバーされているこれに似たアプローチを実装し、基本的に依存関係注入を使用して特定のコンテキストにHttpContext
(および基になるユーザー情報)を注入するサービスの作成を含みますが、それを使用したいと思います。
非常に基本的な実装は次のようになります。
public class UserResolverService
{
private readonly IHttpContextAccessor _context;
public UserResolverService(IHttpContextAccessor context)
{
_context = context;
}
public string GetUser()
{
return _context.HttpContext.User?.Identity?.Name;
}
}
これを、Startup.cs
ファイルのConfigureServices
メソッド内のパイプラインに挿入するだけで済みます。
services.AddTransient<UserResolverService>();
そして最後に、指定したDbContext
のコンストラクタ内でアクセスします。
public partial class ExampleContext : IExampleContext
{
private YourContext _context;
private string _user;
public ExampleContext(YourContext context, UserResolverService userService)
{
_context = context;
_user = userService.GetUser();
}
}
次に、_user
を使用して、コンテキスト内の現在のユーザーを参照できます。これは、現在のリクエスト内で利用可能なコンテンツを格納/アクセスするように簡単に拡張できます。