Question

I'm trying to get my head around .NET remoting in an attempt to replicate in .NET a VB6 ActiveX EXE.

So far I have a singleton instantiated on a server that all clients can share.

The singleton accepts requests from clients and validates the data, returning the validated data in the form of an event. This works nicely - classes which request a reference to the Singleton have their events fired - i.e. they send data, receive the validated data.

However, I need an interface to this. The clients are hosted in a WPF application (the server is too) and when they receive data, I need to update the display (textbox, listbox, whatever) to reflect the communication between the clients and the sinlgleton.

However, as soon as I add an event implemented in the mainform for the client to call once it has received a reply from the Singleton I encounter runtime errors complaining that the mainform hasn't the serialization attributes....

To keep this succinct I'll describe the process as follows

Server runs with the code:

            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            //
            IDictionary myDictionary = new Hashtable();
            myDictionary["name"] = String.Format("PracticonChannel_{0}", Port);
            myDictionary["typeFilterLevel"] = TypeFilterLevel.Full;
            myDictionary["port"] = Port.ToString();
            serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

            http = new HttpChannel(myDictionary, clientProvider, serverProvider);

            // Register RemotingShared.SingletonObject as a 
            // Singleton Server-Activated type.
            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(Practicon.RemotingShared.UploadObjectSingleton), // Server-activated type
                "SingletonService",                     // objectUri
                WellKnownObjectMode.Singleton           // Singleton instancing mode
                );

            RemotingConfiguration.ApplicationName = " Upload Server";
            RemotingConfiguration.RegisterActivatedServiceType(
            typeof(Practicon.RemotingShared.UploadObjectSingleton));

The clients obtain the server activated singleton by:

HttpChannel http1;
                // Set the formatters of the messages for delivery.
                BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
                BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
                //
                IDictionary myDictionary = new Hashtable();
                myDictionary["name"] = String.Format("PracticonChannel_{0}", Port);
                myDictionary["typeFilterLevel"] = TypeFilterLevel.Full;
                myDictionary["port"] = port.ToString();
                serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
                http1 = new HttpChannel(myDictionary, clientProvider, serverProvider);

                ChannelServices.RegisterChannel(http1, false);


                uploadObj= (UploadObjectSingleton)Activator.GetObject(
                            typeof(UploadObjectSingleton),
                            fullAddress);

//---------- Here's the problem...
                uploadObj.ReplyEvent += new UploadObjectReplyEventHandler(OnUploadReply);

The OnUploadReply is a Form implemented event that updates various controls. When this is assigned at runtime, the Serialization exceptions occur as a result of the mainform lacking the serialization attribute.

This is driving me nuts. Can someone please show/explain/tell/preach/lecture me as to how I update the User Interface in response to events fired off within a singleton?

Was it helpful?

Solution

OK, Well the answer to this IS to use WCF. It isn't as scary as it sounds and my solution works better than I could have expected.

The things that I would stress to someone trying to do what I was faced with is are:

  1. Obviously, create a server application to host AND ONLY HOST the service. I tried doing fancy things such as using the server app to maintain a UI for the service - status, what it was doing and to/for whom. DONT!. Just dont.

  2. Keep the connection open between client and server open for ONLY as long as needed. Any longer and the channel risks faulting and after many hours trying to sort this out, trying to recover from a fail, you're better off trying to write instructions on how to herd cats. Rethink your problem. Open, use, close.

  3. Anyway, I had to come up with a replacement to an ActiveX control that had a UI. I created 3 projects - the Server (for hosting), a client (for providing a user interface for the service) and a COM interface that interacted with the service (called functions, set properties etc) and an external application.

The first thing the COM interface had to do was to try to find a running instance of the Server (btw, implementing a single instance of a WPF application is by no means an easy feat, but this is off topic)

If one could not be found, it executed the Server app, waited and then opened a channel. This process was repeated every time the COM interface had to talk/wait for the interface (obviously, the Server app only had to be ran once). A ball-ache, but this avoided the dreaded 'channel is in a faulted state' syndrome. Previously, I would find the service could be hosted and a channel kept open for a COMPLETELY random amount of time - 1 minute, an hour, a day but the fault would happen even if the client/server were doing nothing. Since my service is controlling a production line in North America (from the UK) and if the interface goes down NOTHING gets made until it is running again, my priority was stability. So, far the words 'rock' and 'hard' deliriously spring to mind

So, to repeat, open, use, close.

Hope this helps.

MM

BTW I upvoted Blam's suggestion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top