2
votes

i have a client-server application which uses .NET Remoting communication. For authentication reasons i had to write a custom IClientChannelSink to insert a session cookie into the HTTP-requests. On the server side i also wrote a custom IServerChannelSink to read some information the server needs from the HTTP-request headers.

The client side works fine, but on the server side i always get the following error:

System.ArgumentNullException was unhandled by user code Message=No message was deserialized prior to calling the DispatchChannelSink. Parameter name: requestMsg Source=mscorlib ParamName=requestMsg
StackTrace: at System.Runtime.Remoting.Channels.DispatchChannelSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream) at MyAuthentication.MyServerChannelSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream) in C:\Dev\MyAuthentication\MyServerChannelSink.cs:line 82 at System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream) at System.Runtime.Remoting.Channels.Http.HttpServerTransportSink.ServiceRequest(Object state) at System.Runtime.Remoting.Channels.SocketHandler.ProcessRequestNow()
InnerException:

My "ProcessMessage"-methodlooks as follows:

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
    // Pre-processing before sending the message to the next sink in the chain
    object state = null;
    ProcessRequest(requestMsg, requestHeaders, ref requestStream, ref state);

    /* Call the next sink in the chain */
    sinkStack.Push(this, state);
    ServerProcessing serverProcessing = this.NextChannelSink.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);

    // Processing from sink further in the chain has completed. Now do any post-processing before returning to the previous sink in the chain.
    ProcessResponse(null, responseHeaders, ref responseStream, state);

    return serverProcessing;
}

Would be great if anyone can tell me whats wrong.

3

3 Answers

2
votes

Under certain circumstances the requestMsg parameter could be null. So you have to handle those cases. For example another server channel sink is calling your ProcessMessage function with requestMsg set to null!

EDIT: Provided link to a sample. Here is link to sample of a server sink:Server Sink

0
votes

I've solved my problem. Since i don't use the channel sinks to do any serialization i also don't want to handle the message deserialization by myself. The following implemention works fine:

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
    // Pre-processing before sending the message to the next sink in the chain
    object state = null;
    ProcessRequest(requestMsg, requestHeaders, ref requestStream, ref state);

    ServerProcessing serverProcessing;
    if (requestMsg != null)
    {
        /* Call the next sink in the chain */
        sinkStack.Push(this, state);
        serverProcessing = this.NextChannelSink.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
        sinkStack.Pop(this);
    }
    else
    {
        responseMsg = null;
        responseHeaders = null;
        responseStream = null;
        serverProcessing = ServerProcessing.Complete;
    }

    // Processing from sink further in the chain has completed. Now do any post-processing before returning to the previous sink in the chain.
    ProcessResponse(null, responseHeaders, ref responseStream, state);

    return serverProcessing;
}
0
votes

By creating your server channel

TcpServerChannel oTcpChannel =
    new TcpServerChannel(oTcpChannelConfiguration, oServerSinkProvider, oAuthority);

You can set oServerSinkProvider = null and the system will support a default sink provider. You can als specify your own formatter, for example a soap formatter for a TCP channel or a binary formatter for an http channel: SoapServerFormatterSinkProvider or BinaryServerFormatterSinkProvider.

However if you support your own server sink, you must implement your own formatter too. You can do so in your set section of your function IServerChannelSinkProvider.Next by:

  set
  {
    if ( value != null )
    {
      nextProvider = new BinaryServerFormatterSinkProvider ();
      nextProvider.Next = value;
    }
    else
    {
      nextProvider = value;
    };
  }

Then the next provider does the job of fomatting, binary formatting in this case.