Интернет-журнал "Домашняя лаборатория", 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) +