Вызов метода WCF в Excel переключает "контекст" и позволяет Word продолжать "работать",

Моя проблема трудно объяснить, так как я не уверен на 100% сам, что происходит. Я сделаю все возможное, чтобы объяснить ситуацию.

Просто предупреждение, если вы надеетесь, что будет код, на который вы должны обратить внимание, и попытайтесь найти ошибку, я боюсь, что не могу предоставить такую ​​вещь, так как это более общая проблема, с которой я столкнулся, вместо того, ошибка в коде.

Итак... давайте начнем

У меня есть приложение Excel AddIn, приложение WPF и WCF-сервер, все написанные мной, и я могу настроить любую сторону, если это может быть неудобно.

В моем Excel AddIn я вызываю методы WCF Server для извлечения данных из приложения WPF.

После открытия Excel Workbook мой AddIn обновит его значения и вызовет WCF-сервер.

Это отлично работает, когда пользователь "нормально" открывает книгу Excel, но не работает, когда это происходит "автоматически" по коду.

Одним из таких сценариев является то, что упомянутая книга Excel тесно связана в документе MS Word с помощью функции поля, например

{ LINK Excel.Sheet.12 "C:\test.xlsx" "Sheet1!R1C1" }

Когда пользователь открывает документ MS Word, содержащий многоточие этих ссылок на один и тот же файл, MS Word откроет книгу Excel для каждой ссылки и после "оценки" она закрывает книгу.

Итак, если в документе MS Word имеется 10 ссылок на ту же книгу Excel, она откроет/закроет эту книгу Excel 10 раз.

Это опять же не проблема.

Теперь идет catch.

Когда пользователь запускает экземпляр Excel, перед открытием документа MS Word он не сможет открыть связанную книгу Excel по второй ссылке с сообщением о том, что рабочая книга уже открыта, если вы откроете ее во второй раз изменения будут потеряны, вы хотите продолжить.

Итак, по какой-то причине при первом открытии Workbook MS Word не удалось закрыть его.

Благодаря большому количеству проб и ошибок я локализовал ошибку как вызов моего WCF-сервера.

Вызов:

ReturnObject result = server.GetBatch(parameters, baseClass);

Когда я вызываю эту строку, кажется, что Excel не блокирует MS Word продолжением своих работ, поэтому, хотя MS Word уже пытается закрыть и открыть следующую ссылку, я все еще в рутине, чтобы получить всю информацию из моего WCF Server, и поскольку у меня все еще есть ссылка на книгу Excel Handbook, MS Word просто не может закрыть книгу.

Метод определяется как это в моем интерфейсе:

[OperationContract()]
ReturnObject GetBatch(List<Parameter> parameters, ClientInfo clientInfo);

Как вы можете видеть, я не использую Task<ReturnObject>, поэтому я ожидаю, что он будет работать синхронно и заблокировать текущий поток.

Я провел небольшое тестирование вокруг вызова метода и смог исправить мою проблему с помощью этих двух подходов:

1-й подход:

ReturnObject result = null;
Thread th = new Thread(() => { result = server.GetBatch(parameters, baseClass); });
th.Start();
while (th.IsAlive)
{

}

Второй подход:

ReturnObject result = null;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (sender, args) => { result = server.GetBatch(parameters, baseClass); };
bw.RunWorkerCompleted += (sender, args) => {  };
bw.RunWorkerAsync();

while (bw.IsBusy)
{

}

Оба подхода, делают в основном то же самое с единственной разницей, что первый создает a Thread, а второй a BackgroundWorker.

Цель, которую я имел в виду, с этими 2 - "отключить" вызов на сервер WCF и заблокировать вызывающий поток простым циклом while.

Вы можете себе представить, что я не очень доволен этими "решениями".

Есть ли способ, чтобы Excel блокировал "полностью" при вызове моего метода WCF Server?

Что на самом деле происходит здесь, так как я действительно не понимаю, что такое "волшебство", я только предполагаю, что происходит переключение "Синхронизация. Контекст", но я действительно понятия не имею.

Ответ 1

Дело в том, что вызов вашего server.GetBatch уже блокируется, но вызывающий является лишь частью параллельной задачи.

Единственное различие с вашим обходным путем заключается в том, что цикл while использует ресурсы процессора и косвенно блокирует выполнение.

Что вы действительно можете рассмотреть, это посмотреть на управление concurrency на уровне службы WCF.

Только один ссылка среди многих:

Когда служба настроена с помощью ConcurrencyMode.Single, WCF будет обеспечить автоматическую синхронизацию с контекстом службы и запретить одновременные вызовы путем связывания контекста, содержащего службу экземпляр с блокировкой синхронизации. Каждый звонок, входящий в служба должна сначала попытаться приобрести замок. Если блокировка не используется, вызов будет разрешен. После того, как операция вернется, WCF будет разблокируйте замок, тем самым разрешив другому вызывающему абоненту.

Для более подробной ссылки на правильную синхронизацию WCF, здесь это еще одна ссылка .

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, 
                 ConcurrencyMode = ConcurrencyMode.Single)]
public class BatchService : IBatchService
{
}

введите описание изображения здесь