blogs.conchango.com

welcome to the conchango blogging site
Welcome to blogs.conchango.com Sign in | Join | Help
in Search

Matt Hall's Blog

Experiences with Microsoft technologies in particular BizTalk 2004, BizTalk 2006, .NET and SQL Server.

Singleton Remoting Events

I haven’t spent a great deal of time working with Remoting, but a need arose recently whereby I wanted to host an object within IIS and have this raise events to interested parties when a particular action occurred. This was to be a SAO (Server Activated Object) that implemented a Singleton pattern.

 

So off I went on a little voyage of discovery through the various samples available both within MSDN and the Internet and quickly came up with a simple prototype that would mimic the functionality that would be required for the full solution. After numerous iterations of pain I decided that some of these findings would be worthwhile posting on my blog at least as a point of reference for me and possibly as an aid to anyone that comes across similar issues.

 

Problem 1 - Remoted Delegates

 

The first problem is the use of remoted delegates and events that result in callbacks to the clients. The most obvious place to source an example is from the example documentation within MSDN, but unfortunately the Chat sample that is provided works as written only if the client, remotable object, and remoting host assemblies reside in the same directory. Obviously kind of defeating the object of why you are using remoting in the first place.

 

Anyway, fortunately there is quite an in-depth knowledgebase article for this issue and you may find that here. In essence you must remember that the client must also have access to the interface definition of any objects that are used, so therefore you can write an abstract class from which the client’s concrete class can be implemented.

 

Problem 2 - DelegateSerialization Permission

 

.NET Framework 1.1 introduced some security measures that would prevent passing of delegates and object references over Remoting boundaries by default. The typical error message you will receive for this issue is Type System.DelegateSerializationHolder and the types derived from it (such as System.DelegateSerializationHolder) are not permitted to be desterilized at this security level.

 

To overcome this issue you must implement the typeFilterLevel explicitly setting the value to be Full such as that shown below.

 

Web.config

<configuration>

      <system.runtime.remoting>

         <application>

            <service>

               <wellknown mode="Singleton" objectUri="YourURI.rem" type="YourObjectType, YourAssembly"/>

            </service>

            <channels>

               <channel ref="http">

                  <serverProviders>

                     <provider ref="wsdl" />

                     <formatter ref="soap" typeFilterLevel="Full" />

                     <formatter ref="binary" typeFilterLevel="Full" />

                  </serverProviders>

               </channel>

            </channels>

         </application>

      </system.runtime.remoting>

</configuration>

 

In this case a matching client-side configuration file would look like the following:

 

App.config

<configuration>

      <system.runtime.remoting>

         <application>

            <client>

               <wellknown url="http://YourMachine:80/YourVirtualDir/YourURI.rem" type="YourObjectType, YourAssembly"/>

            </client>

            <channels>

               <channel ref="http" useDefaultCredentials="true" port="0">

                  <clientProviders>

                     <formatter ref="soap"/>

                  </clientProviders>

                  <serverProviders>                           

                     <formatter ref="soap" typeFilterLevel="Full" />

                  </serverProviders>

               </channel>

            </channels>

         </application>

      </system.runtime.remoting>

</configuration>

 

You can also achieve this programmatically by utilising the TypeFilterLevel on the sink provider.

 

Problem 3 – Local Version of Object used rather than Remote

 

The majority of issues you will come across when using the configuration files rather than programmatically setting up remoting configuration will be due to the formatting or minor typos in the configuration file(s). This can be quite aggravating as it can sometimes appear everything is working as expected, but due to an error in the configuration file a local copy of the object is being used rather than the remote version.

 

A little tip to determine that this is not the case is to include the following line after you have instantiated your “remote” object. If the assertion fails you have created a local instance.

 

System.Diagnostics.Debug.Assert(RemotingServices.IsTransparentProxy(YourObject));

 

Problem 4 – Config FileNotFound Exception

 

You may receive the following error An unhandled exception of type 'System.Runtime.Remoting.RemotingException' Occurred in mscorlib.dll Additional information: .Config file YourAssembly.exe.config can not be read successfully due to exception System.IO.FileNotFoundException: The system cannot find the file specified

 

This is due to the config file not being located in the same folder as the running process for whatever reason and you may address this using the code below, obviously making sure that the config file exists in the expected location.

 

string configFilePath = System.IO.Path.Combine(System.Environment.CurrentDirectory, "YourAssembly.exe.config");

RemotingConfiguration.Configure(configFilePath);

 

Problem 5 – The Underlying Connection was Closed

 

This was a killer for me and took quite a while to discover why the error was being generated. Generally this can happen if you have not set-up your configuration properly. However, in this instance everything was working correctly for the first client, but once that client had been closed any subsequent clients would raise this event.

 

The reason for the error in my case was due to not unwiring the event when the client exited or had finished listening for the event. This would be achieved using code similar to that below.

 

MyRemoteObject.MyRemoteEvent -= new MyRemoteEventHandler(MyLocalCallbackClass.MyCallbackMethod);

 

Conclusion

 

I have found my initial journey into the use of a slightly more complex remoting solution that I have used in the past quite frustrating. But I guess this is no more so than when you embark on various aspects of development. If you have had no experience of what you’re exactly trying to achieve in the first place you are always going to come across various issues, so you hope there is enough valuable information available to debug those issues in an efficient manner.

 

However, I have found it quite easy to introduce bugs into the configuration XML, so perhaps utilising some form of schema to validate your configuration may be a useful exercise. Once you have things up and running though, I find you do get a sense of satisfaction and realise that this really is easier to work with than DCOM or the like. Perhaps if my journey takes me deeper into more complex scenarios I may find this to not be the case, but at the moment I am satisfied with the result, regardless of the few days pain suffered along the way.

Published 25 May 2005 13:23 by Matthew.Hall
Filed under:

Comments

 

Sélim Bichara said:

Actually for Problem 1, Microsoft has updated its documentation => see http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q312114
July 8, 2005 12:20
New Comments to this post are disabled
Powered by Community Server (Personal Edition), by Telligent Systems