1

Entity Frameworkを介してT-SQLデータベースによって提供されるデータストレージを使用して、ASP.NET MVC 4を使用してWebアプリを構築しています。私は監査ログを統合しており、人間が判読できるアクションの要約を提供したいと考えています。これにより、「ユーザー Bob がログインしました」、「ユーザー Alice 」などの明確なステートメントを使用してわかりやすいログ ビューを表示できます。更新記事「Foo」」など

現在、監査レコードは次のもので構成されています。

  • GUID
  • タイムスタンプ
  • ユーザーID
  • アクションカテゴリ(コントローラ名)
  • action (アクションメソッド名)
  • IsError (ブール値。true は、これがエラーの記録であるか、このアクションが正常に完了しなかったことを意味します)
  • シリアル化された詳細の塊

現時点では、私のロギングは実装するカスタム属性を使用していますIActionFIlter。メソッドはOnActionExecuting()試行されたアクションをログに記録し (URL、パラメーターなどを詳細 blob にシリアル化)、OnActionExecuted()メソッドは戻り、エラーがない場合は IsError を true に設定し、返された結果または例外をエラー メッセージやスタック トレースなどと共に追加します。詳細へ。説明文字列用に別の列を追加したいのですが、きちんとした方法がわかりません。

私が得た最も遠いのは、「User $user logged in」のような文字列を属性に渡し、ログメソッドで文字列をスキャンして $ 文字を探し、その単語をキー値が一致するパラメーター辞書の何かに置き換えることでした単語 (マイナス $ 文字)。これは少し制限されています。例えば記事をID番号で保存する場合、「ユーザー18が編集した記事37」が一番管理しやすいです。ユーザー名や記事のタイトルを取得する実際の方法はありません。コンパイル時に組み込まれているため、インスタンスデータを属性に渡すことはできません。また、ロギングメソッドがその種のデータを取得するためにあらゆる種類のデータベース呼び出しを行うことを本当に望んでいません。 (または少なくとも本当の苦痛)単一の汎用ロギング方法を持つこと。

これに代わる方法は、静的な監査ログ クラスをAuditRecord.WriteLog(foo);用意し、さまざまな種類のアクションを記述するために使用 (または継承) できる何らかの種類の記述子クラスを使用して、あらゆる場所で何かを呼び出し、すべてのパラメーターを格納し、生成することです。必要に応じて説明文字列を追加しますが、私にはエレガントではないようです。[AuditLog]メソッドの上にタグを付けるだけで、それが記録されることを知ることができるのが本当に気に入っています。

コントローラーとアクション名を大きな switch ステートメントで使用して正しい文字列テンプレートを選択するなど、膨大な量の条件付きロジックは避けたいと思います。ロギングメソッドで記事のタイトルなどを把握できればOKです。これを行うためのきちんとした簡単な方法はありますか?

4

3 に答える 3

1

最近、監査履歴のログ記録と、新しい MVC プロジェクト全体へのより複雑なセキュリティ ルールの適用の両方について、職場で同様の議論がありました。

最終的に、私たちが思いついた最も「エレガントな」ソリューションは、メソッド呼び出しをコントローラー アクション内に持つことでした (代替メソッド)。

例えば:

[HttpPost]
public ActionResult CreateItem(Item item)
{
    //Simplified
    CheckSecurity(SecurityTypes.ItemCreation);
    LogActivity("Created an item");

    //Rest of action code

}

これにより、考えられるすべてのユースケースに対応できる柔軟性が得られ、ロジックを単純な使用方法にまとめてコードの繰り返しを減らすことができました。

于 2013-03-12T16:12:02.977 に答える
0

回答が遅くなるかもしれませんが、アクション フィルター属性を使用し続け、リクエストごとのライフサイクル オブジェクトにアクセスできるようにする良い代替手段があると思います。

アナキシマンダーが上で指摘したように、根本的な問題は、属性が CLR によって解決されるため、属性の有効期間を制御できず、IC コンテナーとうまく混合できないことです (要求インスタンスごとに一時的にするためなど)。

通常、.NET では、リフレクション(メソッド)によって解決されるたびに、属性の新しいインスタンスが作成されます。GetCustomAttribute

また、MVC/webapi の場合、アクション フィルター属性はキャッシュされるため、通常は 1 回だけ作成されます。

結論として、属性は注釈のみを目的として設計されています。つまり、属性にはメタデータのみを含める必要があります(それらは DTO です)。残念ながら、私の理解では、MVC と WebApi フレームワークはこのように設計されていません。アクション フィルター属性を単純な DTO に制限し、それらの周りのロジック部分のライフサイクルを管理できるようにするには、特別な手段を講じる必要があります。

あなたのユース ケースは、Steven van Deursen の素晴らしい記事で提供されているソリューションに完全に適合すると思います。属性データをロジックから分離する方法を示します。これは、ioc コンテナーを依存関係として、グローバルに登録されたアクション フィルター (いわゆる「ディスパッチャー」) に基づいています。 コンテナは静的に解決されていません. これは、アプリケーションの初期化時に登録されるときに、グローバル フィルターのコンストラクターで提供されます。したがって、実行されるたびに、実行中のアクションの属性マーカーが検索され、属性が汎用パラメーターである汎用インターフェイスが解決されます。データと動作をマージするアクション フィルター属性を使用する代わりに、2 つのクラスを使用することになります。プレーンな古い属性 (マーカー) と、それに対応するロジックのジェネリック インターフェイスの対応する実装です。コンテナーは、ジェネリック インターフェイスを解決するために使用されます。フィルターが要求ごとのコンポーネントに依存している場合は、必要なサービスを備えた汎用インターフェイスの実装を作成できます。他のサービスに依存していないが、リクエストごとの有効期間が必要な場合 (たとえば、アクションの開始から終了までの時間を測定するため)、コンテナーを使用してジェネリックを解決するおかげで、それも機能します。インターフェース。前述の記事には、WebApi、MVC、および ASP.NET 5 のコード例が含まれています。

また、Mark Seemann は同じアプローチに関する記事を作成しています。

認証フィルターやおそらく例外フィルターなど、すべてのケースに適切なソリューションを提供するとは思いませんが、私にとっては、多くのアクション フィルターにとって最もエレガントな方法です。

于 2015-10-10T21:29:09.550 に答える