Xamarin IOS Notification HTTP Post failing - ios

I have a Xamarin IOS app that uses remote notifications with actions. When an action button is pressed, I want to post a message back to the server to record the response. This is mostly working. If the app is active it always works. If the app is in the background then I am sometimes getting the following exception:
System.Net.Http.HttpRequestException: The network connection was lost. ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x2815e27c0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={NSErrorPeerAddressKey={length = 16, capacity = 16, bytes = 0x100201bb0d42d4cd0000000000000000}, _kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <8A9B9110-D44C-46F5-B67E-B11231D82319>.<18>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <8A9B9110-D44C-46F5-B67E-B11231D82319>.<18>"
), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://callservice-v2.azurewebsites.net/api/callaction, NSErrorFailingURLKey=https://callservice-v2.azurewebsites.net/api/callaction, _kCFStreamErrorDomainKey=4}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x105b568a0 + 0x009a3> in :0
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x105a960c0 + 0x005f4> in <692b89da4aac4c12a3ac3af90678ac25#21125a282fd7860e37414196dba0c548>:0
at Dialer.Models.HttpDataServerClient.PostAsync (System.String api, System.Object message) <0x105f01a70 + 0x0047b> in <8e7629d69d3341bfa512d35c83fa84e0#21125a282fd7860e37414196dba0c548>:0
I have a UNUserNotificationCenterDelegate that has the following method:
public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
try
{
_logger.TraceInfo($"DidReceiveNotificationReponse entered");
var userInfo = response.Notification.Request.Content.UserInfo;
var token = GetUserInfoItem(userInfo, "CallToken");
var subscriberPhoneNumber = GetUserInfoItem(userInfo, "SubscriberPhoneNumber");
var clientCallingNumber = GetUserInfoItem(userInfo, "ClientCallingNumber");
var clientDialedNumber = GetUserInfoItem(userInfo, "ClientDialedNumber");
_logger.TraceInfo($"Notification received, action: {response.ActionIdentifier}, token: {token}, phone #: {subscriberPhoneNumber}");
// Take action based on Action ID
switch (response.ActionIdentifier)
{
case "accept-call":
_callActionsHandler.SendAction(token, subscriberPhoneNumber, CallActions.Accept);
break;
case "send-to-voice-mail":
_callActionsHandler.SendAction(token, subscriberPhoneNumber, CallActions.VoiceMail);
break;
}
// Save the incoming call in the call history
_callHistoryAccess.AddCallToHistory(
new CallHistoryInstance()
{
CallerIdNumber = clientDialedNumber,
CallTime = DateTime.UtcNow,
CustomerPhoneNumber = clientCallingNumber,
Type = CallHistoryInstance.CallType.Inbound
});
}
catch (Exception ex)
{
_logger.TraceException($"An exception occurred while processing the notification", ex);
}
// Inform caller it has been handled
completionHandler();
}
The important thing here is the _callActionsHandler.SendAction call. That code is here:
public void SendAction(string callToken, string subscriberPhoneNumber, CallActions action)
{
Task.Run(async () =>
{
await SendActionAsync(new CallActionMessage(subscriberPhoneNumber, action, callToken));
});
}
private async Task SendActionAsync(CallActionMessage msg)
{
_logger.TraceInfo($"Registering call action for {msg.CallToken} to {msg.CallAction}");
var result = await _client.PostAsync(Constants.CallActionsApi, msg);
if (result != 200)
{
throw new CallActionsException($"HTTP status {result}");
}
}
This code has a wrapper around HttpClient. The PostAsync method is here:
public async Task<int> PostAsync(string api, object message)
{
var apiUrl = Constants.DefaultAppApi + api;
var contentText = JsonConvert.SerializeObject(message);
var content = new StringContent(contentText, Encoding.UTF8, "application/json");
var backOff = 10;
var retryCount = 5;
HttpResponseMessage response = null;
for (var attempt = 1; attempt <= retryCount; attempt++)
{
_logger.TraceInfo($"DataServerClient Post message: {message.GetType().Name}, attempt = {attempt}");
try
{
response = await _client.PostAsync(apiUrl, content);
}
catch (Exception ex)
{
if (attempt == retryCount)
_logger.TraceException($"DataServerClient Post failed", ex);
}
if (response != null && response.IsSuccessStatusCode)
{
_logger.TraceInfo($"DataServerClient post was successful at retry count: {attempt}");
break;
}
backOff *= 2;
await Task.Delay(backOff);
}
return (int)response.StatusCode;
}
I suspected an issue with the await and possibly needing a ConfigureAwait(). I have experimented with both ConfigureAwait(true) and ConfigureAwait(false) with no success. The results are very similar.
I am at a loss right now for why this is failing. Can anyone provide some information here why this is failing? Or, does anyone have code that does an HTTP post in response to a notification action?

Related

Consuming a Web API in ASP.NET MVC using HttpClient. The response message is not what is sent back to the client from the web api

To consume a Web API in ASP.NET MVC server side I am using 'HttpClient'. HttpClient sends a request to the Web API and receives a response. Then I convert the response data that came from the Web API to a model and then render it into a view.
The problem is when there is an error in the web api, my client is not receiving the custom error message that was sent.
The web api sends a status code = 400 and a ReasonPhrase with my custom message, but when it gets to the client, it is a status code = 500 and the ReasonPhrase = 'Internal Server error'.
Why?
Web api code - the WebApi2Controller method called by the client which calls a data access layer then sends result back to client:
[HttpPost]
[Route("getbloggersinfo/{argsData}/")]
public IHttpActionResult GetBloggersInfo(ArgsToPassToApi argsToPassToApi)
{
IHttpActionResult httpActionResult;
HttpResponseMessage httpResponseMessage;
try
{
BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();
bloggerInfoResults = dataAccessLayer.GetBloggersInfo(argsToPassToApi.UserName, argsToPassToApi.IpAddress);
httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, bloggerInfoResults);
}
catch (Exception ex)
{
httpResponseMessage = Request.CreateResponse(HttpStatusCode.BadRequest);
httpResponseMessage.ReasonPhrase = ex.Message;
}
httpActionResult = ResponseMessage(httpResponseMessage);
return httpActionResult;
}
The web api code - the data access layer method called by the WebApi2Controller:
public BloggerInfoResults GetBloggersInfo(string userName, string ipAddress)
{
string userFriendlyMessage = "Unable to get the Blogger's info. We have been notified and are working to resolve this. Please do not continue.";
BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();
SqlDataReader bloggerInfoDataReader = null;
try
{
dbFunc.OpenDB();
SqlCommand cmd = new SqlCommand("dbo.GetBloggersInfo", dbFunc.objConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#a_UserName", userName);
cmd.Parameters.AddWithValue("#a_IpAddress", ipAddress);
bloggerInfoDataReader = cmd.ExecuteReader();
while (bloggerInfoDataReader.Read())
{
bloggerInfoResults.UserId = Convert.ToInt32(bloggerInfoDataReader["UserId"]);
bloggerInfoResults.UserName = bloggerInfoDataReader["UserName"].ToString();
bloggerInfoResults.HasProfileSwitch = Convert.ToBoolean(bloggerInfoDataReader["HasProfileSwitch"]);
}
return bloggerInfoResults;
}
catch (SqlException sqlex)
{
if (sqlex.Message.Contains("Critical"))
{
// A "critical" error coming from the stored procedure.
currentDateTime = DateTime.Now;
sendAlertEmailResult = SendAlertEmailToStaff(currentDateTime, userName, ipAddress);
if (sendAlertEmailResult == "")
{
// The alert email was sent successfully.
// Throw - for setting the UI. Send a user friendly message.
throw new Exception(userFriendlyMessage);
}
else
{
// Not sent successfully. I have no choice but to send the verbose message as it was NOT stored in the error log and I will need to see it
// when debugging.
// Throw - for setting the UI.
throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Sending an alert email for the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + sendAlertEmailResult);
}
}
else
{
// Not coming from the stored procedure. Like if the stored procedure above was not named properly, does not exist, parameter missing, etc.
errorMessage = "Sql Exception Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Error: " + sqlex.Message;
// Log the error and send an alert email.
currentDateTime = DateTime.Now;
processErrorLogAndSendAlertEmailResult = ProcessErrorLogAndSendAlertEmail(currentDateTime, userName, errorMessage, additionalInfoForLog, ipAddress);
if (processErrorLogAndSendAlertEmailResult != "")
{
// Throw - for setting the UI.
throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Logging the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + processErrorLogAndSendAlertEmailResult);
}
else
{
// Throw - for setting the UI. Send a user friendly message.
throw new Exception(userFriendlyMessage);
}
}
}
catch (Exception ex)
{
errorMessage = "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Error: " + ex.Message;
// Log the error and send an alert email.
currentDateTime = DateTime.Now;
processErrorLogAndSendAlertEmailResult = ProcessErrorLogAndSendAlertEmail(currentDateTime, userName, errorMessage, additionalInfoForLog, ipAddress);
if (processErrorLogAndSendAlertEmailResult != "")
{
// Throw - for setting the UI.
throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Logging the initial error: " + ex.Message + ". Now getting this error: " + processErrorLogAndSendAlertEmailResult);
}
else
{
// Throw - for setting the UI. Send a user friendly message.
throw new Exception(userFriendlyMessage);
}
}
finally
{
if (bloggerInfoDataReader != null)
{
// Close the reader.
bloggerInfoDataReader.Close();
}
// Close the database.
dbFunc.CloseDB();
}
}
The custom message being thrown (throw new Exception (....)) from the data access layer method back to the WebApi2Controller method (my custom message):
The error being sent to the client from the WebApi2Controller (a status code = 400 and ReasonPhrase with my custom message):
The client code which calls the web api controller method using httpclient:
public async Task<BloggerInfoResults> GetBloggersInfo(string userName, string webApiUrl, string myIpAddress)
{
try
{
BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();
ArgsToPassToApi argsToPassToApi = new ArgsToPassToApi();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(webApiUrl);
argsToPassToApi.UserName = userName;
argsToPassToApi.IpAddress = myIpAddress;
string restOfUrl = "/api/profileandblog/getbloggersinfo/" + argsToPassToApi + "/";
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string payLoad = JsonConvert.SerializeObject(argsToPassToApi);
HttpContent argsData = new StringContent(payLoad, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(restOfUrl, argsData);
if (response.IsSuccessStatusCode)
{
var entry = response.Content.ReadAsStringAsync().Result;
bloggerInfoResults = JsonConvert.DeserializeObject<BloggerInfoResults>(entry);
}
else
{
// The web api sent an error response.
bloggerInfoResults.ApiErrorMessage = "Web api error. Reason: " + response.ReasonPhrase;
}
// Return the model.
return bloggerInfoResults;
}
}
catch (Exception)
{
throw;
}
}
The error being received (a status code = 400 and the ReasonPhrase = 'Internal Server error'.):

Is there any same method in swift to read InpuStream using post http request

Is there any same method present in swift to read the input stream from HTTP request
InputStream in = address.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
This is a local server is sending two response with 207:
var http = require('http');
var express = require('express')();
var port = process.env.PORT || 3000;
var promise = new Promise(function(resolve, reject) {
const x = "geeksforgeeks";
const y = "geeksforgeeks"
if(x === y) {
console.log('resolve');
resolve();
} else {
reject();
}
});
express.post('/', function(req, res) {
console.log('send req1')
// check if network exists and user requesting is owner of it
return promise.then(() => {
// add listener to receive response from gateway and forward it
//_addGwEmitter.addGwEmitter.addEventListener(req, res, gatewayPsn);
// send the gateway trigger instructions to coco user
res.status(207).write(JSON.stringify({
status: 200,
msg: "Waiting for authorization\n",
instructionText: "devProductInfo.instructionText",
instructionImage: "devProductInfo.instructionImageURL"
}) + "\n \r End" );
// if no event is received from gateway trigger timeout after 60 seconds
res.setTimeout(6000,()=>{
console.log('send req 2');
res.status(207).write(JSON.stringify({
status: 200,
msg: "authorization done \n",
instructionText: "devProductInfo.instructionText",
instructionImage: "devProductInfo.instructionImageURL"
}));
res.end();
});
}).catch(error => {
return res.status(400).send("error.getErrorInfo()");
});
});
http.createServer(express).listen(port);
i want to read two response one by one
i have tried
uploadtask
downloadTask
dataTask
in HTTP URLSession.
I got the answer if you want to use 207 response in iOS devices then implement URL data Task with delegate and in data delegate, you will get the response data. make sure response content type is text/json

401:Authentication credentials were invalid - Invalid or expired token. code - 89

This is the code and I am recieving the error 401: Authentication Error
public class Server {
// initialize socket and input stream
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
public void tweet() throws TwitterException {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDaemonEnabled(true).setOAuthConsumerKey("......")
.setOAuthConsumerSecret("......")
.setOAuthAccessToken("......")
.setOAuthAccessTokenSecret(".....");
TwitterFactory tf = new TwitterFactory();
twitter4j.Twitter twitter = tf.getInstance();
List status = twitter.getHomeTimeline();
for (Status st : status) {
System.out.println(st.getUser().getName() + "---- Tweets----" + st.getText());
}
}
// constructor with port
public Server(int port) throws TwitterException {
// starts server and waits for a connection
try {
server = new ServerSocket(port);
System.out.println("Server started");
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted");
// takes input from the client socket
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String line = "";
// reads message from client until "Over" is sent
while (!line.equals("Over")) {
try {
line = in.readUTF();
System.out.println(line);
if (line.equalsIgnoreCase("Data")) {
tweet();
}
} catch (IOException i) {
System.out.println(i);
}
}
System.out.println("Closing connection");
// close connection
socket.close();
in.close();
} catch (IOException i) {
System.out.println(i);
}
}
public static void main(String args[]) throws TwitterException {
Server server = new Server(5000);
}
}
Please make sure that the tokens are valid.
Then, you could try enabling system proxies like so:
System.setProperty("java.net.useSystemProxies", "true");

In NServiceBus full duplex application Server could not send/reply/return message

I have created a ASP.Net Web API project and using this link. NServiceBus is integrated with web api. Here is my configuration at web api as a client.
Configure.Serialization.Xml();
Configure.Transactions.Enable();
Configure.With()
.DefineEndpointName(Constants.ClientName)
.DefaultBuilder()
.ForWebApi()
.Log4Net()
.UseTransport<Msmq>()
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start();
This is how I'm sending message to Server
var response = await Bus.Send(Constants.ServerName, request)
.Register<ResponseModel>((NServiceBus.CompletionResult completionResult) =>
{
ResponseModel responseMessage = null;
if (completionResult != null && completionResult.Messages.Length > 0)
{
var status = completionResult.Messages[0] as RequestStatus?;
if (status == RequestStatus.Successful)
{
responseMessage = TransactionManager.TransactionDictionary[request.RequestId].ResponseModel;
}
}
return responseMessage;
});
This is how I'm sending response from Server. I have commented some lines to show what I have already tried.
public void Handle(RequestModel message)
{
ProcessRequest(message).RunSynchronously();
}
private async Task ProcessRequest(RequestModel message)
{
....
ResponseModel response = new ResponseModel();
response.RequestId = message.RequestId;
response.Result = await responseMessage.Content.ReadAsStringAsync();
//Bus.Send(Util.Constants.ClientName, response);
//Bus.Reply(response);
//Bus.Reply<ResponseModel>((ResponseModel response) =>
//{
// response = Bus.CreateInstance<ResponseModel>(r =>
// {
// r.RequestId = message.RequestId;
// r.Result = responseMessage.Content.ReadAsStringAsync().Result;
// });
//});
await Bus.Send(Util.Constants.ClientName, response).Register((NServiceBus.CompletionResult completionResult) =>
{
if (completionResult != null && completionResult.Messages.Length > 0)
{
var msg = completionResult.Messages[0];
if (msg != null)
{
var status = (RequestStatus)msg;
return status;
}
}
return RequestStatus.Error;
});
....
}
From any of the above response methods ultimately all messages end up in error queue.
Previously I was getting 'Could not enlist message' error. Now it is not throwing that error. But Server could not send message to Client.
I could not get what I'm doing wrong. Please also suggest if you see any scope for improvements.
I'm not sure if TransactionScope work correctly with async/await in C#. According to this question (Get TransactionScope to work with async / await) in .NET 4.5.1 there was introduced option for TransactionScope that enable mixing it with async/await. Unfortunately NServiceBus doesn't support .NET 4.5/4.5.1 so try just remove async/await.

org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool [duplicate]

This question already has answers here:
httpclient exception "org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection"
(10 answers)
Closed 8 years ago.
I use Multi-thread to scan the different URL in the same time in java. There was the bug,if the sum of request time exceed 100,000. I have already close which i should close. Here the code from my servlet
private String proyGetHttp(String url) throws ParseException, IOException,
InterruptedException {
String content = "";
getMethod = new HttpGet(url);
HttpResponse response = null;
HttpEntity httpEntity = null;
boolean success = false;
while (!success) {
System.out.println("url:" + url + ",connect...");
try {
response = client.execute(getMethod);
httpEntity = response.getEntity();
StringBuffer sb = new StringBuffer();
if (httpEntity != null) {
BufferedReader in = null;
InputStream instream = httpEntity.getContent();
try {
in = new BufferedReader(new InputStreamReader(instream));
String lineContent = "";
while(lineContent != null){
sb.append(lineContent);
lineContent = in.readLine();
}
} catch (Exception ex)
getMethod.abort();
throw ex;
} finally {
// Closing the input stream will trigger connection release
try { instream.close(); in.close();} catch (Exception ignore) {}
}
}
content = sb.toString();
success = true;
System.out.println("connect successfully...");
} catch (Exception e) {
e.printStackTrace();
getMethod.abort();
System.out.println("connect fail, please waitting...");
Thread.sleep(sleepTime);
}finally{
getMethod.releaseConnection();
}
}
return content;
}
Here code create the default client
PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
cm.setMaxTotal(100);
DefaultHttpClient client = null;
client = new DefaultHttpClient(cm);
client.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY);
client.getParams().setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, 5000);
I have the same problem and I found the fix. This timeout is because of a connection leak. In my case, I'm using httpDelete method and not consuming the response. Instead, I'm checking the status of the response.
The fix is, the response entity need to be consumed. In order to ensure the proper release of system resources, one must close the content stream associated with the entity.
So I used EntityUtils.consumeQuietly(response.getEntity()); which ensures that the entity content is fully consumed and the content stream, if exists, is closed.

Resources