Чтение онлайн

ЖАНРЫ

Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:

Как уже упоминалось ранее, в случае пересечения вызовом границы контекста (кроме контекста по умолчанию), прокси на вызывающей стороне преобразует вызов в сообщение (объект, реализующий интерфейс 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 +

" \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) +

Поделиться с друзьями: