Re: отлов исключений для всех методов Remoting объекта
От: Tom Россия http://www.RSDN.ru
Дата: 26.11.04 17:26
Оценка: 74 (5)
"Ael" <27323@users.rsdn.ru> wrote in message news:919398@news.rsdn.ru...
> Веб приложение обращается через Remoting к Windows Servic-у. Столкнулись с тем, что когда исключение происходик в процессе виндоус-сервиса, то к веб-приложению оно естественно возвращается как Remoting exception, но плохо то что иногда server stack приходит, а иногда (в среде, где веб приложение стоит на кластере нет).
> Решили делать централизованный отлов исключений на стороне виндоус сервиса. Но методов уже несколько сотен, не будешь же каждому писать try... catch. Поэтому такой вопрос — как переопределить вызов метода через ремотинг, чтобы встроить в него отлов исключений для всех методов зарегистрированного remoting объекта?
> Спасибо!

Надо написать remoting sink и отлавливать исключения там. Что то типа этого:

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Reflection;

using System.Diagnostics;

using ACSServer.Service;
using ACSServer.Managers;

namespace ACSServer.Helpers
{
 #region CBO Filtering

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
 public class ExceptionsFilterContextAttribute : ContextAttribute
 {
  private Type[] _AllowedExceptions;
  private Type _NewException;

  public ExceptionsFilterContextAttribute(Type[] AllowedExceptions, Type NewException) :
   base("ExceptionsFilterContextAttribute")
  {
   _AllowedExceptions = AllowedExceptions;
   _NewException = NewException;
  }

  public Type NewException
  {
   get{return _NewException;}
  }

  public Type[] AllowedExceptions
  {
   get{return _AllowedExceptions;}
  }

  public override void GetPropertiesForNewContext(System.Runtime.Remoting.Activation.IConstructionCallMessage ctorMsg)
  {
   ctorMsg.ContextProperties.Add(new ExceptionsFilterContextProperty(this.AttributeName));
  }

  public override bool IsContextOK(Context ctx, System.Runtime.Remoting.Activation.IConstructionCallMessage ctorMsg)
  {
   return (ctx.GetProperty(this.AttributeName) != null);
  }


  public class ExceptionsFilterContextProperty : IContextProperty,
   IContributeServerContextSink
  {
   private string   _Name;
   private IMessageSink _ExceptionsFilterSink;

   public ExceptionsFilterContextProperty(string Name)
   {
    _Name = Name;
   }

   public string Name
   {
    get
    {
     return _Name;;
    }
   }

   public bool IsNewContextOK(Context newCtx)
   {
    return true;
   }

   public void Freeze(Context newContext)
   {
   }

   public IMessageSink GetServerContextSink(IMessageSink nextSink)
   {
    lock(this)
    {
     if (_ExceptionsFilterSink == null)
      _ExceptionsFilterSink = new ExceptionsFilterContextSink(nextSink);
    }

    return _ExceptionsFilterSink;
   }
  }
 }

 public class ExceptionsFilterContextSink : IMessageSink
 {
  private IMessageSink _NextSink;

  public ExceptionsFilterContextSink(IMessageSink NextSink)
  {
   _NextSink = NextSink;
  }

  public IMessageSink NextSink
  {
   get{return _NextSink;}
  }

  public IMessage SyncProcessMessage(IMessage msg)
  {
   IMethodReturnMessage retMsg = _NextSink.SyncProcessMessage(msg) as IMethodReturnMessage;

   if (msg is IMethodCallMessage)
    InspectReturnMessageAndReplaceException(msg as IMethodCallMessage, ref retMsg);

   return retMsg;
  }

  public IMessageCtrl AsyncProcessMessage(IMessage msg,
   IMessageSink replySink)
  {
   return null;
  }

  private void InspectReturnMessageAndReplaceException(IMethodCallMessage reqMsg, ref IMethodReturnMessage retMsg)
  {
   if ((retMsg != null) && (retMsg.Exception != null))
   {
    // Check method/property/class for ExceptionsFilterAttribute
    ExceptionsFilterContextAttribute filterAtr = null;
    
    // Check method attribute
    filterAtr = (ExceptionsFilterContextAttribute) Attribute.GetCustomAttribute(reqMsg.MethodBase, typeof(ExceptionsFilterContextAttribute));
    
    // Check class attribute
    if (filterAtr == null)
     filterAtr = (ExceptionsFilterContextAttribute) Attribute.GetCustomAttribute(reqMsg.MethodBase.DeclaringType, typeof(ExceptionsFilterContextAttribute));

    if (filterAtr != null)
    {
     foreach(Type allowedException in filterAtr.AllowedExceptions)
     {
      // If this is allowed exception then simply pass it
      if (allowedException.Equals(retMsg.Exception.GetType()))
       return;
     }

     Listener.Instance.EventLog.WriteEntry(retMsg.Exception.ToString(), EventLogEntryType.Error);

     retMsg = new ReturnMessage((Exception) Activator.CreateInstance(filterAtr.NewException, new object[]{retMsg.Exception}), reqMsg);
    }
   }
  }
 }

 #endregion

 #region Remoting Filtering
 
 [Serializable]
 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
 public class ExceptionsFilterAttribute : Attribute
 {
  private Type[] _AllowedExceptions;
  private Type _NewException;

  public ExceptionsFilterAttribute(Type[] AllowedExceptions, Type NewException)
  {
   _AllowedExceptions = AllowedExceptions;
   _NewException = NewException;
  }

  public Type NewException
  {
   get{return _NewException;}
  }

  public Type[] AllowedExceptions
  {
   get{return _AllowedExceptions;}
  }
 }

 /// <summary>
 /// Summary description for ExceptionsControllerServerChannelSink.
 /// </summary>
 public class ExceptionsFilterServerChannelSink : IServerChannelSink
 {
  private IServerChannelSink _NextSink;

  public ExceptionsFilterServerChannelSink(IServerChannelSink NextSink)
  {
   Listener.Instance.EventLog.WriteEntry("ExceptionsFilterServerChannelSink created");
   _NextSink = NextSink;
  }

  public ServerProcessing ProcessMessage(
   IServerChannelSinkStack sinkStack,
   IMessage requestMsg,
   ITransportHeaders requestHeaders,
   Stream requestStream,
   out IMessage responseMsg,
   out ITransportHeaders responseHeaders,
   out Stream responseStream
   )
  {
   ServerProcessing sp = 
    _NextSink.ProcessMessage(
    sinkStack,
    requestMsg,
    requestHeaders,
    requestStream,
    out responseMsg,
    out responseHeaders,
    out responseStream);
   
   IMethodCallMessage inMessage = requestMsg as IMethodCallMessage;
   IMethodReturnMessage outMsg = responseMsg as IMethodReturnMessage;

   InspectReturnMessageAndReplaceException(inMessage, ref outMsg);
   responseMsg = outMsg;
   return sp;
  }
  
  public Stream GetResponseStream(
   IServerResponseChannelSinkStack sinkStack,
   object state,
   IMessage msg,
   ITransportHeaders headers
   )
  {
   return null;
  }

  public void AsyncProcessResponse(
   IServerResponseChannelSinkStack sinkStack,
   object state,
   IMessage msg,
   ITransportHeaders headers,
   Stream stream
   )
  {
  }

  public IServerChannelSink NextChannelSink
  {
   get{return _NextSink;}
  }

  public IDictionary Properties
  {
   get{return null;}
  }

  private void InspectReturnMessageAndReplaceException(IMethodCallMessage reqMsg, ref IMethodReturnMessage retMsg)
  {
   if ((retMsg != null) && (retMsg.Exception != null))
   {
    ExceptionsFilterAttribute filterAtr = null;
    
    //
    // Get the type which begin processing call
    //
    Type serverType = RemotingServices.GetServerTypeForUri(retMsg.Uri);
   
    //
    // Prepare Type array for every type in the call parameters
    //
    ArrayList argTypesList = new ArrayList();
    foreach(object inArg in reqMsg.Args)
     argTypesList.Add(inArg.GetType());

    Type[] argTypes = (Type[]) argTypesList.ToArray(typeof(Type));
    
    MethodInfo methodInfo = serverType.GetMethod(retMsg.MethodName, argTypes);
    methodInfo = serverType.GetMethod(retMsg.MethodName, new Type[]{typeof(HRInterfaces.DataType.Person)});

    if (methodInfo != null)
     filterAtr = (ExceptionsFilterAttribute) Attribute.GetCustomAttribute(methodInfo, typeof(ExceptionsFilterAttribute));
    else
    {
     //
     // FOR DEBUG ONLY!!!
     // TODO: Fix this
     //
//     Listener.Instance.EventLog.WriteEntry("methodInfo = null", EventLogEntryType.Error);
//     Listener.Instance.EventLog.WriteEntry(retMsg.Exception.ToString(), EventLogEntryType.Error);
    }

    if (filterAtr != null)
    {
     foreach(Type allowedException in filterAtr.AllowedExceptions)
     {
      // If this is allowed exception then simply pass it
      if (allowedException.Equals(retMsg.Exception.GetType()))
       return;
     };

     Listener.Instance.EventLog.WriteEntry(retMsg.Exception.ToString(), EventLogEntryType.Error);

     retMsg = new ReturnMessage((Exception) Activator.CreateInstance(filterAtr.NewException), reqMsg);
    }
   }
  }
 }

 public class ExceptionsFilterServerChannelSinkProvider : IServerChannelSinkProvider
 {
  private IServerChannelSinkProvider _NextProvider;

  public ExceptionsFilterServerChannelSinkProvider(
   IDictionary Properties,
   ICollection ProviderData) :
   this(Properties, ProviderData, null)
  {
  }
  
  public ExceptionsFilterServerChannelSinkProvider(
   IDictionary Properties,
   ICollection ProviderData,
   IServerChannelSinkProvider provider)
  {
   _NextProvider = provider;
  }

  public IServerChannelSink CreateSink(IChannelReceiver Channel)
  {
   IServerChannelSink NextSink = null;
   if (_NextProvider != null)
   {
    NextSink = _NextProvider.CreateSink( Channel );
   }

   return new ExceptionsFilterServerChannelSink(NextSink);
  }
  
  public void GetChannelData(IChannelDataStore channelData)
  {
  }
  
  public IServerChannelSinkProvider Next
  {
   get{return _NextProvider;}
   set{_NextProvider = value;}
  }
 }
 #endregion
}
Posted via RSDN NNTP Server 1.9 delta
Народная мудрось
всем все никому ничего(с).
отлов исключений для всех методов Remoting объекта
От: Ael США  
Дата: 26.11.04 16:57
Оценка:
Веб приложение обращается через Remoting к Windows Servic-у. Столкнулись с тем, что когда исключение происходик в процессе виндоус-сервиса, то к веб-приложению оно естественно возвращается как Remoting exception, но плохо то что иногда server stack приходит, а иногда (в среде, где веб приложение стоит на кластере нет).
Решили делать централизованный отлов исключений на стороне виндоус сервиса. Но методов уже несколько сотен, не будешь же каждому писать try... catch. Поэтому такой вопрос — как переопределить вызов метода через ремотинг, чтобы встроить в него отлов исключений для всех методов зарегистрированного remoting объекта?
Спасибо!
Re[2]: отлов исключений для всех методов Remoting объекта
От: Ael США  
Дата: 29.11.04 06:54
Оценка:
Классно, спасибо. Я на за выходные по сути до этого и дошел (переопределил IServerChannelSinkProvider и IServerChannelSink). В итоге у меня проще получилось, чем в твоем примере, то есть все свелось к тому, чтобы в методе ProcessMessage проверять в случае если ServerProcessing = Complete, (после того, как ProcessMessage выполнится на nextSink) проперти Exception объекта ReturnMessage.
Re[3]: отлов исключений для всех методов Remoting объекта
От: Tom Россия http://www.RSDN.ru
Дата: 29.11.04 09:09
Оценка:
Здравствуйте, Ael, Вы писали:

Ael>Классно, спасибо. Я на за выходные по сути до этого и дошел (переопределил IServerChannelSinkProvider и IServerChannelSink). В итоге у меня проще получилось, чем в твоем примере, то есть все свелось к тому, чтобы в методе ProcessMessage проверять в случае если ServerProcessing = Complete, (после того, как ProcessMessage выполнится на nextSink) проперти Exception объекта ReturnMessage.



Я навернул следующую фичу. Если произошёл exception, то у обьекта ищется ExceptionsFilterAttribute. В этом атрибуте задаётся какие типы исключений разрешено вцыбрасывать, и на какое исключение заменять те исключения, которые выбрасывать нельзя. Это надо например что бы SecurityException был выброшен, но скажем какой нибудь OleDbException не был выброшен, а заменён на то исключение, которое ты укажешь в атрибуте. Типа InternalServerErrorException. В своём роде получился framework работы с исключениями в remoting-е.
Народная мудрось
всем все никому ничего(с).
Re: отлов исключений для всех методов Remoting объекта
От: Аноним  
Дата: 04.03.05 06:57
Оценка:
Здравствуйте, Ael, Вы писали:

Ael>Веб приложение обращается через Remoting к Windows Servic-у. Столкнулись с тем, что когда исключение происходик в процессе виндоус-сервиса, то к веб-приложению оно естественно возвращается как Remoting exception, но плохо то что иногда server stack приходит, а иногда (в среде, где веб приложение стоит на кластере нет).

Ael>Решили делать централизованный отлов исключений на стороне виндоус сервиса. Но методов уже несколько сотен, не будешь же каждому писать try... catch. Поэтому такой вопрос — как переопределить вызов метода через ремотинг, чтобы встроить в него отлов исключений для всех методов зарегистрированного remoting объекта?
Ael>Спасибо!

Не могли бы Вы более подробно оприсать(а лучше показать коды) решение данной задачи. Вот создали мы атрибут и что с ним дальше делать?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.