posted on Tuesday, January 13, 2004 8:06 PM by taylorza

Remoting Exceptions

Note: The content of this article is relevant to 1.0/1.1 framework. As pointed out by AdamR the 2.0 Framework now supports setting the RemotingConfiguration.CustomErrorsMode.

 

Remoting is one of the more intriguing technologies to come out of the .NET framework, yet in many ways it shows its lack of maturity. Over the last week I have been assisting a development team with a problem they were facing throwing exceptions across remoting boundaries

 

After creating an exception class as outlined in  Boilerplate Code - Exception Classes, the exception was successfully serialized between remoting client and server as long as they both resided on the same machine. When the client was executed from another machine the exception received was a in the form of a System.Runtime.Remoting.RemotingException, the message in the exceptions was as follows “Server encountered an internal error. For more information, turn on customErrors in the server’s .config file.” Using this information I looked up the customErrors element in the online help and put together the following .config file.

 

xml version="1.0" encoding="utf-8" ?>

<configuration>

  <system.runtime.remoting>   

    <customErrors mode="off"/>

  system.runtime.remoting>

configuration>

 

I was just lucky, reading the exception again, “Server encountered an internal error. For more information, turn on customErrors in the server’s .config file”,  I might have actually chosen to set the mode=”on”, fortunately it was the reference to customErrors that caught my attention and the documentation guided my decision. The test application I had put together performed in-code registration of the channel and service type, which I found I could leave like it was and just use the minimal .config file above to adjust the customErrors. The resulting code in my test application resembled the following.

 

  // Configure customErrors

  RemotingConfiguration.Configure("TestServer.exe.config");

 

  // Register channel

  HttpChannel channel = new HttpChannel(1234);

  ChannelServices.RegisterChannel( channel );     

 

  // Register service

  RemotingConfiguration.RegisterWellKnownServiceType(

    typeof(ServerObject),

    "ServerObject.soap",

    WellKnownObjectMode.Singleton );

 

After this I was successfully receiving the custom exceptions that were raised on the server. Now I started to wander if there was a way I could change the customErrors mode programmatically, after spending some time between the documentation and Google I came up empty handed. Then I started greping through SSCLI source code, again I came up empty handed, feeling really confused I decided I fired up my favorite decompiler and started looking for what was going on. Having a feel for the source code from my SSCLI search, I quickly found that the internal class RemotingConfigHandler contained a private static member called _errorMode. Then I started search for public properties or methods that might enable me to change this attribute, but other than the readonly CustomErrorsEnabled member of RemotingConfiguration, there was nothing I could find to set the attribute other than using a .config file.

 

Normally I would leave well enough alone and assume that since there is away to set the value using a .config file there is no need to bother any further, but being the thrill seeker I am I thought I would put my understanding of the code I have spent the last 45min reading to the test and see if I can come up with a routine to set the _errorMode property programmatically using reflection. That in it self is a simple enough task, it helps to validate that I had understood or at least made correct assumptions. The following routine is what I came up with

 

System.Reflection.Assembly remoting =
  System.Reflection.Assembly.GetAssembly(
    typeof(System.Runtime.Remoting.RemotingConfiguration) );

 

Type remotingConfigHandler = remoting.GetType
  ("System.Runtime.Remoting.RemotingConfigHandler");

Type customErrorsModes = remoting.GetType
  ("System.Runtime.Remoting.CustomErrorsModes");

 

FieldInfo errorMode = remotingConfigHandler.GetField("_errorMode",

  BindingFlags.Static | BindingFlags.NonPublic);

 

FieldInfo mode = customErrorsModes.GetField( "Off" );

errorMode.SetValue( null, mode.GetValue( null ) );

 

Nothing to complicated here, I get the assembly that hosts the type System.Runtime.Remoting.RemoteConfiguration then reflect on the assembly to get the internal static RemotingConfigHandler class and the enum CustomErrorsModes. CustomErrorsModes is the datatype type used for _errorMode. Then the next step is to get the _errorMode field info which is a non-public static member of RemotingConfigHandler, from the CustomErrorsModes I get the Off member of the enum. Using all the information I set the errorMode value to the value of the Off member of the enum. Using this routine I ran the server and was pleasantly surprised when the clients continued to receive the unfiltered exceptions, of coarse I made sure that I had removed the references to the .config file I was using previously.

 

Conclusion

Please do not interpret my presentation of the reflection code as anything more than a fun exercise. I seriously doubt that I would ever use this in a production system and would definitely not recommend it. The only time I have ever used a backdoor trick like this in a production system was to provide proxy authentication for .NET remoting objects hosted in IIS, but this is only because I could not find any alternative other than to write a custom sink and I did not have the luxury of time for the development and QA that would be required for a production solution of this nature.

As a final note the customErrors mode can also be configured at a machine level in the machine.config file.

Comments