I have a problem with calling WCF Service methods with Silverlight 3.
private bool usr_OK = false;
clientService.CheckUserMailAsync(this.mailTF.Text);
if (usr_OK == true)
{ isValidationOK = true; }
else { isValidationOK = false; MessageBox.Show("User already exists.", "User registered succes!", MessageBoxButton.OK); }
CheckUserMail should change usr_OK parameter. However it runs in other thread and it does not change the usr_OK param before IF block begins. I've tried thread.join byt the application freezed and i do not know what to do else. Please help me...how can i wait for WCF method to return param usr_OK.
The most direct answer to your question: Don't block on WCF calls. They make it hard for a reason. There, quite likely, is no way to block if you even tried... but don't.
Elaboration: The mode of operation for Silverlight is Asyncronicity. This is something you have to get used to when you are developing in Silverlight. They make it really hard for you to block on anything.
This is a good thing, in my opinion. When you block on the result of something like a WCF service call, you are ultimately blocking the user thread. It does require some getting used to on the developer's part, but again... get used to it.
Lets say you have code that you want to go like this (Synchronous) :
var theResult = clientService.DoSomething(foo);
Process(theResult);
The way to re-write it would be like this (Asynchronous) :
clientService.DoSomethingCompleted += (sender, args) => Process(args.Result);
clientService.DoSomethingAsync(foo);
Taking it a step further, I like to abstract my services out as interfaces (so I can replace them when testing, or running in stand-alone mode while developing). I take that as an opportunity to create an interface that looks like this:
public interface IMyService
{
void DoSomething(string input, Action<string> whenComplete);
}
I implement the service like the async code above, and then when I call it, it is very clean and simple:
myService.DoSomething(foo, Process);
You will find that much of your system will morph into an asynchronous code base, but it might require you to re-adjust your expectations.
Bind the code that checks the usr_OK variable in the event handler for CheckUserMailCompletedEvent
clientService.CheckUserMailCompleted += new EventHandler<CheckUserMailCompletedEventArgs> (clientService_CheckUserMailCompleted);
clientService.CheckUserMailAsync(this.mailTF.Text);
void clientService_CheckUserMailCompleted(object sender, CheckUserMailCompletedEventArgs e) {
if (usr_OK == true) {
isValidationOK = true;
}
else {
isValidationOK = false;
MessageBox.Show("User already exists.", "User registered success!", MessageBoxButton.OK);
}
}
Related
I wrote some code in an MVC Framework that looks something like:
class Controller_Test extends Controller
{
public function action_index()
{
$obj = new MyObject();
$errors = array();
try
{
$results = $obj->doSomething();
}
catch(MyObject_Exception $e)
{
$e->getErrors();
}
catch(Exception $e)
{
$errors[] = $e->getMessage();
}
}
My friend argues that the Controller should know nothing about MyObject, and therefore I should not catch MyObject_Exception.
He argues that the code should do something like this instead:
class Controller_Test extends Controller
{
public function action_index()
{
$obj = new MyObject();
$errors = array();
if($obj->doSomething())
{
$results = $obj->getResults();
}
else
{
$errors = $obj->getErrors();
}
}
I definitely understand his approach, but feel as though state management can lead to unintended side effects.
What is the right or preferred approach?
Edit: mistakenly put $obj->getErrors() in MyObject_Exception catch clause instead of $e->getErrors();
The debate about exceptions vs. returned error codes is a long and bloody one.
His argument breaks down in that, by using a getErrors() function, you are learning information about the object. If that is your reason for using a boolean return to indicate success, then you are wrong. In order for the Controller to handle the error properly, it has to know about the object it was touching and what the specific error was. Was it a network error? Memory error? It has to know in some way or another.
I prefer the exception model because it's cleaner and allows me to handle more errors in a more controlled fashion. It also provides a clear cut way for the data relating to an exception to be passed.
However, I disagree with your use of a function like getErrors(). Any data pertaining to the exception that would help me handle it should be included with the exception. I should not have to go hunting into the object again to get information about what went wrong.
Did the network connection timeout? The exception should contain the host/port it tried to connect to, how long it waited, and any data from the lower networking levels.
Let's do this in example (in psuedo c#):
public class NetworkController {
Socket MySocket = null;
public void EstablishConnection() {
try {
this.MySocket = new Socket("1.1.1.1",90);
this.MySocket.Open();
} catch(SocketTimeoutException ex) {
//Attempt a Single Reconnect
}
catch(InvalidHostNameException ex) {
Log("InvalidHostname");
Exit();
}
}
}
Using his method:
public class NetworkController {
Socket MySocket = null;
public Boolean EstablishConnection() {
this.MySocket = new Socket("1.1.1.1",90);
if(this.MySocket.Open()) {
return true;
} else {
switch(this.MySocket.getError()) {
case "timeout":
// Reattempt
break;
case "badhost":
Log("InvalidHostname");
break;
}
}
}
}
Ultimately, you need to know what happened to the object to know how to respond to it, and there is no sense in using some convoluted if statement set or switch-case to determine that. Use the exceptions and love them.
EDIT: I accidentally the last half of a sentence.
In general, I would say that what's important is whether the controller understands the meaning of the exception and can handle it properly. In many cases (if not most), the controller will not know how to properly handle the exception, and so should not catch and handle it.
On the other hand, the controller might reasonably be permitted to understand some specific exception like a "DatabaseUnavailableException", even if it has no idea how or why MyObject used a database. The controller might be permitted to retry the call to MyObject a certain number of times, all without knowing about how MyObject is implemented.
First of all controller is not meant for handling the underlying exceptions thrown by classes.
Even if one occurs controller should halt saying something wrong at underlying error.
This way we make sure that controller does really and only do the job of flow control.
The other classes which give controller some output should be error free unless the error is very much controller specific.
The question pretty much sums it up. I have a WCF service, and I want to wait until it finished to do something else, but it has to be until it finishes. My code looks something like this. Thanks!
private void RequestGeoCoordinateFromAddress(string address)
{
GeocodeRequest geocodeRequest = new GeocodeRequest();
GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);
// Make the geocode request
geocodeService.GeocodeAsync(geocodeRequest);
//if (geocodeResponse.Results.Length > 0)
// results = String.Format("Latitude: {0}\nLongitude: {1}",
// geocodeResponse.Results[0].Locations[0].Latitude,
// geocodeResponse.Results[0].Locations[0].Longitude);
//else
// results = "No Results Found";
// wait for the request to finish here, so I can do something else
// DoSomethingElse();
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
bool isErrorNull = e.Error == null;
Exception error = e.Error;
try
{
double altitude = e.Result.Results[0].Locations[0].Latitude;
double longitude = e.Result.Results[0].Locations[0].Longitude;
SetMapLocation(new GeoCoordinate(altitude, longitude));
}
catch (Exception ex)
{
// TODO: Remove reason later
MessageBox.Show("Unable to find address. Reason: " + ex.Message);
}
}
There is a pattern, supported by WCF, for a call to have an asynchronous begin call, and a corresponding end call.
In this case, the asynchronous methods would be in the client's interface as so:
[ServiceContract]
interface GeocodeService
{
// Synchronous Operations
[OperationContract(AsyncPattern = false, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
GeocodeResults Geocode(GeocodeRequestType geocodeRequest);
// Asynchronous operations
[OperationContract(AsyncPattern = true, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
IAsyncResult BeginGeocode(GeocodeRequestType geocodeRequest, object asyncState);
GeocodeResults EndGeocode(IAsyncResult result);
}
If you generate the client interface using svcutil with the asynchronous calls option, you will get all of this automatically. You can also hand-create the client interface if you aren't using automatically generating the client proxies.
The End call would block until the call is complete.
IAsyncResult asyncResult = geocodeService.BeginGeocode(geocodeRequest, null);
//
// Do something else with your CPU cycles here, if you want to
//
var geocodeResponse = geocodeService.EndGeocode(asyncResult);
I don't know what you've done with your interface declarations to get the GeocodeAsync function, but if you can wrangle it back into this pattern your job would be easier.
You could use a ManualResetEvent:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
Obviously doing this makes absolutely no sense, so the question here is: why do you need to do this? Why using async call if you are going to block the main thread? Why not use a direct call instead?
Generally when using async web service calls you shouldn't block the main thread but do all the work of handling the results in the async callback. Depending of the type of application (WinForms, WPF) you shouldn't forget that GUI controls can only be updated on the main thread so if you intend to modify the GUI in the callback you should use the appropriate technique (InvokeRequired, ...).
Don't use this code with Silverlight:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
When we call _wait.WaitOne(TimeSpan.FromMinutes(2)), we are blocking the UI thread, which means the service call never takes place. In the background, the call to geocodeService.GeocodeAsync is actually placed in a message queue, and will only be actioned when the thread is not executing user code. If we block the thread, the service call never takes place.
Synchronous Web Service Calls with Silverlight: Dispelling the async-only myth
The Visual Studio 11 Beta inludes C# 5 with async-await.
See Async CTP - How can I use async/await to call a wcf service?
It makes it possible to write async clients in a 'synchronous style'.
I saw one guy did use ManualReset and waitAll, but he had to wrap all code inside of ThreadPool..
It is very bad idea...thought it works
I have a question regarding the sequencing of events in the scenario where you are calling a wcf service from silverlight 3 and updating the ui on a seperate thread. Basically, I would like to know whether what I am doing is correct... Sample is as follows. This is my first post on here, so bear with me, because i am not sure how to post actual code. Sample is as follows :
//<summary>
public static void Load(string userId)
{
//Build the request.
GetUserNameRequest request =
new GetUserNameRequest { UserId = userId };
//Open the connection.
instance.serviceClient = ServiceController.UserService;
//Make the request.
instance.serviceClient.GetUserNameCompleted
+= UserService_GetUserNameCompleted;
instance.serviceClient.GetGetUserNameAsync(request);
return instance.VM;
}
/// <summary>
private static void UserService_GetUserNameCompleted(object sender, GetUserNameCompletedEventArgs e)
{
try
{
Controller.UIDispatcher.BeginInvoke(() =>
{
//Load the response.
if (e.Result != null && e.Result.Success)
{
LoadResponse(e.Result);
}
//Completed loading data.
});
}
finally
{
instance.serviceClient.GetUserNameCompleted
-= UserService_GetUserNameCompleted;
ServiceHelper.CloseService(instance.serviceClient);
}
}
So my question basically is, inside of my UI thread when I am loading the response if that throws an exception, will the "finally" block catch that ? If not, should i put another try/catch inside of the lambda where I am loading the response ?
Also, since I am executing the load on the ui thread, is it possible that the finally will execute before the UI thread is done updating ? And could as a result call the Servicehelper.CloseService() before the load has been done ?
I ask because I am having intermittent problems using this approach.
The finally block should get executed before the processing of the response inside the BeginInvoke. BeginInvoke means that the code will get executed in the next UI cycle.
Typically the best approach to this type of thing is to pull all the data you need out of the response and store it in a variable and then clean up your service code. Then make a call to BeginInvoke and update the UI using the data in the variable.
I'm finding mixed answers to my question out in the web. To elaborate on the question:
Should I instantiate a service client proxy once per asynchronous invocation, or once per Silverlight app?
Should I close the service client proxy explicitly (as I do in my ASP.NET MVC application calling WCF services synchronously)?
I've found plenty of bloggers and forum posters out contradicting each other. Can anyone point to any definitive sources or evidence to answer this once and for all?
I've been using Silverlight with WCF since V2 (working with V4 now), and here's what I've found. In general, it works very well to open one client and just use that one client for all communications. And if you're not using the DuplexHttBinding, it also works fine to do just the opposite, to open a new connection each time and then close it when you're done. And because of how Microsoft has architected the WCF client in Silverlight, you're not going to see much performance difference between keeping one client open all the time vs. creating a new client with each request. (But if you're creating a new client with each request, make darned sure you're closing it as well.)
Now, if you're using the DuplexHttBinding, i.e., if you want to call methods on the client from the server, it's of course important that you don't close the client with each request. That's just common sense. However, what none of the documentation tells you, but which I've found to be absolutely critical, is that if you're using the DuplexHttBinding, you should only ever have one instance of the client open at once. Otherwise, you're going to run into all sorts of nasty timeout problems that are going to be really, really hard to troubleshoot. Your life will be dramatically easier if you just have one connection.
The way that I've enforced this in my own code is to run all my connections through a single static DataConnectionManager class that throws an Assert if I try to open a second connection before closing the first. A few snippets from that class:
private static int clientsOpen;
public static int ClientsOpen
{
get
{
return clientsOpen;
}
set
{
clientsOpen = value;
Debug.Assert(clientsOpen <= 1, "Bad things seem to happen when there's more than one open client.");
}
}
public static RoomServiceClient GetRoomServiceClient()
{
ClientsCreated++;
ClientsOpen++;
Logger.LogDebugMessage("Clients created: {0}; Clients open: {1}", ClientsCreated, ClientsOpen);
return new RoomServiceClient(GetDuplexHttpBinding(), GetDuplexHttpEndpoint());
}
public static void TryClientClose(RoomServiceClient client, bool waitForPendingCalls, Action<Exception> callback)
{
if (client != null && client.State != CommunicationState.Closed)
{
client.CloseCompleted += (sender, e) =>
{
ClientsClosed++;
ClientsOpen--;
Logger.LogDebugMessage("Clients closed: {0}; Clients open: {1}", ClientsClosed, ClientsOpen);
if (e.Error != null)
{
Logger.LogDebugMessage(e.Error.Message);
client.Abort();
}
closingIntentionally = false;
if (callback != null)
{
callback(e.Error);
}
};
closingIntentionally = true;
if (waitForPendingCalls)
{
WaitForPendingCalls(() => client.CloseAsync());
}
else
{
client.CloseAsync();
}
}
else
{
if (callback != null)
{
callback(null);
}
}
}
The annoying part, of course, is if you only have one connection, you need to trap for when that connection closes unintentionally and try to reopen it. And then you need to reinitialize all the callbacks that your different classes were registered to handle. It's not really all that difficult, but it's annoying to make sure it's done right. And of course, automated testing of that part is difficult if not impossible . . .
You should open your client per call and close it immediately after. If you in doubt browse using IE to a SVC file and look at the example they have there.
WCF have configuration settings that tells it how long it should wait for a call to return, my thinking is that when it does not complete in the allowed time the AsyncClose will close it. Therefore call client.AsyncClose().
In classic ASP.NET I’d persist data extracted from a web service in base class property as follows:
private string m_stringData;
public string _stringData
{ get {
if (m_stringData==null)
{
//fetch data from my web service
m_stringData = ws.FetchData()
}
return m_stringData;
}
}
This way I could simply make reference to _stringData and know that I’d always get the data I was after (maybe sometimes I’d use Session state as a store instead of a private member variable).
In Silverlight with a WCF I might choose to use Isolated Storage as my persistance mechanism, but the service call can't be done like this, because a WCF service has to be called asynchronously.
How can I both invoke the service call and retrieve the response in one method?
Thanks,
Mark
In your method, invoke the service call asynchronously and register a callback that sets a flag. After you have invoked the method, enter a busy/wait loop checking the flag periodically until the flag is set indicating that the data has been returned. The callback should set the backing field for your method and you should be able to return it as soon as you detect the flag has been set indicating success. You'll also need to be concerned about failure. If it's possible to get multiple calls to your method from different threads, you'll also need to use some locking to make your code thread-safe.
EDIT
Actually, the busy/wait loop is probably not the way to go if the web service supports BeginGetData/EndGetData semantics. I had a look at some of my code where I do something similar and I use WaitOne to simply wait on the async result and then retrieve it. If your web service doesn't support this then throw a Thread.Sleep -- say for 50-100ms -- in your wait loop to give time for other processes to execute.
Example from my code:
IAsyncResult asyncResult = null;
try
{
asyncResult = _webService.BeginGetData( searchCriteria, null, null );
if (asyncResult.AsyncWaitHandle.WaitOne( _timeOut, false ))
{
result = _webService.EndGetData( asyncResult );
}
}
catch (WebException e)
{
...log the error, clean up...
}
Thanks for your help tvanfosson. I followed your code and have also found a pseudo similar solution that meets my needs exactly using a lambda expression:
private string m_stringData;
public string _stringData{
get
{
//if we don't have a list of departments, fetch from WCF
if (m_stringData == null)
{
StringServiceClient client = new StringServiceClient();
client.GetStringCompleted +=
(sender, e) =>
{
m_stringData = e.Result;
};
client.GetStringAsync();
}
return m_stringData;
}
}
EDIT
Oops... actually this doesn't work either :-(
I ended up making the calls Asynchronously and altering my programming logic to use MVVM pattern and more binding.