0

I have a service which needs to pump strings to a helper application which displays critical messages from the service to the user (Vista+ does not give services access to the GUI). Since I've used .NET Remoting over TCP, I figured I'd do the same with the IPC protocol. However, after getting the reference to the remote object, I get the following exception when making a call to the remote method:

MissingMethodException: No parameterless constructor defined for this object.

Simply adding a parameterless constructor to the class gives me a NullReferenceException when making the call instead. What is it that I am doing wrong? I've included my relevant code below:

Application Code

public class MyMsgBus : MarshalByRefObject, IDisposable, IMxServeBus
{
    private Thread myThread = null;
    private volatile List<string> myMsgBus = null;
    private volatile bool myThreadAlive = false;
    private volatile bool myIsDisposed = false;
    private volatile bool myIsDisposing = false;
    private IpcChannel myIpc = null;

    public MyMsgBus(string busname)
    {
       myMsgBus = new List<string>();

       myIpc = CreateIpcChannel(busname);
       ChannelServices.RegisterChannel(myIpc);

       var entry = new WellKnownServiceTypeEntry(
          typeof(MxServeBus),
          "MyRemoteObj.rem",
          WellKnownObjectMode.Singleton);

       RemotingConfiguration.RegisterWellKnownServiceType(entry);
    }

    // defined in IMyMsgBus
    public void SendMessage(string message)
    {
       // do stuff
    }

    public static IpcChannel CreateIpcChannel(string portName)
    {
       var serverSinkProvider = new BinaryServerFormatterSinkProvider();
       serverSinkProvider.TypeFilterLevel = TypeFilterLevel.Low;

       IDictionary props = new Hashtable();
       props["portName"] = portName;
       props["authorizedGroup"] = "Authenticated Users";

       return new IpcChannel(props, null, serverSinkProvider);
    }

    public static IpcChannel CreateIpcChannelWithUniquePortName()
    {
       return CreateIpcChannel(Guid.NewGuid().ToString());
    }
}

Test Client

static void Main(string[] args)
{
   var channel = MyMsgBus.CreateIpcChannelWithUniquePortName();
   ChannelServices.RegisterChannel(channel, true);

   var objUri = "ipc://MyMsgBus/MyRemoteObj.rem";
   IMyMsgBus lBus = (IMyMsgBus)Activator.GetObject(typeof(IMyMsgBus), objUri);
   lBus.SendMessage("test");
   Console.WriteLine();
}

Thanks in advance for any assistance on this. As an FYI, this is a remoting instance configured through the use of a shared interface, where IMyMsgBus defines the methods which should be available to call over IPC.

codewario
  • 19,553
  • 20
  • 90
  • 159

1 Answers1

0

You are getting NullReferenceException on adding parameterless constructor as parameter is required for proper initialization. By not supplying it, some part of initialization is missed.

You should refactor your code to allow parameter less constructor as

   private bool _initialized = false;

    public MyMsgBus() {}

    public Initialize(string busname) // Make this part of interface    
    {
       myMsgBus = new List<string>();

       myIpc = CreateIpcChannel(busname);
       ChannelServices.RegisterChannel(myIpc);

       var entry = new WellKnownServiceTypeEntry(
          typeof(MxServeBus),
          "MyRemoteObj.rem",
          WellKnownObjectMode.Singleton);

       RemotingConfiguration.RegisterWellKnownServiceType(entry);
       _initialized = true;
    }

In all other public methods, check for _initialized flag and throw NotInitializedException if flag is false.

You should use it as

 IMyMsgBus lBus = (IMyMsgBus)Activator.GetObject(typeof(IMyMsgBus));
 lBus.Initialize(objUri);
 ... do Further operation
Tilak
  • 30,108
  • 19
  • 83
  • 131
  • How would I call initialize from a remote process if initialize sets up remoting? – codewario Jan 10 '13 at 15:26
  • Try this. If it does not work, you need some other way to pass parameter. – Tilak Jan 10 '13 at 15:28
  • I didn't implement this exactly as you outlined above, but I implemented the parameterless constructor like so: public MyMsgBus() : this("MyMsgBus") { }. Which works, thanks man! – codewario Jan 10 '13 at 15:31
  • thats another way, but it still makes message bus name fixed. That is the trade-off. – Tilak Jan 10 '13 at 15:34