Getting an invalid object from a call to LyncClient.GetClient()

2

NOTE: Updated with a solution at the bottom of the question

I'm having some trouble with an application that uses the Lync 2013 SDK. Here is the behavior that I am seeing:

  • If Lync is already running when I start my application, then a call to LyncClient.GetClient() will return a valid client object.
  • If Lync is not running when I start my application, then a call to LyncClient.GetClient() will throw ClientNotFoundException. I can handle the exception and start a timer to ping for the client to appear. Later, when I start Lync, LyncClient.GetClient() will return a valid client object.
  • If Lync exits while my application is running, then I can detect this situation in multiple ways and start a timer to ping for the client to come back.

So far so good, but here's where the problems come in:

  • If Lync goes away while my application is running, then subsequent calls to LyncClient.GetClient() seem to return a valid client object (even though Lync is not running), but attempts to call into this object throw InvalidCastException.
  • Even after Lync is restarted, subsequent calls to LyncClient.GetClient() still return an object that throws InvalidCastException when I try to access it.

The details of the exception are:

Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Uc.IClient'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{EE9F3E74-AC61-469E-80D6-E22BF4EEFF5C}' failed due to the following error: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA).

I tried the recommendation here: Troubleshooting Lync 2013 SDK development issues. It doesn't seem to make any difference. I continue to get an invalid client object for many minutes after Lync is running and signed-in again.

This doesn't happen every time. The problem seems to pretty consistently occur if Lync is already running when my application starts (i.e. the very first call to LyncClient.GetClient() succeeds.) On the other hand, everything seems to work fine across multiple restarts of Lync if I start Lync after my application is already running (i.e. the first attempt to GetClient() fails.)

Has anyone else seen this before? Any suggestions?


Update with an attempt at unloading the AppDomain

I tried to get the client object with this code, but the behavior is exactly the same:

public class LyncClientProvider
{
    private AppDomain _domain = CreateDomain();

    public LyncClient GetLyncClient()
    {
        if (_domain == null) CreateDomain();
        var client = GetClient();
        if (client != null && client.Capabilities != LyncClientCapabilityTypes.Invalid) return client;

        // Reload AppDomain
        if (_domain != null) AppDomain.Unload(_domain);
        _domain = CreateDomain();
        return GetClient();
    }

    private LyncClient GetClient()
    {
        if (_domain == null) return null;
        return ((InternalProvider)
            _domain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName,
                typeof (InternalProvider).FullName)).GetLyncClient();
    }

    private static AppDomain CreateDomain()
    {
        return AppDomain.CreateDomain("LyncClientCreator", null, new AppDomainSetup
        {
            ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
            ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
        });
    }

    [Serializable]
    private class InternalProvider
    {
        public LyncClient GetLyncClient()
        {
            try
            {
                return LyncClient.GetClient();
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

Example of a solution using a dedicated thread

Thanks to input from djp, I implemented this simple class to provide a LyncClient, and reconnects are now working properly.

public class LyncClientProvider
{
    private Thread _thread;
    private volatile bool _running;
    private volatile bool _clientRequested;
    private volatile LyncClient _lyncClient;

    private void MakeClientLoop()
    {
        while (_running)
        {
            if (_clientRequested) MakeClient();
            Thread.Sleep(100);
        }
    }

    private void MakeClient()
    {
        try
        {
            _lyncClient = LyncClient.GetClient();
        }
        catch (Exception)
        {
            _lyncClient = null;
        }
        _clientRequested = false;
    }

    public void Start()
    {
        if (_running) return;
        _running = true;
        _thread = new Thread(MakeClientLoop);
        _thread.Start();
    }

    public void Stop()
    {
        if (!_running) return;
        _running = false;
        _thread.Join();
        _clientRequested = false;
    }

    public LyncClient GetLyncClient()
    {
        if (!_running) return null;
        _clientRequested = true;
        while (_clientRequested) Thread.Sleep(100);
        return _lyncClient;
    }
}
c#
lync-2013
lync-client-sdk
asked on Stack Overflow Jun 5, 2015 by danBhentschel • edited Jul 10, 2015 by danBhentschel

3 Answers

1

I had the same issue, the fix for me is to make sure that every call to LyncClient.GetClient() happens on the same thread

answered on Stack Overflow Jul 10, 2015 by djp
0

"•If Lync goes away while my application is running, then subsequent calls to LyncClient.GetClient() seem to return a valid client object (even though Lync is not running), but attempts to call into this object throw InvalidCastException."

Can you elaborate what you mean by "If Lync goes away". Do you mean you have signed out of Lync or you have exited the Lync (i.e. no Lync process running)? If you have just signed out of the Lync LyncClient will not throw exception. You can listen to LyncClient.StateChanged event and check for clientStateChangedEventArgs.NewState event.

private void LyncClient_StateChanged(object sender, ClientStateChangedEventArgs e) {
        switch (e.NewState) {
                case ClientState.Invalid:
                case ClientState.ShuttingDown:                  
                    this.IsLyncStarted = false;
                    this.IsLyncSignedIn = false;
                    break;
                case ClientState.SignedOut:
                case ClientState.SigningIn:
                case ClientState.SigningOut  
                    this.IsLyncStarted = true;
                    this.IsLyncSignedIn = false;
                    break;
                case ClientState.SignedIn:
                    this.IsLyncStarted = true;
                    this.IsLyncSignedIn = true;
                    break;
            }
            if (!this.IsLyncStarted || !this.IsLyncSignedIn) {                    
                // Do relevant operation
                // Show error message to user - Lync is not present
            }
    }

When the user exits the Lync - I start the timer similar to your approach and try to Initialize Lync like below:

private void InitializeLync() {
        try {
            if (this.LyncClient == null || this.LyncClient.State == ClientState.Invalid) {
                this.LyncClient = LyncClient.GetClient();

                if (this.LyncClient != null) {
                    this.LyncClient.StateChanged += this.LyncClient_StateChanged;       
                }
            }

        } catch (Exception ex) {
            // Show message to user that Lync is not started
        }
}

This works for me. May be it is machine specific issue.

answered on Stack Overflow Jun 6, 2015 by Ankit Vijay
-2

I am assuming you are being disconnected from the Lync server. The LyncClient.GetClient() method may still work because you have some lingering variables, but you won't be able to preform any Lync actions with it.

I think looking at the UI suppression stuff would help. https://msdn.microsoft.com/en-us/library/office/hh345230%28v=office.14%29.aspx

answered on Stack Overflow Jun 5, 2015 by jrs

User contributions licensed under CC BY-SA 3.0