从对 LyncClient.GetClient() 的调用中获取无效对象
Getting an invalid object from a call to LyncClient.GetClient()
注意:更新了问题底部的解决方案
我在使用 Lync 2013 SDK 的应用程序时遇到了一些问题。这是我看到的行为:
- 如果在我启动我的应用程序时 Lync 已经 运行,那么对
LyncClient.GetClient()
的调用将 return 一个有效的客户端对象。
- 如果在我启动应用程序时 Lync 不是 运行,则对
LyncClient.GetClient()
的调用将抛出 ClientNotFoundException
。我可以处理异常并启动计时器以 ping 客户端出现。稍后,当我启动 Lync 时,LyncClient.GetClient()
将 return 一个有效的客户端对象。
- 如果 Lync 在我的应用程序处于 运行 时退出,那么我可以通过多种方式检测到这种情况,并启动一个计时器来 ping 客户端回来。
到目前为止一切顺利,但问题出在这里:
- 如果 Lync 在我的应用程序处于 运行 时消失,那么对
LyncClient.GetClient()
的后续调用似乎 return 一个有效的客户端对象(即使 Lync 不是 运行 ), 但尝试调用此对象抛出 InvalidCastException
.
- 即使在 Lync 重新启动后,对
LyncClient.GetClient()
的后续调用仍然 return 一个在我尝试访问它时抛出 InvalidCastException
的对象。
异常详情如下:
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).
我尝试了这里的推荐:Troubleshooting Lync 2013 SDK development issues。它似乎没有任何区别。在 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 的输入,我实现了这个简单的 class 以提供 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;
}
}
我假设您正在与 Lync 服务器断开连接。 LyncClient.GetClient()
方法可能仍然有效,因为您有一些挥之不去的变量,但您将无法使用它执行任何 Lync 操作。
我认为查看 UI 压制内容会有所帮助。
https://msdn.microsoft.com/en-us/library/office/hh345230%28v=office.14%29.aspx
“•如果 Lync 在我的应用程序处于 运行 时消失,那么对 LyncClient.GetClient() 的后续调用似乎 return 是一个有效的客户端对象(即使 Lync 不是 运行), 但尝试调用此对象抛出 InvalidCastException."
能否详细说明 "If Lync goes away" 是什么意思?您是说您已注销 Lync 还是退出了 Lync(即没有 Lync 进程 运行)?如果您刚退出 Lync LyncClient
将不会抛出异常。您可以收听 LyncClient.StateChanged
事件并检查 clientStateChangedEventArgs.NewState
事件。
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
}
}
当用户退出 Lync 时 - 我启动计时器类似于您的方法并尝试初始化 Lync,如下所示:
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
}
}
这对我有用。可能是机器特定问题。
我遇到了同样的问题,我的解决方法是确保对 LyncClient.GetClient()
的每次调用都发生在同一个线程上
注意:更新了问题底部的解决方案
我在使用 Lync 2013 SDK 的应用程序时遇到了一些问题。这是我看到的行为:
- 如果在我启动我的应用程序时 Lync 已经 运行,那么对
LyncClient.GetClient()
的调用将 return 一个有效的客户端对象。 - 如果在我启动应用程序时 Lync 不是 运行,则对
LyncClient.GetClient()
的调用将抛出ClientNotFoundException
。我可以处理异常并启动计时器以 ping 客户端出现。稍后,当我启动 Lync 时,LyncClient.GetClient()
将 return 一个有效的客户端对象。 - 如果 Lync 在我的应用程序处于 运行 时退出,那么我可以通过多种方式检测到这种情况,并启动一个计时器来 ping 客户端回来。
到目前为止一切顺利,但问题出在这里:
- 如果 Lync 在我的应用程序处于 运行 时消失,那么对
LyncClient.GetClient()
的后续调用似乎 return 一个有效的客户端对象(即使 Lync 不是 运行 ), 但尝试调用此对象抛出InvalidCastException
. - 即使在 Lync 重新启动后,对
LyncClient.GetClient()
的后续调用仍然 return 一个在我尝试访问它时抛出InvalidCastException
的对象。
异常详情如下:
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).
我尝试了这里的推荐:Troubleshooting Lync 2013 SDK development issues。它似乎没有任何区别。在 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 的输入,我实现了这个简单的 class 以提供 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;
}
}
我假设您正在与 Lync 服务器断开连接。 LyncClient.GetClient()
方法可能仍然有效,因为您有一些挥之不去的变量,但您将无法使用它执行任何 Lync 操作。
我认为查看 UI 压制内容会有所帮助。 https://msdn.microsoft.com/en-us/library/office/hh345230%28v=office.14%29.aspx
“•如果 Lync 在我的应用程序处于 运行 时消失,那么对 LyncClient.GetClient() 的后续调用似乎 return 是一个有效的客户端对象(即使 Lync 不是 运行), 但尝试调用此对象抛出 InvalidCastException."
能否详细说明 "If Lync goes away" 是什么意思?您是说您已注销 Lync 还是退出了 Lync(即没有 Lync 进程 运行)?如果您刚退出 Lync LyncClient
将不会抛出异常。您可以收听 LyncClient.StateChanged
事件并检查 clientStateChangedEventArgs.NewState
事件。
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
}
}
当用户退出 Lync 时 - 我启动计时器类似于您的方法并尝试初始化 Lync,如下所示:
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
}
}
这对我有用。可能是机器特定问题。
我遇到了同样的问题,我的解决方法是确保对 LyncClient.GetClient()
的每次调用都发生在同一个线程上