ПРИМЕЧАНИЕ. Обновлено решением внизу вопроса.
У меня возникли проблемы с приложением, использующим Lync 2013 SDK. Вот поведение, которое я вижу:
- Если Lync уже запущен, когда я запускаю свое приложение, то вызов
LyncClient.GetClient()
вернет действительный клиентский объект. - Если Lync не запущен, когда я запускаю свое приложение, вызов
LyncClient.GetClient()
вызоветClientNotFoundException
. Я могу обработать исключение и запустить таймер для проверки связи с клиентом. Позже, когда я запущу Lync,LyncClient.GetClient()
вернет действительный клиентский объект. - Если Lync завершает работу во время работы моего приложения, я могу обнаружить эту ситуацию несколькими способами и запустить таймер для проверки связи, чтобы клиент вернулся.
Пока все хорошо, но вот где возникают проблемы:
- Если Lync отключается во время работы моего приложения, то последующие вызовы
LyncClient.GetClient()
кажутся возвращающими допустимый клиентский объект (даже если Lync не запущен), но попытки вызова этого объекта вызываютInvalidCastException
. - Даже после перезапуска Lync последующие вызовы
LyncClient.GetClient()
по-прежнему возвращают объект, который выдаетInvalidCastException
при попытке доступа к нему.
Детали исключения:
Невозможно привести COM-объект типа «System.__ComObject» к типу интерфейса «Microsoft.Office.Uc.IClient». Эта операция завершилась неудачно, так как вызов QueryInterface компонента COM для интерфейса с IID "{EE9F3E74-AC61-469E-80D6-E22BF4EEFF5C}" завершился неудачно из-за следующей ошибки: сервер RPC недоступен. (Исключение из HRESULT: 0x800706BA).
Я попробовал рекомендации здесь: Устранение неполадок при разработке Lync 2013 SDK. Кажется, это не имеет никакого значения. Я продолжаю получать недопустимый объект клиента в течение многих минут после запуска Lync и повторного входа в систему.
Это происходит не каждый раз. Проблема, по-видимому, довольно часто возникает, если Lync уже запущен, когда мое приложение запускается (т. е. самый первый вызов LyncClient.GetClient()
завершается успешно). уже работает (т.е. первая попытка 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 я реализовал этот простой класс для предоставления 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;
}
}
public static LyncClient GetClient
-static
меня вот смущает. Если реализация этого метода кэширует COM-объект в лениво инициализируемой статической переменной и нет возможности аннулировать кешированное значение, то единственный способ — создать другой домен приложения, создать этот метод в этом домене и выгрузить домен, когда Lync был закрыт и вы поймали исключение. Вы сравнивали ссылки, возвращенныеGetClient
? Они одинаковы? Есть ли способ, который позволяет сбросить/пересоздать значение клиента? - person Dennis   schedule 05.06.2015GetHashCode()
выводит одно и то же значение снова и снова, когда я получаю плохой объект. OTOH, я каждый раз получаю уникальный хеш-код в сценарии, где переподключения работают правильно. Я не могу найти способ сбросить кеш. - person danBhentschel   schedule 05.06.2015GetClient()
никогда не изменится, пока я не перезапущу программу. Это не проблема признания действительного результата. Проблема в том, что результат всегда недействителен при определенной последовательности событий. - person danBhentschel   schedule 05.06.2015LyncClient
требуется несколько секунд, но не минут. Не уверен, но это может быть проблема с машиной. Может попробовать проделать ту же операцию на какой-нибудь другой машине? - person Ankit Vijay   schedule 06.06.2015