Reuse of Remoting Channels...

From: Rob Jones (rjones_at_bak.rr.com)
Date: 03/24/05


Date: Thu, 24 Mar 2005 14:50:57 -0800

Although my question pertains to remoting within .NET 2.0, I'm posting
my question here because:

1) There's not much activity in MS's private newgroups for .NET 2.0.

2) I think my question is not all that specific to features present
in .NET 2.0 (and missing from .NET 1.1).

So, here goes:

As some of you may know, one of the neat new features in .NET 2.0 is
the added credentials / security available in the TCP channels. This
makes it possible for the server to know the identity of the caller.
This is a feature that I am taking advantage of in my code, and is
related to my problem.

If my client is on the other side of a Windows 'realm' (as in the
client is logged into a Windows domain and the server is not a member
of the same domain) my server code has been instructed (via its
RemotingConfiguration options) to reject any clients whose credentials
the server cannot authenticate. When this happens, my client is
thrown an exception that says "you need to provide credentials that
the target server can authenticate". So, my client then fetches
username and password info from the user (presumably credentials that
the server can authenticate) and the client code then trys to
re-establish a connection with the server. Herein is where my problem
lies. I've discovered that if the client initially provides valid
credentials, all works fine. However, if the first connection attempt
throws the exception mentioned above, any subsequent connection
attempts fail also (even when valid credentials were provided). It's
as if once the client establishes that first connnection with the
remote server, the credential info provided is 'retained' and I can't
seem to clear it out.

Below I've posted the code that gets called each time the client tries
to connect. Note that each time through I check to see if any
channels are already registered and if so, I unregister them.
However, that doesn't seem to be enough.

If anyone has any clues / ideas, I'd be most grateful.

TIA

Rob

=================================================================================
private ILightspeedServices Connect(ref ClientChannelData myChannel,
ref ConnectionError myError, ref string strSystemErrorMessage)
{
        int iLoopCount = 0;
        int iLoopExit = 2;
        string strRemoteURI = "";

        if ( Global.IsServerLocal(myChannel.Server) )
                strRemoteURI = String.Format
                        (
                                @"{0}://{1}/{2}",
                                myChannel.Name,
                                myChannel.Port,
                                myChannel.ObjectUri
                        );
        else
                strRemoteURI = String.Format
                        (
                                @"{0}://{1}:{2}/{3}",
                                myChannel.Name,
                                myChannel.Server,
                                myChannel.Port,
                                myChannel.ObjectUri
                        );

        // If there are any registered channels left over from
previous attempts, unregister them now.
        foreach (IChannel thisChannel in
ChannelServices.RegisteredChannels)
        {
                
                ChannelServices.UnregisterChannel(thisChannel);
        }

        // Select the correct channel...
        switch (myChannel.Name)
        {
                case ChannelDefaults.TcpChannelName:
                        TcpClientChannel myTcpChannel = new
TcpClientChannel(myChannel.ChannelParameters, null);
                        ChannelServices.RegisterChannel(myTcpChannel);
                        break;

                case ChannelDefaults.IpcChannelName:
                        IpcClientChannel myIpcChannel = new
IpcClientChannel(myChannel.ChannelParameters, null);
                        ChannelServices.RegisterChannel(myIpcChannel);
                        break;

        }

        // If this is the first pass, we must initialze everything.
Otherwise, just change those parameters of
        // each WellKnownClientTypeEntry that was registered during
the first pass...
        WellKnownClientTypeEntry[] entryArray =
RemotingConfiguration.GetRegisteredWellKnownClientTypes();
        if (entryArray == null || entryArray.Length == 0)
        {
                WellKnownClientTypeEntry myEntry = new
WellKnownClientTypeEntry(typeof(ILightspeedServices), strRemoteURI);

RemotingConfiguration.RegisterWellKnownClientType(myEntry);
        }

        remoteLightspeedServices =
(ILightspeedServices)Activator.GetObject(typeof(ILightspeedServices),
strRemoteURI);

        do
        {
                strSystemErrorMessage = "";
                try
                {
                        if (remoteLightspeedServices.TtcServiceControl
!= null)
                                return (remoteLightspeedServices);
                }
                catch (System.Net.Sockets.SocketException socketEx)
                {
                        switch (socketEx.ErrorCode)
                        {
                                // No credentials provided...
                                case 10054:
                                        myError =
ConnectionError.MissingCredentials;
                                        strSystemErrorMessage =
socketEx.Message;
                                        break;

                                // Remoting server cannot be
reached...
                                case 10060:
                                        myError =
ConnectionError.UnresponsiveServer;
                                        strSystemErrorMessage =
"Remoting server cannot be reached. " + socketEx.Message;
                                        break;

                                // Remoting server appears to be
alive, but we can't seem to find LightspeedServices service
                                case 10061:
                                        myError =
ConnectionError.NoServer;
                                        strSystemErrorMessage =
socketEx.Message;
                                        break;

                                // Remoting server's name cannot be
resolved...
                                case 11001:
                                        myError =
ConnectionError.UnknownServer;
                                        strSystemErrorMessage =
"Remoting server's name does not exist. " + socketEx.Message;
                                        break;

                                default:
                                        myError =
ConnectionError.Unknown;
                                        strSystemErrorMessage =
socketEx.Message;
                                        break;

                        }
                }
                catch
(System.Security.Authentication.InvalidCredentialException
credentialsEx)
                {
                        // Bad credentials provided...
                        myError = ConnectionError.BadCredentials;
                        strSystemErrorMessage = credentialsEx.Message;

                }
                catch (System.Runtime.Remoting.RemotingException
remotingEx)
                {
                        // We handle this error as if the remoting
server is not running...
                        myError = ConnectionError.NoServer;
                        strSystemErrorMessage = remotingEx.Message;
                }
                catch (Exception generalEx)
                {
                        myError = ConnectionError.Unknown;
                        strSystemErrorMessage = generalEx.Message;
                }

                // If we're here, something went wrong. Can we do
anything about it???
                switch (myError)
                {
                        // Maybe we can start the remote server???
                        case ConnectionError.NoServer:
                                RestartLightspeedServicesService();
                                break;

                        // All other errors, just go back with an
exception...
                        default:
                                iLoopCount = iLoopExit;
                                break;
                }
        }
        while (++iLoopCount < iLoopExit);

        // nothing has worked, so go back empty handed...
        return null;

}
=========================================================================



Relevant Pages

  • Re: Events in .Net Remoting
    ... I am writing with respect to the Events in .Net Remoting that I had ... another channel for the callbacks..both on client side. ... Then I force a method on the server end (through a GUI control on the ... >> the regular client side requests still work fine. ...
    (microsoft.public.dotnet.framework.remoting)
  • Re: passing structs (setializable) object in web service
    ... The philosophy of webservices is different than that of remoting. ... follow Seely's advice as Christoph pointed out earlier - you have to modify ... > having total control over both client and server types. ...
    (microsoft.public.dotnet.framework.aspnet.webservices)
  • Re: Delegate Failure after Migration to .NET 2.0 - Vista
    ... remoting to work in .NET 2.0 for you? ... ActivatedClientTypeEntry entry = new ... I make the single below call in order to register my server type. ... the client. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: SSPI Kerberos for delegation
    ... We want the authentication to happen without providing credentials ... But SSPI while authenticating from the client to the server can do mutual ...
    (comp.protocols.kerberos)
  • Re: soapsuds
    ... pre-instantiated exe running in a singleton mode, for remoting, even if you ... Revised framework implementations will probably not break your application ... We can then compile the client using this code which allows us ... Both client and server are ...
    (microsoft.public.dotnet.framework.remoting)