注意:更新了问题底部的解决方案
我在使用 Lync 2013 SDK 的应用程序时遇到了一些问题。这是我看到的行为:
- 如果在我启动应用程序时 Lync 已经在运行,那么调用
LyncClient.GetClient()
将返回一个有效的客户端对象。 - 如果在我启动应用程序时 Lync 未运行,则调用
LyncClient.GetClient()
将抛出ClientNotFoundException
. 我可以处理异常并启动一个计时器来 ping 客户端出现。后来,当我启动 Lync 时,LyncClient.GetClient()
会返回一个有效的客户端对象。 - 如果在我的应用程序运行时 Lync 退出,那么我可以通过多种方式检测这种情况并启动计时器以 ping 客户端返回。
到目前为止一切顺利,但问题出在:
- 如果在我的应用程序运行时 Lync 消失了,那么后续调用
LyncClient.GetClient()
似乎会返回一个有效的客户端对象(即使 Lync 没有运行),但会尝试调用这个对象 throwInvalidCastException
。 - 即使在重新启动 Lync 后,后续调用仍会返回一个在我尝试访问它时
LyncClient.GetClient()
抛出的对象。InvalidCastException
异常详情如下:
无法将“System.__ComObject”类型的 COM 对象转换为接口类型“Microsoft.Office.Uc.IClient”。此操作失败,因为 IID 为“{EE9F3E74-AC61-469E-80D6-E22BF4EEFF5C}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:RPC 服务器不可用。(来自 HRESULT 的异常:0x800706BA)。
我在这里尝试了建议:Lync 2013 SDK 开发问题疑难解答。它似乎没有任何区别。在 Lync 运行并再次登录后的几分钟内,我继续获得无效的客户端对象。
这不会每次都发生。如果在我的应用程序启动时 Lync 已经在运行(即第一次调用成功),该问题似乎一直在发生LyncClient.GetClient()
。另一方面,如果我在我的应用程序已经启动 Lync 之后,在多次重新启动 Lync 时一切正常运行(即第一次尝试GetClient()
失败。)
有没有其他人见过这个?有什么建议么?
更新并尝试卸载 AppDomain
我尝试使用此代码获取客户端对象,但行为完全相同:
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;
}
}
}
}
使用专用线程的解决方案示例
感谢来自djp的输入,我实现了这个简单的类来提供 a LyncClient
,并且重新连接现在可以正常工作。
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;
}
}