Выбрать главу

После этих вводных замечаний о механизме работы атрибута и контекста перейдем к коду атрибута 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 +

                              " \n\t <<<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 +

                    " \n\t <<<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 обеспечивает выбор контекста для размещения активируемого объекта (в старом или в новом контексте), а в случае формирования нового контекста — назначение ему свойств, которые объект может вызывать в своем коде явно.