Someone else before me wrote a program that takes a bunch of UPS tracking #'s and queries UPS for the status of these. The problem is, with time this program has grown more complex. These queries are now taking too long. It takes about 350ms per query, and some pages have nearly 40 queries, taking about ~15 seconds to load per page.
The method takes in a tracking # as a string and then makes some sort of xml request to UPS which returns the correct data, just very slowly.
Here is the code:
public static List<string> MakeRequest(string tracking)
{
List<string> res = new List<string>();
string xmlStringRequest = "<?xml version=\"1.0\"?>" +
"<AccessRequest xml:lang=\"en-US\">" +
"<AccessLicenseNumber>apilicense</AccessLicenseNumber>" +
"<UserId>apiusername</UserId>" +
"<Password>apipassword</Password>" +
"</AccessRequest>" +
"<?xml version=\"1.0\"?>" +
"<TrackRequest xml:lang=\"en-US\">" +
"<Request>" +
"<TransactionReference>" +
"<CustomerContext>Your Test Case Summary Description</CustomerContext>" +
"<XpciVersion>1.0</XpciVersion>" +
"</TransactionReference>" +
"<RequestAction>Track</RequestAction>" +
"<RequestOption>1</RequestOption>" +
"</Request>" +
"<TrackingNumber>" + tracking + "</TrackingNumber>" +
"</TrackRequest>";
ASCIIEncoding encodedData = new ASCIIEncoding();
byte[] byteArray = encodedData.GetBytes(xmlStringRequest);
//Create Request
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("https://onlinetools.ups.com/ups.app/xml/Track");
wr.Method = "POST";
wr.KeepAlive = false;
//wr.ContentType = "application/x-www-form-urlencoded";
wr.ContentLength = byteArray.Length;
XmlDocument xmlDoc = new XmlDocument();
try
{
//Send XML
Stream SendStream = wr.GetRequestStream();
SendStream.Write(byteArray, 0, byteArray.Length);
SendStream.Close();
//Get Response
WebResponse response = wr.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
//Console.Write(reader.ReadToEnd());
xmlDoc.LoadXml(reader.ReadToEnd());
XmlNode nl = xmlDoc.GetElementsByTagName("ResponseStatusCode").Item(0);
response.Close();
if (nl.InnerText == "1")
{
XmlNode del = xmlDoc.GetElementsByTagName("ActivityLocation").Item(0);
XmlNodeList act = del.ChildNodes;
foreach (XmlNode n in act)
{
if (n.Name == "Code")
{
res.Add(n.InnerText);
}
else if (n.Name == "Description")
{
res.Add(n.InnerText);
}
else if (n.Name == "SignedForByName")
{
res.Add(n.InnerText);
}
else
{
continue;
}
}
res.Add(xmlDoc.GetElementsByTagName("Date").Item(0).InnerText);
res.Add(xmlDoc.GetElementsByTagName("Time").Item(0).InnerText);
}
else
{
res.Add("Tracking Info Not Available");
}
}
catch (Exception ex)
{
xmlDoc = null;
}
return res;
}
I stepped through the code, and what seems to take the longest is this line:
SendStream.Write(byteArray, 0, byteArray.Length);
Is there an obvious way to increase the speed/efficiency of this query? I'm more familiar with jSON than XML.
Related
I'm trying to create a Bulk API to send Data to Salesforce .Here is my Code`
string userName = "XXXX";
//Console.Write("Enter password: ");
string password = "XXX";
string SessionId = SalesforceLogin(userName, password);
string JobId = CreateJob(SessionId, "insert", "Contact");
byte[] inputFileData = null;
string jobId = string.Empty;
string resultId = string.Empty;
string batchId = string.Empty;
if (JobId.Length > 0)
{
System.IO.FileInfo oFile = null;
//oFile = New System.IO.FileInfo("data.csv")
oFile = new System.IO.FileInfo(#"D:\request.txt");
System.IO.FileStream oFileStream = oFile.OpenRead();
long lBytes = oFileStream.Length;
int a = (int)lBytes; //modified after conversion
if ((lBytes > 0))
{
byte[] fileData = new byte[lBytes];
// Read the file into a byte array
oFileStream.Read(fileData, 0, a); //modified after conversion
oFileStream.Close();
//Get the file where the Query is present
inputFileData = fileData;
}
batchId= AddBatch(SessionId, JobId, inputFileData);
After that, I create A Job
private static string CreateJob(string sessionId, string sfOperation, string sfObjectName)
{
string str = "";
string reqURL = "";
byte[] bytes;
XmlDocument reqDoc;
XmlDocument respDoc;
str = ""
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" // added \r\n as recommended by L.B's answer
+ "<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
+ " <operation></operation>" // removed "+sfOperation+"
+ " <object></object>" // removed "+sfObjectName+"
+ " <contentType>XML</contentType>" // should be CSV, NOT XML
+ "</jobInfo>"
;
reqURL = "https://ap2.salesforce.com/services/async/23.0/job";
reqDoc = new XmlDocument();
reqDoc.LoadXml(str);
// added XML modifications
reqDoc.GetElementsByTagName("operation")[0].InnerText = sfOperation;
reqDoc.GetElementsByTagName("object")[0].InnerText = sfObjectName;
bytes = System.Text.Encoding.ASCII.GetBytes(reqDoc.InnerXml);
respDoc = Post(bytes, reqURL, sessionId); // create job
string JobId = (respDoc != null) ?
(respDoc.GetElementsByTagName("id").Count > 0) ?
(respDoc.GetElementsByTagName("id")[0].InnerText) :
"" :
""
;
return JobId;
}`
Then I create A Batch to
private static string AddBatch(string sessionId, string jobId, byte[] fileBytes)
{
string reqURL = "https://ap2.salesforce.com/services/async/23.0/job/" + jobId + "/batch";
XmlDocument respDoc = Post(fileBytes, reqURL, sessionId);
string batchId = (respDoc != null) ?
(respDoc.GetElementsByTagName("id").Count > 0) ?
(respDoc.GetElementsByTagName("id")[0].InnerText) :
"" :
""
;
return batchId;
}
Then the Post Method
private static XmlDocument Post(byte[] bytes, string reqURL, object sfSessionId)
{
WebRequest req = WebRequest.Create(reqURL);
req.Method = "POST";
if ((bytes != null))
{
req.ContentLength = bytes.Length;
}
req.ContentType = "application/xml; charset=UTF-8"; // should be text/csv; when passing a CSV file
req.Headers.Add("X-SFDC-Session: " + sfSessionId);
System.IO.Stream strm = req.GetRequestStream();
if ((bytes != null))
strm.Write(bytes, 0, bytes.Length);
strm.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
System.IO.Stream respStrm = resp.GetResponseStream();
XmlDocument respDoc = new XmlDocument();
respDoc.Load(respStrm);
return respDoc;
}
Everything Going Good But when I'm trying to save the Data on Lead it displays the Error
InvalidBatch : Failed to parse XML. Failed to get next element
After Creating Batch I get Result
<?xml version="1.0" encoding="UTF-8"?><batchInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload"><id>7512800000C8OHAAA3</id><jobId>75028000008qk53AAA</jobId><state>Queued</state><createdDate>2017-05-30T14:11:45.000Z</createdDate><systemModstamp>2017-05-30T14:11:45.000Z</systemModstamp><numberRecordsProcessed>0</numberRecordsProcessed><numberRecordsFailed>0</numberRecordsFailed><totalProcessingTime>0</totalProcessingTime><apiActiveProcessingTime>0</apiActiveProcessingTime><apexProcessingTime>0</apexProcessingTime></batchInfo>
One More thing After inserting the Batch, How this job will execute .I'm pasting all the code because it may help Someone if i get the Answer :).
I'm trying to get some data from Aerospike into SOLR, but I'm having a little problem with the web requests to SOLR. I'm using c#-s HttpWebRequest for the web requests on multiple threads. After a few batches the process gets blocked.
I found out that the code stops at the data = request.GetRequestStream(); line, no exceptions, no messages, no timeouts it just waits and does nothing.
Here is a part of my code:
public static ConcurrentBag<String> docs = new ConcurrentBag<String>();
public static int count { get; set; }
<< data extraction into the "docs" container >>
if (count == 50)
{
string dataStr = "{";
string temp;
lock (docs)
{
while (!docs.IsEmpty)
{
docs.TryTake(out temp);
dataStr += temp;
}
}
dataStr = dataStr.ToString().Remove(dataStr.ToString().Length - 1) + "}";
count = 0;
string SOLRInsert = "http://192.168.23.28:8985/solr/test/update";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SOLRInsert);
request.ContentType = "application/json";
request.Method = "POST";
byte[] dataBytes = Encoding.ASCII.GetBytes(dataStr);
request.ContentLength = dataBytes.Length;
request.Proxy = null;
Stream data = null;
try
{
data = request.GetRequestStream();
sw.Start();
data.Write(dataBytes, 0, dataBytes.Length);
sw.Stop();
//data.Close();
data.Dispose();
}
catch (Exception ex)
{
Console.Write(key.userKey.ToString() + "->" + ex.ToString() + "\r\n");
File.AppendAllText(#"import.log", key.userKey.ToString() + "->" + ex.ToString() + Environment.NewLine);
}
finally
{
if (data != null)
{
//data.Close();
data.Dispose();
}
}
}
Any help would be appreciated.
I obtain an access_token OK from Facebook, but whenever I try to use it, it fails (bad request).
It looks like the access_token is not being sent to the server correctly. I have used Server.UrlEncode to encode it.
Any ideas what I am doing wrong?
string ourAccessToken = "unknown";
//--------------------------------------
protected void Page_Load(object sender, EventArgs e)
{
getAccessToken();
getMe();
}
// -----------------------
private void getAccessToken()
{
string result = "unknown";
try
{
// get app access token
string thisURL = "https://graph.facebook.com/oauth/access_token";
thisURL += "?client_id=" + ourClientID;
thisURL += "&client_secret=" + ourClientSecret;
thisURL += "&grant_type=client_credentials";
thisURL += "&redirect_uri=" + Server.UrlEncode(ourSiteRedirectURL);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create( thisURL);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpStatusCode rc = response.StatusCode;
if( rc == HttpStatusCode.OK)
{
StreamReader Sreader = new StreamReader( response.GetResponseStream());
result = Sreader.ReadToEnd();
Sreader.Close();
}
response.Close();
}
catch (Exception exc)
{
result = "ERROR : " + exc.ToString();
}
Response.Write( "<br>result=[" + result + "]");
// extract accessToken
string accessToken = "";
int equalsAt = result.IndexOf( "=");
if( equalsAt >= 0 && result.Length > equalsAt) accessToken = (result.Substring( equalsAt + 1)).Trim();
Response.Write( "<br>accessToken=[" + accessToken + "]");
ourAccessToken = accessToken;
}
// -----------------------
private void getMe()
{
string result = "unknown";
try
{
string thisURL = "https://graph.facebook.com/me?access_token=" + Server.UrlEncode(ourAccessToken);
Response.Write("<br>thisURL=" + thisURL);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create( thisURL);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpStatusCode rc = response.StatusCode;
if( rc == HttpStatusCode.OK)
{
StreamReader Sreader = new StreamReader( response.GetResponseStream());
result = Sreader.ReadToEnd();
Sreader.Close();
}
response.Close();
}
catch (Exception ex)
{
Response.Write("<br>getMe Exc: " + ex.Message.ToString() + "<br>");
}
Response.Write("<br>getMe result = " + result + "<br><br>");
}
Thanks
Right settings in App-Dashboard? If you active "Native/Desktop" you can not send API-Calls with this method, see:
https://developers.facebook.com/docs/facebook-login/access-tokens?locale=en_US#apptokens
After a lot of trial and error, I conclude that an App Access Token is not relevant, and that the ClientID and ClientSecret should be used directly. I want my App to generate a set of photographs of registered users. Because the server is making the call, there is no meaning to "me". A set of data can be obtained by preparing a batch process:
string p1 = "access_token=" + Server.UrlEncode(ourClientID + "|" + ourClientSecret);
string p2 = "&batch=" +
Server.UrlEncode( " [ { \"method\": \"get\", \"relative_url\": \"" + chrisFBID + "?fields=name,picture.type(square)\" }, " +
" { \"method\": \"get\", \"relative_url\": \"" + johnFBID + "?fields=name,picture.type(large)\" }, " +
" { \"method\": \"get\", \"relative_url\": \"" + stephFBID + "?fields=name,picture.type(large)\" } ]");
string responseData = "";
try
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("https://graph.facebook.com/");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
byte[] bytedata = Encoding.UTF8.GetBytes(p1 + p2);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse httpWebResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = httpWebResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8);
responseData = reader.ReadToEnd();
}
catch (Exception ex)
{
Response.Write(ex.Message.ToString() + "<br>");
}
Response.Write("<br>" + responseData + "<br><br>");
I also conclude that the FB documentation suffers from the usual fatal flaw of documentation: it has been written by an expert and never tested on a novice user before release.
I working in project that connect to appannie.com API and get result and it is working fine in debug but when I publish it and try to test it I get this page :
and here is the code used for this page in C#:
protected void Button1_Click(object sender, EventArgs e)
{
string url = "https://api.appannie.com/v1/accounts?page_index=0";
string id="",temp="";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.UseDefaultCredentials = true;
request.Proxy = WebProxy.GetDefaultProxy();
request.Credentials = new NetworkCredential("username", "password");
request.ContentType = "Accept: application/xml";
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
request.Referer = "http://stackoverflow.com";
request.Headers.Add("Authorization", "bearer **************");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream receiveStream = response.GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
temp = readStream.ReadToEnd();
//TextArea1.InnerText = temp + "\n";
string[] id_arr = temp.Split(',');
int count = 0;
while (count != id_arr.Length)
{
if (id_arr[count].Contains("account_id"))
{
id = id_arr[count];
count = id_arr.Length;
break;
}
count++;
}
id = id.Substring(id.IndexOf("account_id") + 13);
//TextArea1.InnerText += id;
//Console.Write(readStream.ReadToEnd());
//response.Close();
response = null;
//readStream.Close();
request = null;
string date = Calendar1.SelectedDate.ToString("yyyy-MM-dd");
string url2 = "https://api.appannie.com/v1/accounts/" + id + "/sales?break_down=application+date" +
"&start_date="+date+
"&end_date="+date+
"¤cy=USD" +
"&countries=" +
"&page_index=0";
TextArea1.InnerText = url2;
request = (HttpWebRequest)WebRequest.Create(url2);
request.Proxy = WebProxy.GetDefaultProxy();
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
request.Referer = "http://stackoverflow.com";
request.Headers.Add("Authorization", "bearer **************");
response = (HttpWebResponse)request.GetResponse();
receiveStream = response.GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new StreamReader(receiveStream, Encoding.UTF8);
temp = "";
temp = readStream.ReadToEnd();
//TextArea1.InnerText = temp;
string[] id_arr2 = temp.Split(',');
int count2 = 0;
string down = "";
string update = "";
while (count2 != id_arr2.Length)
{
if (id_arr2[count2].Contains("downloads"))
{
down = id_arr2[count2];
count2 = id_arr2.Length;
break;
}
count2++;
}
count2 = 0;
while (count2 != id_arr2.Length)
{
if (id_arr2[count2].Contains("update"))
{
update = id_arr2[count2];
count2 = id_arr2.Length;
break;
}
count2++;
}
down = down.Substring(down.IndexOf("downloads") + 12);
update = update.Substring(update.IndexOf("update") + 9);
//TextArea1.InnerText = "downloads : "+down+ "----- update :" + update;
TextBox1.Text = down;
TextBox2.Text = update;
}
}
Once you publish it, one of the following is not taking effect:
Credentials
Proxy Settings.
Hence the remote api is giving back a 403. 2 ways to torubleshoot this further:
Run fiddler trace on the working request/response and compare it with the non-working request/response. Typically a good API has more details in the response body as to why it is a 403 error.. (token invalid, invalid credentials etc.)
You can also catch a WebException in code, and try to get the exception body if any. The same will also be visible in Fiddler.
<< code formatting refuses to work on my browser. please bear with unformatted code below >>
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
// breakpoint and see what this is.
string errorDetails = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
}
I am using the following code to retrieve emails from an Exchange 2003 server. All was working on Friday and now it fails.
From some investigation I have narrowed it to the targetDate variable. Seems if the date is in April it fails with a 400 back from the server. I have commented this line out and tried various dates 2012-3-29, 2012-4-1, 2012-4-10 (today) and the ones in April seem to fail.
Some kind of sick April fools joke?
The code itself is derived from this article: http://www.codeproject.com/Articles/42458/Using-Exchange-2003-with-Webdav-Send-Retrieve-Atta
public XmlDocument GetMailAll()
{
HttpWebRequest request = default(HttpWebRequest);
HttpWebResponse response = default(HttpWebResponse);
string rootUri = null;
string query = null;
byte[] bytes = null;
Stream requestStream = default(Stream);
Stream responseStream = default(Stream);
XmlDocument xmlDoc = default(XmlDocument);
xmlDoc = new XmlDocument();
try
{
DateTime targetDateTime = DateTime.Today.AddDays(-5);
String targetDate = ""+targetDateTime.Year + "-" + targetDateTime.Month + "-" + targetDateTime.Day;
rootUri = server + "/Exchange/" + alias + "/" + inbox;
query = "<?xml version=\"1.0\"?>"
+ "<D:searchrequest xmlns:D = \"DAV:\" xmlns:m=\"urn:schemas:httpmail:\">"
+ "<D:sql>SELECT \"urn:schemas:httpmail:hasattachment\", \"DAV:displayname\", "
+ "\"urn:schemas:httpmail:from\", \"urn:schemas:httpmail:subject\", "
//+ "\"urn:schemas:httpmail:htmldescription\"," //Return full body (not necessary right now)
+ "\"urn:schemas:httpmail:datereceived\", \"urn:schemas:httpmail:read\" FROM \"" + rootUri
+ "\" WHERE \"DAV:ishidden\" = false "
+ "AND \"DAV:isfolder\" = false "
//+ "AND \"urn:schemas:httpmail:read\" = false"
+ "AND \"urn:schemas:httpmail:datereceived\" >= CAST(\"" + targetDate + "T00:00:000Z\" AS 'dateTime.tz')"
+ "</D:sql></D:searchrequest>";
request = (HttpWebRequest)WebRequest.Create(rootUri);
request.Timeout = 5000;
request.Credentials = new NetworkCredential(alias, password, domain);
request.Method = "SEARCH";
request.ContentType = "text/xml";
request.Headers.Add("Translate", "F");
bytes = System.Text.Encoding.UTF8.GetBytes(query);
request.ContentLength = bytes.Length;
requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
response = (HttpWebResponse)request.GetResponse();
authCookies = new List<Cookie>();
foreach(Cookie cookie in response.Cookies)
{
authCookies.Add(cookie);
}
responseStream = response.GetResponseStream();
xmlDoc.Load(responseStream);
responseStream.Close();
}
catch (WebException ex)
{
if (ex.Response == null)
{
throw new Exception();
}
else if ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.Unauthorized)
{
throw new ExchangeCatastrophicException();
}
else
{
throw new ExchangeFailedException();
}
}
catch (Exception ex)
{
throw;
}
return xmlDoc;
}
Finally got it working. The exact targetDate to cast including the T00:00:..Z part must match the specification on http://msdn.microsoft.com/en-us/library/aa123600%28v=exchg.65%29.aspx
I now have:
DateTime targetDateTime = DateTime.Today;
string targetDate = targetDateTime.ToString("yyyy-MM-dd");
snip
+ "AND \"urn:schemas:httpmail:datereceived\" >= CAST(\"" + targetDate + "T00:00:00Z" + "\" AS 'dateTime.tz')"
Note that the seconds part is two zero's instead of three.