multiple amount of asynchronous calls to web service in Silverlight, bind response to request
I want to send multiple asynchronous calls to different web services with silverlight and be able to match the responses to each request.
Lets say i have a list with n items in it. Every item represents a string URL of a web service. So you may have 2 services, but you also may have 7. Now, i have a GUI and when i press a button, the list with the URLs is iterated and to every service a request is sent. You do not know how many services you might call, so it has to be dynamic. I have solved the sending part, and i get all the responses, BUT with my solution there is no way to figure out which response refers to which request.
private void startCall(object sender, RoutedEventArgs e)
{
var urls = {"http://this.is.the.first/service1", "http://this.is.thesecond/service2", "http://this.is.thethirt/service3"};
foreach (var item in urls)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringC开发者_Python百科ompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri(item));
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
list_ResponseFromServer.Add(e.Result.ToString());
}
}
In this example i have 3 services/items in the list. And i also get 3 responses to the handler void wc_DownloadStringCompleted, but i do not know in what order. Its obvious i want to have
ListRequest(A,B,C,D,E)
ListResponse(A,B,C,D,E)
but i do not know if response A takes much longer than response B,C
so I might get in my ListResponse(B,C,D,A,E)
=> what is FAIL
I have seen some examples with 2 asynchronous calls, but they were all hardcoded. For every request, response they had several hardcoded methods/handlers. It would be great if someone could help me to solve this problem with a variable amount of multiple asynchronous calls to different webServices
One approach would be to use a delegate to create a capture like this:-
private void startCall(object sender, RoutedEventArgs e)
{
var urls = {"http://this.is.the.first/service1", "http://this.is.thesecond/service2", "http://this.is.thethirt/service3"};
foreach string item in urls)
{
Uri uri = new Uri(item);
WebClient wc = new WebClient();
wc.DownloadStringCompleted += (s, args) =>
{
if (args.Error == null)
{
// You can use the uri variable to determine which Uri this is a response to.
// NOTE: don't use item variable here.
list_ResponseFromServer.Add(args.Result);
}
};
wc.DownloadStringAsync(new Uri(item));
}
}
Edit: Response to comments
By one means or another you need a way to corelate a response to the orignating request. The Silverlight API offers no built in mechanism to do that, there is no standard solution. So yes you need to write your own code to relate an asynchronous response to the originating Url if that is important to you. If you prefer to use the original string url then add another string variable inside the foreach
code block and assign item
to it.
What it sounds like you are looking for is away to guarantee the order that the responses arrive in to match the order they are generated. The only way to do that is to issue each request only when the previous response has arrived. Whilst that is possible (I've written a series of blogs on the subject), I wouldn't recommend it as solution in this case.
You can pass a custom object to DownloadStringAsync, so I change a little Anthony code:
var urls = {"http://this.is.the.first/service1", "http://this.is.thesecond/service2", "http://this.is.thethirt/service3"};
var i = 0;
var maxRequests = urls.Length;
Dictionary<int, string> dict = new Dictionary<int,string>();
foreach (string item in urls)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += (s, args) =>
{
if (args.Error == null)
{
//add the the caller "id" and the response
dict.Add((int)args.UserState, args.Result);
}
//here you test if it is the last request... if it is, you can
//order the list and use it as you want
if (dict.Count == maxRequests)
{
var orderedResults = dict.OrderBy(a => a.Key);
}
};
wc.DownloadStringAsync(new Uri(item), i++);
}
}
for (int i = 0; i < urls.Count; i++)
{
if (uri.AbsoluteUri.ToString().Equals(urls[i]))
{
list_ResponseFromServer.RemoveAt(i);
list_ResponseFromServer.Insert(i, args.Result);
}
}
that was my fast hack how to bring responses into same order like the requests. If everything is unique you could use "break;" too
精彩评论