method returning value appears as void in silverlight - silverlight

I have written a webmethod that returns the list of the Users althought the service works fine, when I call it from the page the methods in the webservice have return type as void.

What you might be thrown off by is that web service calls in Silverlight must be handled asynchronously.
When you define a WebMethod, say for example you have one called DoWork on a Class called WorkMan. Your code in the Silverlight would end up looking like:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(this.DoWorkCompleteHandler); // where DoWorkCompletedHandler handles the callback.
Then you call your actual method and allow the callback to process the result.
client.DoWorkAsync();
If your webmethod returns a value, your EventArg object will have a Result property that you can leverage for the result.
One final note: a personal stylistic thing but I like lambda expressions rather than generating a whole new method for the callback. I might write something like the following:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += (s,e) => {
if(e.Result != null){
object foo = e.Result;
}
};
client.DoWorkAsync();

Related

Managing async service calls using Silverlight and Reactive Extensions

So I'm reading up on Rx and having a difficult time grokking it. I have a Silverlight app that needs to make say 6 calls to a specific service asynchronously. In the old days, we'd handle this by making the calls and querying the userState/token to match the response with the request since they're not guaranteed to return in the order we called them. However, I suspect Rx handles this in a far more elegant manner. But I can't get it to work. Here's what I have so far...
myCollection.Add(new myObject(1));
myCollection.Add(new myObject(2));
myCollection.Add(new myObject(3));
myCollection.Add(new myObject(4));
myCollection.Add(new myObject(5));
myCollection.Add(new myObject(6));
foreach (var myItem in myCollection)
{
var myObservable = Observable.FromEventPattern<MyServiceMethodCompletedEventArgs>
(
f => myServiceClient.MyServiceMethodCompleted += f,
f => myServiceClient.MyServiceMethodCompleted -= f
).Take(1).ObserveOn(SynchronizationContext.Current);
myObservable.Subscribe
(
s =>
{
if (s.EventArgs.Error == null)
{
myItem.MyProperty = s.EventArgs.Result;
}
}
);
myServiceClient.MyServiceMethodAsync(myItem);
}
I hope you can see what I'm trying to achieve here...
What I end up with is all of myObject's being set to the result of the first call that returns.
I'm sure it's something silly but I haven't been able to figure it out yet.
Thanks :)
Consider trying the Observable.FromAsyncPattern instead of Observable.FromEventPattern. There is a trick to using FromAsyncPattern in Silverlight (and the phone) because the BeginInvoke/EndInvoke pair are not exposed directly by the service proxy. However, if you use the interface for the service proxy rather than the service proxy itself, you can access the begin/end pattern:
IMyService svc = new myServiceClient();
var svcObservable = Observable.FromAsyncPattern<T, MyServiceResultArgs>
(svc.BeginMyServiceMethod, svc.EndMyServiceMethod);
Now, you can switch from using foreach (an anti-pattern with LINQ) to making your myCollection into an observable and SelectMany between the myCollection and the service request as follows:
var requestResult = from myItem in myCollection.ToObservable()
from result in svcObservable(myItem)
select new {myItem, result};
requestResult.Subscribe(result => result.myItem.myProperty = result.result);
One additional word of caution: If you use the FromAsyncPattern in silverlight this way, the result will come back on a background thread. You will need to take care teo delegate back to the dispatcher.
If you want to see this in action, check out the last 20 minutes or so of my Mix presentation at http://channel9.msdn.com/events/MIX/MIX11/EXT08.

Partial Trust JavaScript Object Access in XBAP via HostScript: SecurityException in Callbacks

I've encountered a problem with the XBAP Script Interop feature that was added in WPF 4. It involves a combination of the following:
Accessing members of a script object from .NET
Running .NET code in a callback invoked from JavaScript
Running in Partial trust
This seems to be a "pick any two" scenario... If I try and do all three of those things, I get a SecurityException.
For example, combining 1 and 3 is easy. I can put this into my hosting web page's script:
function ReturnSomething()
{
return { Foo: "Hello", Bar: 42 };
}
And then in, say, a button click handler in my WPF code behind, I can do this:
dynamic script = BrowserInteropHelper.HostScript;
if (script != null)
{
dynamic result = script.ReturnSomething();
string foo = result.Foo;
int bar = result.Bar;
// go on to do something useful with foo and bar...
}
That works fine, even in a partial trust deployment. (I'm using the default ClickOnce security settings offered by the WPF Browser Application template in Visual Studio 2010, which debugs the XBAP as though it were running in the Internet zone.) So far, so good.
I can also combine 2 and 3. To make my .NET method callable from JavaScript, sadly we can't just pass a delegate, we have to do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(int arg)
{
return "Value: " + arg;
}
}
and then I can declare a JavaScript method that looks like this:
function CallMethod(obj)
{
var result = obj.MyMethod(42);
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and now in, say, a WPF button click handler, I can do this:
script.CallMethod(new CallbackClass());
So my WPF code calls (via BrowserInteropHelper.HostScript) my JavaScript CallMethod function, which in turn calls my .NET code back - specifically, it calls the MyMethod method exposed by my CallbackClass. (Or I could mark the callback method as a default method with a [DispId(0)] attribute, which would let me simplify the JavaScript code - the script could treat the argument itself as a method. Either approach yields the same results.)
The MyMethod callback is successfully called. I can see in the debugger that the argument passed from JavaScript (42) is getting through correctly (having been properly coerced to an int). And when my method returns, the string that it returns ends up in my HTML UI thanks to the rest of the CallMethod function.
Great - so we can do 2 and 3.
But what about combining all three? I want to modify my callback class so that it can work with script objects just like the one returned by my first snippet, the ReturnSomething function. We know that it's perfectly possible to work with such objects because that first example succeded. So you'd think I could do this:
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(dynamic arg)
{
return "Foo: " + arg.Foo + ", Bar: " + arg.Bar;
}
}
and then modify my JavaScript to look like this:
function CallMethod(obj)
{
var result = obj.MyMethod({ Foo: "Hello", Bar: 42 });
var myElement = document.getElementById("myElement");
myElement.innerText = "Result: " + result;
}
and then call the method from my WPF button click handler as before:
script.CallMethod(new CallbackClass());
this successfully calls the JavaScript CallMethod function, which successfully calls back the MyMethod C# method, but when that method attempts to retrieve the arg.Foo property, I get a SecurityException with a message of RequestFailed. Here's the call stack:
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessSecurityEngine.Check(PermissionSet permSet, StackCrawlMark& stackMark)
at System.Security.PermissionSet.Demand()
at System.Dynamic.ComBinder.TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject& result, Boolean delayInvocation)
at Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder.FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
at System.Dynamic.DynamicMetaObject.BindGetMember(GetMemberBinder binder)
at System.Dynamic.GetMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at XBapDemo.CallbackClass.MyMethod(Object arg)
That's the whole trace as reported by the exception. And above CallbackClass.MyMethod, Visual Studio is showing two lots of [Native to Managed Transition] and an [AppDomain Transition] - so that's the whole of the stack. (Apparently we're on a different thread now. This callback is happening on what the Threads panel describes as a Worker Thread - I can see that the Main Thread is still sat inside my WPF button click handler, waiting for the call to the JavaScript CallMethod function to return.)
Apparently the problem is that the DLR has ended up wrapping the JavaScript object in the ComBinder which demands full trust. But in the earlier case where I called a JavaScript method via HostScript and it returned me an object, the HostScript wrapped it in a System.Windows.Interop.DynamicScriptObject for me.
The DynamicScriptObject class is specific to WPFs XBAP script interop - it's not part of the usual DLR types, and it's defined in PresentationFramework.dll. As far as I can tell, one of the jobs it does is to make it possible to use C#'s dynamic keyword to access JavaScript properties without needing full trust, even though those properties are being accessed through COM interop (which usually requires full trust) under the covers.
As far as I can tell, the problem is that you only get these DynamicScriptObject wrappers for objects that are returned from other DynamicScriptObject instances (such as HostScript). With callbacks, that wrapping doesn't seem to occur. In my callback, I'm getting the sort of dynamic wrapper C# would normally give me in plain old COM interop scenarios, at which point, it demands that I have full trust.
Running it with full trust works fine - that would be the "1 and 2" combination from the list above. But I don't want to have full trust. (I want 1, 2, and 3.) And outside of callback situations, I can access JavaScript object members just fine. It seems inconsistent that I can access a JavaScript object just fine most of the time, but accessing an identical object in a callback is forbidden.
Is there a way around this? Or am I doomed to run my code in full trust if I want to do anything interesting in a callback?
I haven't done XBAP in a while, but I am curious if it is the dynamic type that could be causing the issue. Try changing the dynamic parameter to type object and see if it will work.
[ComVisible(true)]
public class CallbackClass
{
public string MyMethod(object arg)
{
return "Arg is: " + arg.ToString();
}
}

Silverlight Webservice Problem

I have a webservice that calls a method and returns a generic list. The webservice completed method looks like this (note: names and e.Result are both of the same type of List):
void SetNames()
{
ServiceReference1.ServiceClient webservice = new ServiceReference1.ServiceClient();
webservice.GetNameCompleted += new EventHandler<GetNameCompletedEventArgs>(webservice_GetNameCompleted);
webservice.GetNameAsync();
}
private void webservice_GetNameCompleted(object sender, ServiceReference1.GetNameCompletedEventArgs e)
{
names = e.Result;
}
The problem I'm having is that I can only retrieve the items in the names list in the webservice method. Whenever I try to access the items in the names list anywhere outside of that method it is empty. For example (this displays nothing in the textbox),
List<string> names = new List<string>();
public MainPage()
{
InitializeComponent();
SetNames();
foreach (string name in names)
textBox1.Text += name;
}
But this will display the correct thing:
private void webservice_GetNameCompleted(object sender, ServiceReference1.GetNameCompletedEventArgs e)
{
names = e.Result;
foreach (string name in names)
textBox1.Text += name;
}
I'm new to Silverlight and webservies, and I'm probably over looking something. I've been working on this for a while and I'm at the point where I feel I need to ask for help. Any help would be greatly appreciated!
In Silverlight all calls to web-services are asynchronous (unlike WPF which can also use synchronous call).
It means that the code after the call to the web-service will be invoked before the service has sent a response to the Silverlight client.
So, in the MainPage constructor, the foreach loop is iterating over the collection BEFORE the service has returned, and then iterate over an empty collection.
The right way to proceed is the second one : initializing the collection after the service has responded, in the callback method dedicated to this task : webservice_GetNameCompleted.
You have to wait for the Web Servicec call back to complete.
By defualt all Silverlight WCF web service calls are asynchronous.
you are sending a request to the webservice and unlike .asmx with WCF and Silverlight the application continues to run instead of waiting for the webservice to return a result.
So when you make a call like:
public MainPage()
{
InitializeComponent();
SetNames();
foreach (string name in names)
textBox1.Text += name;
}
The application does not stop and wait for SetNames to Return a value it just carries on and since the webservice hasn't returned a result yet you have a blank or null list still when you call your foreach.
Cheers

Silverlight Async Design Pattern Issue

I'm in the middle of a Silverlight application and I have a function which needs to call a webservice and using the result complete the rest of the function.
My issue is that I would have normally done a synchronous web service call got the result and using that carried on with the function. As Silverlight doesn't support synchronous web service calls without additional custom classes to mimic it, I figure it would be best to go with the flow of async rather than fight it. So my question relates around whats the best design pattern for working with async calls in program flow.
In the following example I want to use the myFunction TypeId parameter depending on the return value of the web service call. But I don't want to call the web service until this function is called. How can I alter my code design to allow for the async call?
string _myPath;
bool myFunction(Guid TypeId)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += new System.EventHandler<WS_WebService1.GetPathByTypeIdCompleted>(proxy_GetPathByTypeIdCompleted);
proxy.GetPathByTypeIdAsync(TypeId);
// Get return value
if (myPath == "\\Server1")
{
//Use the TypeId parameter in here
}
}
void proxy_GetPathByTypeIdCompleted(object sender, WS_WebService1.GetPathByTypeIdCompletedEventArgs e)
{
string server = e.Result.Server;
myPath = '\\' + server;
}
Thanks in advance,
Mike
The best would be to use Reactive Extensions. Then (assuming you'd create an extension method IObservable<string> GetPathByTypeId(string typeId) on WS_WebService1SoapClient you can do this:
proxy
.GetPathByTypeId(TypeId)
.Subscribe(server =>
{
//Here you can do stuff with the returned value
});
As close to having synchronous call as it gets :)
Given the asynch nature of Silverlight you cannot return values from myFunction. Instead you can pass an Action which is executed once the service call is complete. See the example code below. I am not sure if it is considered best practice, but I use this "pattern" a lot and it has always worked fine for me.
EDIT
Updated the code below to include multiple arguments in the callback action.
void DoSomething(Guid TypeId, Action<int, bool> Callback)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += (s, e) =>
{
string server = e.Result.Server;
myPath = '\\' + server;
//
if (myPath == "\\Server1")
{
Callback(888, true);
}
else
{
Callback(999, false);
}
};
proxy.GetPathByTypeIdAsync(TypeId);
}
void CallDoSomething()
{
DoSomething(Guid.NewGuid(), (returnValue1, returnValue2) =>
{
//Here you can do stuff with the returned value(s)
});
}
Put the processing of the GetPathByTypeId result into the GetPathByTypeIdCompleted callback. Assign mypath there. Make mypath a property and implement the INotifyPropertyChanged interface to notify dependents of Mypath that Mypath has changed.
Observer depends on mypath
Observer sets a notification event for mypath
Get Mypath by asynchronous invocation of GetPathByTypeId
Mypath is set, invokes notifiaction of Observer
Observer works with Mypath

Calling a webservice synchronously from a Silverlight 3 application?

I am trying to reuse some .NET code that performs some calls to a data-access-layer type service. I have managed to package up both the input to the method and the output from the method, but unfortunately the service is called from inside code that I really don't want to rewrite in order to be asynchronous.
Unfortunately, the webservice code generated in Silverlight only produces asynchronous methods, so I was wondering if anyone had working code that managed to work around this?
Note: I don't need to execute the main code path here on the UI thread, but the code in question will expect that calls it makes to the data access layers are synchronous in nature, but the entire job can be mainly executing on a background thread.
I tried the recipe found here: The Easy Way To Synchronously Call WCF Services In Silverlight, but unfortunately it times out and never completes the call.
Or rather, what seems to happen is that the completed event handler is called, but only after the method returns. I am suspecting that the event handler is called from a dispatcher or similar, and since I'm blocking the main thread here, it never completes until the code is actually back into the GUI loop.
Or something like that.
Here's my own version that I wrote before I found the above recipe, but it suffers from the same problem:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
Basically, both recipes does this:
Set up a ManualResetEvent
Hook into the Completed event
The event handler grabs the result from the service call, and signals the event
The main thread now starts the web service call asynchronously
It then waits for the event to become signalled
However, the event handler is not called until the method above has returned, hence my code that checks for evt != null and such, to avoid TargetInvocationException from killing my program after the method has timed out.
Does anyone know:
... if it is possible at all in Silverlight 3
... what I have done wrong above?
I suspect that the MinGatServices thingy is trying to be helpful by ensuring the ExecuteRequestCompleted is dispatched on the main UI thread.
I also suspect that your code is already executing on the main UI thread which you have blocked. Never block the UI thread in Silverlight, if you need to block the UI use something like the BusyIndicator control.
The knee-jerk answer is "code asynchronously" but that doesn't satisfy your question's requirement.
One possible solution that may be less troublesome is to start the whole chunk of code from whatever user action invokes it on a different thread, using say the BackgroundWorker.
Of course the MinGatServices might be ensuring the callback occurs on the same thread that executed ExecuteRequestAsync in which case you'll need to get that to run on a different thread (jumping back to the UI thread would be acceptable):-
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));

Resources