Thursday, October 19, 2017

Calling a WCF method in Excel switches “context” and lets Word continue “work”

Leave a Comment

My issue is hard to explain since I am not 100% sure my self, what is going on. I will therefor try my best to explain the situation.

Just a warning, if you are hoping there will be code you have to look at and try to find an error, I am afraid I cannot provide such a thing, since it is more a general problem I am facing instead of an error in a code.

So... lets begin

I have a Excel AddIn, a WPF Application and a WCF Server all written by me and I can adjust any side, if that may be neccassary.

In my Excel AddIn, I call WCF Server methods to retrieve data from the WPF application.

Upon, opening a Excel Workbook my AddIn will update its values, and therefor call WCF Server.

This works fine, when the user "normally" opens the Excel Workbook, but fails when this happens "automatically" by code.

One such scenario is, that the mentioned Excel Workbook is linked in a MS Word Document multiple times, with a field function for example

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

When a user opens the MS Word Document, containing multipe of those links to the same file, MS Word will open the Excel Workbook for each link and after "evaluating" it, it then closes the workbook.

So, if the MS Word Document has 10 links to the same Excel Workbook, it will open/close this Excel Workbook 10 times.

This again, is no problem.

Now, comes the catch.

When the user has an Excel instance running, before opening the MS Word Document, it will fail opening the linked Excel Workbook at the second link with a message stating, the workbook is already open, if you open it a second time all changes will get lost do you wish to continue.

So for some reason, the first time the Workbook got opened, MS Word failed to close it.

Through, a lot of trial and error, I localized the error to be a call to my WCF Server.

The call is:

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

When I call this line, it seems as if Excel doesnt block MS Word from continuing its works, so while MS Word already is trying to close and open the next link, I am still in the routine to get all information from my WCF Server, and since I still have a reference to the Excel Workbook at Hand, MS Word just simply cannot close the workbook.

The method is defined as this in my interface:

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

As you can see, I dont use Task<ReturnObject>, so I expect it to run synchronous and block the running thread.

I have done a little testing around calling the method and could fix my problem with those two approaches:

1st approach:

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

2nd approach:

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) {  } 

Both approaches, do basically the same with the only difference the first creates a Thread and the second a BackgroundWorker.

The goal I had in mind, with those 2 is to "off-load" the call to WCF Server and block the calling thread with a simple while loop.

You may imagine, that I am not really happy with those "solutions".

Is there a way to let Excel block "entirely" when calling my WCF Server method?

What does actually happen here, as I dont really undertand what "magic" is happening, I only guess some "Synchronization.Context" switching is taking place, but I really have no clue?

1 Answers

Answers 1

The point is that the call to your server.GetBatch is already blocking, but the caller is just part of a parallel task activity.

The only difference with your workaround is that the while loop is eating cpu resources and that indirectly blocks the execution.

What you can really consider, is to look at managing concurrency at the WCF service level.

Just one reference among many:

When the service is configured with ConcurrencyMode.Single, WCF will provide automatic synchronization to the service context and disallow concurrent calls by associating the context containing the service instance with a synchronization lock. Every call coming into the service must first try to acquire the lock. If the lock is unowned, the caller will be allowed in. Once the operation returns, WCF will unlock the lock, thus allowing in another caller.

For a more extended reference to the correct WCF synchronization, here it is another link.

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

enter image description here

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment