When calling a WCF RIA Service method using Invoke, does the return type affect when the Completed callback is executed? - wcf

I inherited a Silverlight 5 application. On the server side, it has a DomainContext (service) with a method marked as
[Invoke]
public void DoIt
{
do stuff for 10 seconds here
}
On the client side, it has a ViewModel method containing this:
var q = Context.DoIt(0);
var x=1; var y=2;
q.Completed += (a,b) => DoMore(x,y);
My 2 questions are
1) has DoIt already been activated by the time I attach q.Completed, and
2) does the return type (void) enter into the timing at all?
Now, I know there's another way to call DoIt, namely:
var q = Context.DoIt(0,myCallback);
This leads me to think the two ways of making the call are mutually exclusive.

Although DoIt() is executed on a remote computer, it is best to attach Completed event handler immediately. Otherwise, when the process completes, you might miss out on the callback.
You are correct. The two ways of calling DoIt are mutually exclusive.
If you have complicated logic, you may want to consider using the Bcl Async library. See this blog post.
Using async, your code will look like this:
// Note: you will need the OperationExtensions helper
public async void CallDoItAndDosomething()
{
this.BusyIndicator.IsBusy = true;
await context.DoIt(0).AsTask();
this.BusyIndicator.IsBusy = false;
}
public static class OperationExtensions
{
public static Task<T> AsTask<T>(this T operation)
where T : OperationBase
{
TaskCompletionSource<T> tcs =
new TaskCompletionSource<T>(operation.UserState);
operation.Completed += (sender, e) =>
{
if (operation.HasError && !operation.IsErrorHandled)
{
tcs.TrySetException(operation.Error);
operation.MarkErrorAsHandled();
}
else if (operation.IsCanceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(operation);
}
};
return tcs.Task;
}
}

Related

Wrong Thread.CurrentPrincipal in async WCF end-method

I have a WCF service which has its Thread.CurrentPrincipal set in the ServiceConfiguration.ClaimsAuthorizationManager.
When I implement the service asynchronously like this:
public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
{
// Audit log call (uses Thread.CurrentPrincipal)
var task = Task<int>.Factory.StartNew(this.WorkerFunction, state);
return task.ContinueWith(res => callback(task));
}
public string EndMethod1(IAsyncResult ar)
{
// Audit log result (uses Thread.CurrentPrincipal)
return ar.AsyncState as string;
}
private int WorkerFunction(object state)
{
// perform work
}
I find that the Thread.CurrentPrincipal is set to the correct ClaimsPrincipal in the Begin-method and also in the WorkerFunction, but in the End-method it's set to a GenericPrincipal.
I know I can enable ASP.NET compatibility for the service and use HttpContext.Current.User which has the correct principal in all methods, but I'd rather not do this.
Is there a way to force the Thread.CurrentPrincipal to the correct ClaimsPrincipal without turning on ASP.NET compatibility?
Starting with a summary of WCF extension points, you'll see the one that is expressly designed to solve your problem. It is called a CallContextInitializer. Take a look at this article which gives CallContextInitializer sample code.
If you make an ICallContextInitializer extension, you will be given control over both the BeginXXX thread context AND the EndXXX thread context. You are saying that the ClaimsAuthorizationManager has correctly established the user principal in your BeginXXX(...) method. In that case, you then make for yourself a custom ICallContextInitializer which either assigns or records the CurrentPrincipal, depending on whether it is handling your BeginXXX() or your EndXXX(). Something like:
public object BeforeInvoke(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.IClientChannel channel, System.ServiceModel.Channels.Message request){
object principal = null;
if (request.Properties.TryGetValue("userPrincipal", out principal))
{
//If we got here, it means we're about to call the EndXXX(...) method.
Thread.CurrentPrincipal = (IPrincipal)principal;
}
else
{
//If we got here, it means we're about to call the BeginXXX(...) method.
request.Properties["userPrincipal"] = Thread.CurrentPrincipal;
}
...
}
To clarify further, consider two cases. Suppose you implemented both an ICallContextInitializer and an IParameterInspector. Suppose that these hooks are expected to execute with a synchronous WCF service and with an async WCF service (which is your special case).
Below are the sequence of events and the explanation of what is happening:
Synchronous Case
ICallContextInitializer.BeforeInvoke();
IParemeterInspector.BeforeCall();
//...service executes...
IParameterInspector.AfterCall();
ICallContextInitializer.AfterInvoke();
Nothing surprising in the above code. But now look below at what happens with asynchronous service operations...
Asynchronous Case
ICallContextInitializer.BeforeInvoke(); //TryGetValue() fails, so this records the UserPrincipal.
IParameterInspector.BeforeCall();
//...Your BeginXXX() routine now executes...
ICallContextInitializer.AfterInvoke();
//...Now your Task async code executes (or finishes executing)...
ICallContextInitializercut.BeforeInvoke(); //TryGetValue succeeds, so this assigns the UserPrincipal.
//...Your EndXXX() routine now executes...
IParameterInspector.AfterCall();
ICallContextInitializer.AfterInvoke();
As you can see, the CallContextInitializer ensures you have opportunity to initialize values such as your CurrentPrincipal just before the EndXXX() routine runs. It therefore doesn't matter that the EndXXX() routine assuredly is executing on a different thread than did the BeginXXX() routine. And yes, the System.ServiceModel.Channels.Message object which is storing your user principal between Begin/End methods, is preserved and properly transmitted by WCF even though the thread changed.
Overall, this approach allows your EndXXX(IAsyncresult) to execute with the correct IPrincipal, without having to explicitly re-establish the CurrentPrincipal in the EndXXX() routine. And as with any WCF behavior, you can decide if this applies to individual operations, all operations on a contract, or all operations on an endpoint.
Not really the answer to my question, but an alternate approach of implementing the WCF service (in .NET 4.5) that does not exhibit the same issues with Thread.CurrentPrincipal.
public async Task<string> Method1()
{
// Audit log call (uses Thread.CurrentPrincipal)
try
{
return await Task.Factory.StartNew(() => this.WorkerFunction());
}
finally
{
// Audit log result (uses Thread.CurrentPrincipal)
}
}
private string WorkerFunction()
{
// perform work
return string.Empty;
}
The valid approach to this is to create an extension:
public class SLOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private static ReaderWriterLockSlim _instanceLock = new ReaderWriterLockSlim();
private SLOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static SLOperationContext Current
{
get
{
SLOperationContext context = OperationContext.Current.Extensions.Find<SLOperationContext>();
if (context == null)
{
_instanceLock.EnterWriteLock();
context = new SLOperationContext();
OperationContext.Current.Extensions.Add(context);
_instanceLock.ExitWriteLock();
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Now this extension is used as a container for objects that you want to persist between thread switching as OperationContext.Current will remain the same.
Now you can use this in BeginMethod1 to save current user:
SLOperationContext.Current.Items["Principal"] = OperationContext.Current.ClaimsPrincipal;
And then in EndMethod1 you can get the user by typing:
ClaimsPrincipal principal = SLOperationContext.Current.Items["Principal"];
EDIT (Another approach):
public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
{
var task = Task.Factory.StartNew(this.WorkerFunction, state);
var ec = ExecutionContext.Capture();
return task.ContinueWith(res =>
ExecutionContext.Run(ec, (_) => callback(task), null));
}

MMVM Light Using WCF Asynchronously

What is a good practice to implement MMVM with WCF Services? The View model will be communicating with the service. So lets say in a view I have 3-4 data display modules. All this information for the modules is coming from different WCF Service calls.
If I do this synchronously, I have a feeling that the data in the view model will take time to load.
I want to do the calls for all these service methods asynchronously with out waiting for the first call to come back. What is good way of doing this?
I think the best way is to call the Service Asynchronously and then assign value on Complete method, like:
class TestViewModel : ViewModelBase
{
private ObservableCollection<string> data;
public ObservableCollection<string> Data
{
get { return data; }
set
{
if (value == data) return;
data = value;
RaisePropertyChanged("Data");
}
}
public TestViewModel()
{
GetDataClient proxy = new GetDataClient();
System.EventHandler<GetDataCompletedEventArgs> Client_GetDataCompleted = null;
Client_GetDataCompleted = (s, e) =>
{
if (e.Error == null && e.Result != null)
{
Data = new ObservableCollection<SelectionItem<string>>(e.Result));
}
proxy.GetDataCompleted -= Client_GetDataCompleted;
};
proxy.GetDataCompleted += Client_GetDataCompleted;
proxy.GetDataAsync();
}
}

WCF closing best practice

I read that the best practice for using WCF proxy would be:
YourClientProxy clientProxy = new YourClientProxy();
try
{
.. use your service
clientProxy.Close();
}
catch(FaultException)
{
clientProxy.Abort();
}
catch(CommunicationException)
{
clientProxy.Abort();
}
catch (TimeoutException)
{
clientProxy.Abort();
}
My problem is, after I allocate my proxy, I assign event handlers to it and also initialize other method using the proxy:
public void InitProxy()
{
sdksvc = new SdkServiceClient();
sdksvc.InitClusteringObjectCompleted += new EventHandler<InitClusteringObjectCompletedEventArgs>(sdksvc_InitClusteringObjectCompleted);
sdksvc.InitClusteringObjectAsync(Utils.DSN, Utils.USER,Utils.PASSWORD);
sdksvc.DoClusteringCompleted += new EventHandler<DoClusteringCompletedEventArgs>(sdksvc_DoClusteringCompleted);
sdksvc.CreateTablesCompleted += new EventHandler<CreateTablesCompletedEventArgs>(sdksvc_CreateTablesCompleted);
}
I now need to call the InitProxy() method each Time I use the proxy if I want to use it as best practice suggests.
Any ideas on how to avoid this?
There are several options. One option is to write a helper class as follows:
public class SvcClient : IDisposable {
public SvcClient(ICommunicationObject service) {
if( service == null ) {
throw ArgumentNullException("service");
}
_service = service;
// Add your event handlers here, e.g. using your example:
sdksvc = new SdkServiceClient();
sdksvc.InitClusteringObjectCompleted += new EventHandler<InitClusteringObjectCompletedEventArgs>(sdksvc_InitClusteringObjectCompleted);
sdksvc.InitClusteringObjectAsync(Utils.DSN, Utils.USER,Utils.PASSWORD);
sdksvc.DoClusteringCompleted += new EventHandler<DoClusteringCompletedEventArgs>(sdksvc_DoClusteringCompleted);
sdksvc.CreateTablesCompleted += new EventHandler<CreateTablesCompletedEventArgs>(sdksvc_CreateTablesCompleted);
}
public void Dispose() {
try {
if( _service.State == CommunicationState.Faulted ) {
_service.Abort();
}
}
finally {
_service.Close();
}
}
private readonly ICommunicationObject _service;
}
To use this class write the following:
var clientProxy = new YourClientProxy();
using(new SvcClient(clientProxy)) {
// use clientProxy as usual. No need to call Abort() and/or Close() here.
}
When the constructor for SvcClient is called it then sets up the SdkServiceClient instance as desired. Furthermore the SvcClient class cleans up the service client proxy as well aborting and/or closing the connection as needed regardless of how the control flow leaves the using-block.
I don't see how the ClientProxy and the InitProxy() are linked but if they are linked this strong I'd move the initialization of the ClientProxy to the InitProxy (or make a method that initializes both) so you can control both their lifespans from there.

Best practices for converting WCF calls to async WCF calls

I am running into issues when trying to convert all my normal WCF calls to async WCF calls. I'm finding I have a refactor a lot of code and not sure exactly how to do it. I have used the method that I found here but running into issues where I need things to happen in order.
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoSomeWork(i);
if(i.SomeID == 0)
{
DoSomeMoreWork(i);
}
UpdateRecord(i) // this can't execute until the above code is complete
}
}
private void DoSomeWork(Item i)
{
// call async method
}
private void DoSomeMoreWork(i)
{
// call async method
}
private void UpdateRecord(item i)
{
// call async method
}
What is the best way to refactor code to work in an asyncronous way, or do I need to completely rethink my logic? Do I really have to insert counters and switches everywhere to make sure certain things are done before other things execute?
EDIT: The reason I'm doing this is in the next couple months, we are converting this WPF application to Silverlight, which requires async calls. So I'm trying to convert our regular WCF calls to async in preparation. I'm finding it requires a different way of thinking.
For what you're doing, I'd say the real place to handle things is to make a single call to the service per item, not 3.
Preferably, if the list of items is not huge, make a single call to the service with the whole list...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoAllTheWorkAndUpdate(i);
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
if(i.Id == 0)
{
DoLotsOfWorkAndUpdate(i);
}
else
{
DoSomeWorkAndUpdate(i);
}
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
DoTheWorkOnTheWholeList(itemList);
}
In other words, it feels like some of your responsibilities may be misplaced - I generally prefer to make services where I can make a single call to them. Then, the asynchronous nature is irrelevant, because you're not performing a sequence of events.
Take a look at Juval Lowy's (author of Programming WCF Services) website for examples of how to achieve asynchronous programming in WCF. The downloads are free; you just have to provide your email address.
I am perhaps a bit puzzled as to why you need to use asynchronous WCF operations when you need things to be synchronous inside the loop.
If you are just using the async methods to help keep the UI from hanging, then you could just use a BackgroundWorker that supports progress updates to keep the UI up to date, and not use Async WCF calls.
You should also be able to call your various functions from the Completed events for the Async methods.
Just hook up event handlers to the completed events and then pass your Item object as the userState parameter when you start the async WCF call. This way you will have it as a parameter when each of the Completed events fires. That way you will only be doing the next step in your processing as the previous async call completes.
I don't know if this really is answering your question though.
Try using this
http://ayende.com/Blog/archive/2008/03/29/WCF-Async-without-proxies.aspx
the approach that definitely works.
If you're not using Silverlight, you can block your thread in one method until the other methods complete, using, say, a ManualResetEvent. But that won't work in Silverlight, since all WCF calls happen on the main UI thread, so if you block that thread, everything blocks. A better approach is to do something like this, using callbacks:
public delegate void OperationCallback();
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach (Item i in itemList)
{
DoSomeWork(i, () =>
{
if (i.SomeID == 0)
{
DoSomeMoreWork(i, () =>
{
UpdateRecord(i);
});
}
else
{
UpdateRecord(i);
}
});
}
}
private void DoSomeWork(Item i, OperationCallback callback)
{
// call async method then callback when it completes.
callback();
}
private void DoSomeMoreWork(Item i, OperationCallback callback)
{
// call async method, then callback when it completes.
callback();
}
private void UpdateRecord(Item i)
{
// call async method
}
It's certainly not as clear as the synchronous version, but if you use lambda expressions as much as possible, it's still possible to keep the control flow fairly readable.
Add 2 properties to Item called SomeWorkDone and SomeMoreWorkDone both as booleans. Create methods to handle both DoSomeWorkCompleted and DoSomeMoreWorkCompleted. In those methods, set the respective boolean properties to true and call UpdateRecord. Within UpdateRecord, ensure that both Done properties are true and then complete the calls.
You'll have some possible contention issues but this should get you going.

How do you wait/join on a WCF Web Service called from Silverlight?

If you call a web service from Silverlight like this:
MyServiceClient serviceClient = new MyServiceClient();
void MyMethod()
{
serviceClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(serviceClient_GetDataCompleted);
serviceClient.GetDataAsync();
// HOW DO I WAIT/JOIN HERE ON THE ASYNC CALL, RATHER THAN BEING FORCE TO LEAVE THIS METHOD?
}
I would rather wait/join with the asych service thread inside "MyMethod" rather than leaving "MyMethod" after calling "GetDataAsync", what is the best way to do this?
Thanks,
Jeff
No you cannot do this way. You will end up in a deadlock. GetDataCompleted is called by the mainthreed. The same threed thait is waiting in WaitOne.
I have to ask; why? The point is to provide your user with a fluid experience and waiting on a web service call will not necessarily do that. I suppose you want the full block of content to load before the Silverlight control loads. In that case, I would turn to caching the content rather than forcing the client to wait indefinitely.
To do this you would use a ManualResetEvent in your class (class level variable) and then wait on it.
void MyMethod()
{
wait = new ManualResetEvent(false);
// call your service
wait.WaitOne();
// finish working
}
and in your event handler code
void serviceClient_GetDataCompleted(...)
{
// Set values you need from service
wait.Set();
}
You could also use a lambda and closure to get similar behavior:
serviceClient.GetDataCompleted += (s,e) =>
{
// Your code here
};
serviceClient.GetDataAsync();
If you had a base class provide the mechanics of building a WCF channel, it could then be used to build the BeginX / EndX methods for a async call.
public class ServiceFooCoordinator : CoordinatorBase<IServiceFoo>
{
public IAsyncResult BeginMethodFoo ()
{
IAsyncResult ar = null;
IServiceFoo channel = null;
channel = _factory.GetChannel();
Begin( channel, () => ar = channel.BeginMethodFoo( null, channel ) );
return ar;
}
public Bar[] EndMethodFoo ( IAsyncResult ar )
{
IServiceFoo channel = null;
channel = _factory.GetChannel();
return channel.EndMethodFoo( ar );
}
}
Which can then be used in a method:
ServiceFooCoordinator _coordinator;
var asyncResult = _coordinator.BeginMethodFoo();
try
{
var result = _coordinator.EndMethodFoo( asyncResult );
}
catch ( Exception )
{ }
Which gets you your asynchronous call in a sychronous manner.