chitay-knigi.com » Разная литература » Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 234 235 236 237 238 239 240 241 242 ... 361
Перейти на страницу:
понятия перехвата.

Как уже упоминалось ранее, в случае пересечения вызовом границы контекста (кроме контекста по умолчанию), прокси на вызывающей стороне преобразует вызов в сообщение (объект, реализующий интерфейс IMessage), которое пройдя через цепочку перехватчиков (объектов, реализующих интерфейс IMessageSink), в вызываемом контексте вновь преобразуется в вызов, который исполняется соответствующим объектом. Результат отправляется вызывающей стороне через ту же цепочку перехватчиков.

Каждое свойство контекста может встроить в эту цепочку перехватчиков собственный перехватчик, что и создает возможность неявного вызова нужного сервиса как до, так и после каждого вызова соответствующего объекта. Для этого объект-свойство, приписаваемый контексту, должен реализовать какие-либо из трех интерфейсов:

ICcontributeObjectSink, IContributeServerContextSink, IContributeClientContextSink. Выбор одного из этих интерфейсов определяет ту цепочку перехватчиков, в конец которой будет добавлен новый перехватчик. На самом деле в контексте может существовать несколько цепочек перехватчиков:

• Одна цепочка перехватчиков, перехватывающих все вызовы поступающие ко всем объектам, живущим в данном контексте. Для встраивания перехватчика в эту цепочку объект-свойство контекста должен реализовать интерфейс IContributeServerContextSink.

• По одной цепочке к каждому объекту, живущему в контексте. В эту цепочку вызов попадает пройдя по цепочке общей для всего контекста. Для встраивания перехватчика в эту специфичную для объекта цепочку объект-свойство должен реализовать интерфейс IContributeObjectSink.

• Одна цепочка для всех вызовов, которые объекты контекста делают за пределы данного контекста. Для встраивания перехватчика в эту цепочку объект-свойство должен реализовать интерфейс IContributeClientContextSink.

После этих вводных замечаний о механизме работы атрибута и контекста перейдем к коду атрибута MyCallTraceAttribute и к комментариям к этому коду.

using System;

using System.10;

using System.Threading;

using System.Runtime.Remoting.Messaging;

using System.Runtime.Remoting.Contexts;

using System.Runtime.Remoting.Activation;

using System.Runtime.CompilerServices;

namespace SPbU.AOP_NET{

[AttributeUsage(AttributeTargets.Class)]

public class MyCaiiTraceAttribute: ContextAttribute,

       IContributeServerContextSink {

        private const String PROPERTY_NAME = "MyCallTrace";

        private String _logFileName = null;

        public MyCallTraceAttribute(String logFileName):

           base(PROPERTY_NAME) {

           if (logFileName == null) {

                throw new ArgumentNullException("logFileName");

           }

           _logFileName = logFileName;

}

public override bool IsContextOK(Context ctx,

         IConstructionCallMessage msg) {

         if (ctx == null)

               throw new ArgumentNullException("ctx");

         if (msg == null)

                throw new ArgumentNullException("msg");

         MyCallTraceAttribute property =

               (MyCallTraceAttribute)ctx.GetProperty(PROPERTY_NAME)

        if ((property!= null) &&

             (property._logFileName == _logFileName))

              return true;

        else

              return false;

}

public override void GetPropertiesForNewContext {

       IConstructionCallMessage ctorMsg) {

       ctorMsg.ContextProperties.Add((IContextProperty) this);

}

public virtual IMessageSink GetServerContextSink {

       IMessageSink nextSink) {

        MyCallTraceServerContextSink propertySink =

            new MyCallTraceServerContextSink(this, nextSink);

         return (IMessageSink)propertySink;

}

 [Methodlmpl(MethodImplOptions.Synchronized)]

 internal void LogMessage(String msg){

         StreamWriter logFile = null;

         while (logFile == null) {

                 logFile = File.AppendText(_logFileName);

         }

         logFile.WriteLine(msg);

         logFile.Close();

    }

}

internal class MyCallTraceServerContextSink: IMessageSink {

         internal IMessageSink _nextSink;

         internal MyCallTraceAttribute _property;

         internal IMessage _replyMsg;

         internal MyCallTraceServerContextSink {

              MyCaiiTraceAttribute property, IMessageSink nextSink) {

                _property = property;

                _nextSink = nextSink;

                _replyMsg = null;

     {

     public virtual IMessage SyncProcessMessage(IMessage reqMsg) {

            if (reqMsg is IMethodMessage) {

                 IMethodMessage call = reqMsg as IMethodMessage;

                lock(_property){

                       _property.LogMessage("===" + call.TypeName);

                       _property.LogMessage("n" + call.MethodName +

                              " nt <<<IN>>> parameters: (");

                       for (int i = 0; i < call.ArgCount; i++) {

                              if (i > 0) _property.LogMessage(", ");

                              _property.LogMessage(call.GetArgName(i) +

                              "= " + call.GetArg(i));

                        }

                       _property.LogMes sage(")n");

         }

}

_replyMsg = _nextSink.SyncProcessMessage(reqMsg);

if (_replyMsg is IMethodReturnMessage) {

       IMethodReturnMessage retMsg =

              (IMethodReturnMessage) _replyMsg;

        Exception e = retMsg.Exception;

        if (e!= null) {

              Console.WriteLine(e.Mes sage);

               return _replyMsg;

        }

        lock(_property) {

               _property.LogMessage("===" + retMsg.TypeName);

               _property.LogMessage("n" + retMsg.MethodName +

                    " nt <<<OUT»> parameters: (");

              for (int i = 0; i < retMsg.OutArgCount; i++) {

                   if (i > 0) _property.LogMessage(", ");

                  _property.LogMessage(retMsg.GetOutArgName(i) +

                   " = " + retMsg.GetOutArg(i));

               }

               _property.LogMes sage(")n");

        }

}

       return _replyMsg;

   public virtual IMessageCtrl AsyncProcessMessage(IMessage msg,

        IMessageSink replySink) {

       throw new InvalidOperationExcept();

    }

    public IMessageSink NextSink {

           get {

          return _nextSink;

     }

  }

}

}

Комментарии к коду:

1. Данный код содержит определения двух классов:

♦ MyCallTraceAttribute

Этот публичный класс доступен всем приложениям, имеющим доступ к сборке MyServer.ехе

♦ MyCallTraceServerContextSink

Этот класс является внутренним (internal) для сборки MyServer.ехе и не доступен за ее пределами.

2. Классу MyCallTraceAttribute приписан атрибут [AttributeUsage (AttributeTargets. Class)]. Данный атрибут используется при определении пользовательских атрибутов для задания элементов, которым может быть приписан данный атрибут. В данном случае атрибут MyCallTraceAttribute можно приписать только классу (но нельзя приписать, например, какому-то методу).

3. Комментарии к коду класса MyCallTraceAttribute:

♦ Класс MyCallTraceAttribute является производным классом от класса ContextAttribute и реализует интерфейс IContributeServerContextSink. В свою очередь класс ContextAttribute реализует интерфейсы IContextProperty и IContextAttribute.

Реализация интерфейсов IContextProperty и IContextAttribute обеспечивает выбор контекста для размещения активируемого объекта (в старом или в новом контексте), а в случае формирования нового контекста — назначение ему свойств, которые объект может вызывать в своем коде явно.

Реализация интерфейса IContributeServerContextSink позволяет включить в конец цепочки перехватчиков, которые перехватывают все входящие в контекст вызовы, новый перехватчик. Это позволяет декларативно связать некоторый класс с некоторым автоматическим сервисом, что и является реализацией идей аспектно-ориентированного программирования.

♦ Константа PROPERTY_NAME будет использована для задания имени свойству контекста. Каждое свойство контекста имеет имя и для любого заданного контекста

1 ... 234 235 236 237 238 239 240 241 242 ... 361
Перейти на страницу:

Комментарии
Минимальная длина комментария - 25 символов.
Комментариев еще нет. Будьте первым.