i have a function which retrieves values from a webservice , then loops through the returned values and for each returned value does another webservice lookup.
Im having a problem however that when i make the second webservice call within the for loop that the function does not wait for the reuslt and just keeps processing and in turn giving me no value
the code looks like this;
private function getResult(e:ResultEvent):void{
var lengthOfResult:int = e.result.length;
var arrayCollResults:ArrayCollection = new ArrayCollection();
var resultArray:Array = new Array(e.result);
for(var i:int = 0 ; i < lengthOfResult; i++){
var currentName:String = e.result[i].toString();
arrayCollResults.addItem(e.result[i] + ws.getMatches(currentName));
}
acu.dataProvider = arrayCollResults;
}
what can i do to insure that the value of ws.getMatches(currentName) actually returns a value before moving to next line?
The documentation here indicates that you do not call the Web service directly, you need to set up an event listener and handle the response on completed delivery.
From the section "Calling web services in ActionScript":
<?xml version="1.0"?>
<!-- fds\rpc\WebServiceInAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.rpc.soap.WebService;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
private var ws:WebService;
public function useWebService(intArg:int, strArg:String):void {
ws = new WebService();
ws.destination = "echoArgService";
ws.echoArgs.addEventListener("result", echoResultHandler);
ws.addEventListener("fault", faultHandler);
ws.loadWSDL();
ws.echoArgs(intArg, strArg);
}
public function echoResultHandler(event:ResultEvent):void {
var retStr:String = event.result.echoStr;
var retInt:int = event.result.echoInt;
//Do something.
}
public function faultHandler(event:FaultEvent):void {
//deal with event.fault.faultString, etc
}
]]>
</mx:Script>
</mx:Application>
Put the "arrayCollResults.addItem(...)" segment in the result handler for your ws.getMatches() event.
As far as I know flex/as3 cannot do a blocking wait for the result - you have to add a listener and wait to be notified.
Related
I would like to add an item to a list:
void submitAll() async {
List<UserSearchItem> userSearchItems = [];
Firestore.instance
.collection('insta_users')
.snapshots()
.listen((data) =>
data.documents.forEach((doc){
print(data.documents.length);
User user = new User.fromDocument(doc);
UserSearchItem searchItem = new UserSearchItem(user);
userSearchItems.add(searchItem);
print(user.bio);
}));
print("Loaded");
print(userSearchItems.length);
}
But if I print the length of the list to the console, it always says, the list is 0 long...
print(userSearchItems.length);
Any suggegstions?
Best Regards
I will try to give an explanation of what is happing here take a look on this code:
import 'dart:async';
void main() {
List<int> userSearchItems = [];
Timer _sendTimeOutTimer;
const oneSec = Duration(seconds: 2);
_sendTimeOutTimer = Timer.periodic(oneSec, (Timer t) {
userSearchItems.add(1);
print(userSearchItems.length); // result 1 and it will be executed after 2 seconds
_sendTimeOutTimer.cancel();
});
print(userSearchItems.length); // result 0 and it will be executed first
}
The print inside asynchronous action(Timer) it will be executed after 2 seconds means after the asynchronous action ends but the one which is outside of asynchronous action(Timer) it will be executed directly without waiting 2 seconds, in your case the asynchronous action is listening to data .listen((data) =>, so if you print the length outside of your asynchronous action you will not see the deferent because the item is not added yet.
Solution: you can create function witch return Future and then wait until it's finished then print the length.
List<UserSearchItem> userSearchItems = [];
Future<String> submitAll() async {
Firestore.instance
.collection('insta_users')
.snapshots()
.listen((data) =>
data.documents.forEach((doc){
print(data.documents.length);
User user = new User.fromDocument(doc);
UserSearchItem searchItem = new UserSearchItem(user);
userSearchItems.add(searchItem);
print(user.bio);
return 'success';
}));
}
void yourFunction() async{
await submitAll();
print("Loaded");
print(userSearchItems.length);
}
Then call yourFunction().
Try to add print(userSearchItems.length); inside forEach after adding the item and you will see the real length.
There is a simple way tu add new data tu a list on Flutter.
for (var i = 0; i < list.length; i++) {
double newValue=newValue+1; //This is just an example,you should put what you'r trying to add here.
list[i]["newValueName"] = newValue; //This is how we add the new value tu the list,
}
See if it work by doing a:
print(list);//You can put a breakpoint her to see it more clearly
Hope it helps.
My question is about a strange behavious I notice both on my iPhone device and the codenameone simulator (NetBeans).
I invoke the following code below which calls a google web service to provide a list of food places around a GPS coordinate:
The web service that is called is as follows (KEY OBSCURED):
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXXXXXXXXXXXXXXXXX
Each result contains the next page token and thus, the second call (for the subsequent page) is as follows:
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXXXXXXXXXXXXXXXXX&pagetoken=YYYYYYYYYYYYYYYYYY
public static byte[] getWSResponseData(String urlString, boolean usePost)
{
ConnectionRequest r = new ConnectionRequest();
r.setUrl(urlString);
r.setPost(usePost);
InfiniteProgress prog = new InfiniteProgress();
Dialog dlg = prog.showInifiniteBlocking();
r.setDisposeOnCompletion(dlg);
NetworkManager.getInstance().addToQueueAndWait(r);
try
{
Thread.sleep(2000);
}
catch (InterruptedException ex)
{
}
byte[] responseData = r.getResponseData();
return responseData;
}
public static void getLocationsList(double lat, double lng)
{
boolean done = false;
while (!done)
{
byte[] responseData = getWSResponseData(finalURL,false);
result = Result.fromContent(parser.parseJSON(new InputStreamReader(new ByteArrayInputStream(responseData))));
String venueNames[] = result.getAsStringArray("/results/name");
nextToken = result.getAsString("/next_page_token");
if ( nextToken == null || nextToken.equals(""))
done = true;
else
finalURL = completeURL + "&pagetoken=" + nextToken;
}
.....
}
This code works fine with the sleep timer, but when I remove the Thread.sleep, only the first page gets called.
Any help would be appreciated.
Using the debugger does not help as this is a timing issue and the issue does not occur when using the debugger.
Also when I put some print statements into the code
while (!done)
{
String nextToken = null;
**System.out.println(finalURL);**
...
}
System.out.println("Total Number of entries returned: " + itemCount);
I get the following output:
First Run (WITHOUT SLEEP):
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXX
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXX&pagetoken=CqQCF...
Total Number of entries returned: 20
Using the network monitor I see that the response to the second WS call returns:
{
"html_attributions" : [],
"results" : [],
"status" : "INVALID_REQUEST"
}
Which is strange as when I cut and paste the WS URL into my browser, it works fine...
Second Run (WITH SLEEP):
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXXX
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXXX&pagetoken=CqQCFQEAA...
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.714353,-74.00597299999998&radius=200&types=food&key=XXXXXXXXX&pagetoken=CsQDtQEAA...
Total Number of entries returned: 60
Well it seems to be a google API issue as indicated here:
Paging on Google Places API returns status INVALID_REQUEST
I still could not get it to work by changing the WS URL with a random parameter as they suggested, but I will keep trying and post something here if I get it to work. For now I will just keep a 2 second delay between the calls which seems to work.
Well gave up on using the google WS for this and switched to Yelp, works very well:
https://api.yelp.com/v3/businesses/search?.....
How do I create a webservice using Mono For Android? It seems like everything is about consuming a webservice, and not really about creating one.
I've tried using this: http://www.mono-project.com/Writing_a_WebService
But System.Web.Services.WebService doesn't exist. System.ServiceModel hasn't been translated yet either. Does anyone have clues on how to create a webservice on Mono For Android?
Thanks
I have now tried to implement the following code and tried to run it in the emulator, but the request I make either through my browser or through a REST client, never reaches the HandleRequest.
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var startBtn = FindViewById<Button>(Resource.Id.StartBtn);
stopBtn.Clickable = false;
startBtn.Click += SetupListener;
}
private void SetupListener(object sender, EventArgs e) {
_httpListener = new HttpListener();
_httpListener.Prefixes.Add("http://*:9876/");
_httpListener.Start();
_httpListener.BeginGetContext(HandleRequest, _httpListener);
}
private void HandleRequest(IAsyncResult result) {
var context = _httpListener.EndGetContext(result);
var response = "<html>Hello World</html>";
var buffer = Encoding.UTF8.GetBytes(response);
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.OutputStream.Close();
_httpListener.BeginGetContext(HandleRequest, _httpListener);
}
I have tried making request like the following: http:// localhost:9876/ , http:// 10.1.1.190:9876/ and http:// 10.0.2.2:9876/ but none of them actually reaches into the application.
I am creating an application for a client that integrates with the LinkedIn API. I got through the authentication without too many problems, but everything there is working and now I need to make the actual requests. Primarily I am working in the Share API. I create the HTTP call with the following method:
public any function sendRequest(any req){
var param = false;
var headParams = [];
var bodyParams = [];
var call = new http(proxyserver='192.168.201.12', proxyport=8888);
var i = 1;
call.setUrl(Arguments.req.getRequestUrl());
call.setMethod(Arguments.req.getMethod());
getSigner().signRequest(Arguments.req);
headParams = Arguments.req.getParameters(true);
bodyParams = Arguments.req.getParameters();
if(arrayLen(bodyParams)){
call.addParam(
type='header',
name='Authorization',
value="OAuth#Variables.encoder.encodedParameter(Arguments.req.getParameters(true), true, false, true)#"
);
}
// Header parameters
if(!arrayLen(bodyParams)){
for(i=1; i<=arrayLen(headParams); i++){
param = headParams[i];
call.addParam(
type=Arguments.req.getParameterType(),
name=Variables.encoder.parameterEncodedFormat(param.name),
value=param.value
);
}
}
// Body parameters (should only be 1)
if(arrayLen(bodyParams)){
for(i=1; i<=arrayLen(bodyParams); i++){
param = bodyParams[i];
call.addParam(
type='xml',
value=param.value
);
}
}
return call.send().getPrefix();
}
When I sign the request, I use the following method:
public void function signRequest(any req){
var headParams = Arguments.req.getParameters(true);
var bodyParams = Arguments.req.getParameters();
var secret = "#Variables.encoder.parameterEncodedFormat(getConsumer().getConsumerSecret())#&#Variables.encoder.parameterEncodedFormat(Arguments.req.getOAuthSecret())#";
var base = '';
params = Variables.encoder.encodedParameter(headParams, true, true);
params = "#params#&#Variables.encoder.parameterEncodedFormat(bodyParams[1].value)#";
secret = toBinary(toBase64(secret));
local.mac = createObject('java', 'javax.crypto.Mac').getInstance('HmacSHA1');
local.key = createObject('java', 'javax.crypto.spec.SecretKeySpec').init(secret, local.mac.getAlgorithm());
base = "#Arguments.req.getMethod()#&";
base = base & Variables.encoder.parameterEncodedFormat(Arguments.req.getRequestUrl());
base = "#base#&#Variables.encoder.parameterEncodedFormat(params)#";
//writeDump(base) abort;
local.mac.init(local.key);
local.mac.update(JavaCast('string', base).getBytes());
Arguments.req.addParameter('oauth_signature', toString(toBase64(mac.doFinal())), true);
}
I have tried signing it with only the header parameters (usual OAuth params) and include the body parameter (xml string), but everything gives me a 401 error, so I was wondering what I should be using in my base string that gets signed for the request?
Not a proper answer to your question, but may help you.
In my case after many unsuccessful tries of using the LinkedIn API with CF8, I finally gave up / didn't have more time for it. Instead of a "proper" integration I've used the linkedin-j Java library. It finally got me going and I didn't encounter any more signing issues.
Btw for all my integrations requiring OAuth I've used this library and didn't have any signing issues as with LinkedIn API.
Another day , another question. My service layer has the following method
public MatchViewData CreateMatch(string user)
{
var matchViewData = !HasReachedMaxNumberOfMatchesLimit(user) ?
CreateMatchAndAddToRepository(user) :
MatchViewData.NewInstance(new Match(user));
matchViewData.LimitReached = HasReachedMaxNumberOfMatchesLimit(user);
return matchViewData;
}
The method calls the this helper method to create a new match object:
private MatchViewData CreateMatchAndAddToRepository(string user)
{
var match = new Match(user);
MatchRepository.Add(match);
return MatchViewData.NewInstance(match);
}
The repository stores the given match object and sets the id to some value > 0.
public void Add(Match match)
{
Check.Require(match != null);
var numberOfMatchesBefore = Matches.Count;
SetIdPerReflection(match, NextVal());
Matches.Add(match);
Check.Ensure(numberOfMatchesBefore == Matches.Count - 1);
}
The matchviewdata object copies some properties of the the match object (including the id).
My unit test should verify that the resulting viewdata object in the service has an id > 0. To archieve this, i have to mock the repository and the behaviour of the add method. But the service method creates a new match object every time its been called and the add method on the repository updates the referenced match object (there is no need for a return value). I have no idea to solve this with moq.
This is my unit test so far:
[Test]
public void ServiceCreateMatchReturnedMatchViewDataHasNonZeroId()
{
var match = TestUtils.FakePersistentMatch(User, 1);
var repositoryMock = new Mock<IMatchRepository>();
repositoryMock.Setup(
r => r.Add(It.IsAny<Match>())).Callback(() => match.Id = 1);
var serviceFacade = new DefaultServiceFacade(repositoryMock.Object);
var returnedMatch = serviceFacade.CreateMatch(User);
Assert.That(returnedMatch.Id, Is.GreaterThan(0));
}
I tried some other variations - nothing works.
It looks to me your problem is in this line;
repositoryMock.Setup(
r => r.Add(It.IsAny<Match>())).Callback(() => match.Id = 1);
What you're actually doing here is setting the id of the first match object you have declared in your test, NOT the new match created in your service.
Because the Match object you will be supplying to the Repository is created internally, I can't think of an easy way to reference it in your Test method to setup a callback for it. To me, this is a sign you may be trying to test too much in one unit test.
I think you should simply test that the Add method is called and write a separate test to ensure that it works as exepected.
I propose something like this;
[Test]
public void ServiceAddsNewMatchToRepository()
{
var repositoryMock = new Mock<IMatchRepository>();
bool addCalled = false;
repositoryMock
.Expect(r => r.Add(It.Is<Match>(x => x.Id == 0))
.Callback(() => addCalled = true);
var serviceFacade = new DefaultServiceFacade(repositoryMock.Object);
serviceFacade.CreateMatch(User);
Assert.True(addCalled);
}
....
[Test]
public void AddingANewMatchGeneratesANewId()
{
var match = new Match(user);
var matchRepository = new MatchRepository();
var returnedMatch = matchRepository.Add(match);
Assert.That(returnedMatch.Id, Is.GreaterThan(0));
}