3

よろしくお願いします。(はい、一番下に質問があります)

Unity 3.x Interception を使用して、AOP 前後のデータベース接続とトランザクション アクティビティを実行しています。データベース インターセプターは常にインスタンス化され、トランザクション インターセプターは CustomAttributeMatchingRule ベースであり、両方とも InterfaceInterceptor を介して行われます。TransactionAttribute に設定されているプロパティがあります。

[Transaction(IsolationLevel.ReadUncommitted, NoRollbackFor = new[] { typeof(TestException) })]

単体テストで使用している例として。TransactionCallHandler クラスの呼び出しメソッドでそれらにアクセスしたいと思います。私は言っている例を見てきました

var transactionAttribute = input.MethodBase.GetCustomAttribute<TransactionAttribute>(false);

これにアクセスする方法ですが、私のトランザクション変数は null です。私の結論は、元の具体的なインスタンスではなく、カスタム属性についてインターセプト プロキシ クラスがチェックされているということです。

これに対する私の回避策は、クラスレベルまでさかのぼって反映し、掘り下げてインターセプトされている正しいメソッドが何であるかを突き止め、そこからカスタム属性の取得を実行することです。

var methods = input
  .Target
  .GetType()
  .GetMethods()
  .Where(m => m.Name == input.MethodBase.Name)
  .Where(m => m.GetCustomAttribute<TransactionAttribute>(false) != null);

(メソッドにオーバーロードがある場合に間違ったメソッド名にアクセスしないようにするために、さらに約 30 行のコードがあります。したがって、パフォーマンスが低下します...)

結局のところ、私の質問は次のとおりです。反射を正しく実行していませんか? Unity に報告すべきバグはありますか?

これが私のコンテナ定義です:

Container = new UnityContainer();
Container.AddNewExtension<Interception>();

Container.RegisterType<IMockUseDefaultConnectionString, MockUseDefaultConnectionString>(
  new InterceptionBehavior<PolicyInjectionBehavior>(),
  new Interceptor<InterfaceInterceptor>(),
  new InjectionConstructor(new DatabaseSettings()));

Container.RegisterType<IMockUseHardcodedConnectionString, MockUseHardCodedConnectionString>(
  new InterceptionBehavior<PolicyInjectionBehavior>(),
  new Interceptor<InterfaceInterceptor>(),
  new InjectionConstructor(new DatabaseSettings
    {
      ConnectionString = MockUseHardCodedConnectionString.ConnectionString
    }));
/* IDatabaseSettings is not registered to manually control the settings being used */

var first = new InjectionProperty("Order", 1);
var second = new InjectionProperty("Order", 2);

Container
  .Configure<Interception>()
  .AddPolicy("DatabaseConnectionPolicy")
  .AddMatchingRule<NamespaceMatchingRule>(new InjectionConstructor("MyNamespace.*", true))
  .AddCallHandler<DatabaseConnectionCallHandler>(first);

Container
  .Configure<Interception>()
  .AddPolicy("TransactionPolicy")
  .AddMatchingRule(new CustomAttributeMatchingRule(typeof(TransactionAttribute), inherited: false))
  .AddCallHandler<TransactionCallHandler>(second);
4

3 に答える 3

2

あなたが見ている動作は、インターセプト メソッドの設計の結果だと思います。InterfaceInterceptor を使用すると、ターゲット インターフェイスを実装するプロキシ オブジェクトが作成されますが、プロキシ オブジェクトは元の型とはまったく異なる型になります。

タイプ互換性のある VirtualMethodInterceptor を使用する場合、元のアプローチを使用してカスタム属性を取得できるはずです。もちろん、VirtualMethodInterceptor の欠点は、インターセプトするすべてのメソッドが仮想でなければならないことです。

于 2013-06-21T18:10:32.493 に答える
1

もう 1 つのオプションは、HandlerAttribute からサブクラスを作成することです。詳細については、このSO 投稿を参照するか、この Unity docをお読みください。HandlerAttribute の CreateHandler() の実装では、GetCustomAttributes() を呼び出す必要がないように、属性インスタンスを呼び出しハンドラ インスタンスに渡します。または、1 つのクラスで HandlerAttribute と ICallHandler の両方を実装し、これを返すだけです。

public sealed class AuditAttribute : HandlerAttribute, ICallHandler
{
    #region attribute properties
    public string Key { get; set; } // your own attribute properties

    public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
    {
        return this;
    }

    #endregion

    #region ICallHandler
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        // do stuff ...

        // then
        return getNext()(input, getNext);
    }

    public int Order { get; set; }
    #endregion

}
于 2015-02-27T23:27:46.113 に答える
0

私はいくつかのサンプル コードを調べていて、思いもよらなかった非常に単純なことに気付きました。

コール ハンドラが属性によって作成されたら、必要なパラメータをハンドラのコンストラクタに渡します。次に、それらは属性に使用されているハンドラー インスタンスにあります。問題が解決しました。

于 2015-04-08T19:59:47.920 に答える