How to hit a rest api url from asp.net MVC 5 - c#

Actually I want to hit a url(if i hit same url from browser, SMS is coming to my number but not from the code) to send sms on mobile. the same code is working for me in C# windows app but in mvc it's giving error as excption[An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.]
Sample code in MVC-5
void sendSMS(string name, string mobile)
{
try
{
string mobNumber = mobile;
string message = "Hello "+name+" your request submitted successfully.";
string apiToken = "xxxxxxxxxxx";
string smsSender = "xxxxxx";
string apiKey = "test#gmail.com";
string url = "http://somewebsite.com/Restapis/send_sms?api_key=" + apiKey + "&api_token=" + apiToken + "&sender=" + smsSender + "&receiver=" + mobNumber + "&msgtype=1&sms=" + message + "";
GetRequest(url, mobNumber);
}
catch(Exception ex){ }
}
public async static void GetRequest(string url, string mob)
{
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url))
{
using (HttpContent content = response.Content)
{
HttpContentHeaders headers = content.Headers;
if (response.ReasonPhrase == "OK") { }
}
}
}
}
Above same code is working in windows App but not in ASP.NET MVC.
Please anyone provide a hint or solution. Thanks in advance.

This is a known issue in ASP.NET.
Replace this line:
using (HttpResponseMessage response = await client.GetAsync(url))
With this:
using (HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false))
You need to use ConfigureAwait or the threads will block.
Check this post for more details.
So, according to it, ASP.NET has a specialized sync context, that only
one thread can have. And if you don’t use .ConfigureAwait(false), it
tries to restore old context, which belongs to the main thread that is
blocked by .Result, hence deadlock.

Related

Best practice for making a HTTP Post from asp.net Page_Load?

Seems like simple task, but the interwebs are flooded with different ways to approach this, so what is best practice for making a simple HTTP POST from asp.net Page_Load (I'm on .net 4.7) ?
Many resources point to the fact that HttpClient.PostAsync is the most lightweight approach.
However, the example here: https://learn.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45 - uses WebClient.
Also, both of theses approaches require setting Page Async="true" on the page - I am seeing conflicting information on whether this is actually the right approach.
Context: My page looks like it is spending a lot of time in BLOCKED_TIME during two requests that are made in Page_Load.
I suspect this is due to the way I currently make the POST:
public string makePost(string parametersToPassOn, string command)
{
HttpContent c = new StringContent(parametersToPassOn, Encoding.UTF8, "application/json");
var t = Task.Run(() => fireRESTcall(new Uri(walletProxyURL + command), c));
t.Wait();
return t.Result;
}
static async Task<String> fireRESTcall(Uri u, HttpContent c)
{
var response = string.Empty;
using (var client = new HttpClient())
{
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = u,
Content = c
};
HttpResponseMessage result = await client.SendAsync(request);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
}
return response;
}
Any help/thoughts would be greatly appreciated.
During the time your page makes an outgoing HTTP request, it can't do anything useful other than waiting for the response. See also Understanding BLOCKED_TIME in PerfView
You probably can't do anything about this delay, as you need the external API for some data, and you need to wait for it to complete in order to do something useful with that data.
So it's advisable to use async/await all the way, using RegisterAsyncTask():
void Page_Load()
{
RegisterAsyncTask(new PageAsyncTask(CallApiAsync));
Page.ExecuteRegisteredAsyncTasks();
}
async Task CallApiAsync() // calls
async Task<string> MakePost() // calls
async Task<String> FireRESTcall()
This frees up the thread to handle a new incoming request, until the outgoing request is finished and the incoming request continues on the same or another thread pool thread.
For this to work with WebForms, you do need Async="true" on your page.

WebUI hangs endlessly when sending an update request to the API [duplicate]

This question already has an answer here:
Attempting To Understand "Common" async Deadlock with ASP.NET and HttpClient()
(1 answer)
Closed 4 years ago.
I have 2 separate applications, an MVC5 UI and a Asp.net WebApi2 (not asp.net core). I can read data from the API just fine. Now I want to send data from a form in the UI to the API, so it can write it to it's database.
For internal reasons, the MVC controller receives a POST request from a form and then is supposed to update the data in the database by sending it to the API and display some form of result (error or confirmation). The API receives the data, does it's work and responds with a 200 and the desired answer ("updated").
Sadly, the UI does somehow not realize this answer and keeps on waiting forever... I have read there would be a timeout at 90 seconds, but that doesn't seem to be the case. I have to emphasize that I am a newbie, so I guess I made some weird mistake :D
The code I used worked fine from my console application, but either I messed it up or it does not work at all from WebApi? I tried setting the timeout, but it doesn't change anything :/
The last log entry is: sending update request to api...
Controller Code:
[HttpPost]
public ActionResult EditTicket(ServiceManagementTicket postedTicket)
{
if (!ModelState.IsValid)
{
// some error handling code
}
string TicketUpdateResult = updateTicket(postedTicket).Result;
if (TicketUpdateResult == "updated")
{
return View("SingleTicketView", postedTicket);
}
else
{
Log.Verbose("ticket could not be updated. The error should have been logged");
return View("Views/Pages/InternalServerError");
}
}
Task Code:
public static async Task<string> updateTicket(ServiceManagementTicket postedTicket)
{
string FinalEndpoint = "api url here"
String jsonToExport = JsonConvert.SerializeObject(postedTicket);
StringContent jsonToExportConverted =
new StringContent(jsonToExport, Encoding.UTF8, "application/json");
Log.Verbose("Trying to update ticket at: " + FinalEndpoint);
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(5);
Log.Verbose("sending update request to api...");
HttpResponseMessage response = await client.PutAsync(
FinalEndpoint,
jsonToExportConverted);
Log.Verbose("Updating the Ticket at the webapi was: " + response.ReasonPhrase);
if (response.ReasonPhrase == "updated")
{
Log.Verbose("api confirmed the update");
return response.Content.ReadAsStringAsync().Result;
}
Log.Verbose("something ent wrong :/");
return "error";
}
}
catch (Exception e)
{
// error handling
}
}
Sending the data to the api in a synchronous call would be fine as well, I just couldn't find an example that worked for me.
The lines of code below will deadlock in ASP.NET applications, never use Task.Result in an ASP.NET application.
string TicketUpdateResult = updateTicket(postedTicket).Result;
return response.Content.ReadAsStringAsync().Result;
Those lines of code should be:
string TicketUpdateResult = await updateTicket(postedTicket);
return await response.Content.ReadAsStringAsync();

HttpClient.PostAsJsonAsync never sees when the post is succeeding and responding

We are using an HttpClient to post json to a restful web service. In one instance, we are running into something that has us baffled. Using tools like postman, fiddler etc, we can post to an endpoint and see that it is working. When we do the same with HttpClient.PostAsJsonAsync, we can verify in the software we are posting to that it received the data just fine. However, our PostAsJsonAsync will always eventually time out rather than give us a response.
We have worked with the team that created the service we are consuming, plus our additional testing on our side, and we have not yet been able to truly time out that service.
Every time we do a post with HttpClient, we then can verify that the target software we post to does indeed get the data. Any time we do a post to that target software from any other tool, we always very quickly see a response with status code of 200. Something about HttpClient is failing to accept the response from this particular service. Does anyone have an idea what we can look at from here?
Here's the code (though it is so cookie cutter that I hardly feel it is needed)
public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = client.PostAsJsonAsync(useUrl, o).Result;
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return response.Content.ReadAsStringAsync().Result;
}
return "";
}
}
This:
var response = client.PostAsJsonAsync(useUrl, o).Result;
Is causing you code to deadlock. This is often the case when blocking on async API's, and that's why you're experiencing the "I don't see any response coming back" effect.
How is this causing a deadlock? The fact that you are executing this request in an environment that contains a synchronization context, perhaps one which belongs to the UI. It's executing the async request, and when the response arrives, it continues via an IO completion thread which attempts to post the continuation onto that same UI context, which is currently blocked by your .Result call.
If you want to make an HTTP request synchronously, use WebClient instead. If you want to take advantage of the async API properly, then await instead of block with .Result.
I had the same issue and this SO answer fixed it for me.
In a nutshell, you have to use the ConfigureAwait(false) extension to avoid the deadlock:
var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false);
Is there a reason why you're not following the async await pattern? You're calling an async method, but not awaiting it. You didn't say if the code calling your REST service was a Windows Forms or ASP.NET application, but that .Result is probably causing you issues.
Can you restructure your method like this:
public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
This is a slight modification to #Justin Helgerson's solution. There are 2 blocking .Result calls in your method; once you go async you should fix them both.
public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1)
{
using (var client = new HttpClient())
{
if (timeoutMinutes > 0)
{
client.Timeout = new TimeSpan(0,timeoutMinutes,0);
}
var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath;
var response = await client.PostAsJsonAsync(useUrl, o);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync();
}
return "";
}
}
Note I've also renamed the method to PostDataAsync in accordance with the TAP pattern.
System.Net.ServicePointManager.Expect100Continue = false;
That one line of code in our case fixed the problem. A developer from a different team offered that suggestion, and it works. I have yet to google it and read up on it enough to offer an explanation of what that is addressing.

WP8 Fast App Resume with Asynchronous methods

In my windows phone 8 app i am using asynchronous methods to retrieve data from server.
After implementing Fast App Resume functionality another problem rose for me. The asynchronous method that retrieves data from server throws the exception of type System.Net.WebException when it resumes.
The steps to reproduce the problem is you just hit the start button when the app is loading data by asynchronous method.
For example i have a page that loads notification of user. I called the async void GetNotifications() method that further calls below method to retrieve response string.
public async Task<string> Get(string URL)
{
var request = WebRequest.Create(new Uri(URL)) as HttpWebRequest;
if (APIHelper.APIHandshake != null)
request.Headers["Cookie"] = "ii=" + APIHelper.APIHandshake.Sid + ";";
return await httpRequest(request);
}
the implementation of httprequest method is given below.
private async Task<string> httpRequest(HttpWebRequest request)
{
string received;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory
.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream))
{
//cookieJar = request.CookieContainer;
//responseCookies = response.Cookies;
received = await sr.ReadToEndAsync();
}
}
}
return received.Replace("[{}]", "[]")
.Replace("[{},{}]", "[]")
.Replace("\"subcat_id\":\"\"", "\"subcat_id\":\"0\"");
}
The user just click the menu that opens the notification page and then press the start button of phone instantly to deactivate the app. When user will click on application tile from start menu the exception will be thrown.
Any solution? will deactivating idle mode detection work?
It would probably not be the best solution but It is possible to not cancel the async request by adding this line of code in the InitalizePhoneApplication() method on your app.xaml.cs page.
PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled;
Read more on this property here
Test it, it should fix the issue but I'm not pretending that's the best thing to do....

Async webrequest with C#?

Hi,
I have a simple ASP.NET MVC C# webpage that users can submit Title, Descirption, Tags and a link(URL). The post to the service is sent with JASON(AJAX) and works great for the most part. But sometimes the post just hangs and nothing happens when this happens it will also be vary slow to load any other page of this website.
The webmethod is real simple, first it stored the data to the database and then it uses HttpWebRequest to fetch the URL page. The fetched page is then read(header data) and in most cases it stores a image.
I suspect that the hangig is due to HttpWebRequest taking to long. The request method starts with this :
if (url != null && url.Length > 0)
{
request = (HttpWebRequest)HttpWebRequest.Create(url);
dirInfo.Create();
request.UserAgent = ConfigurationManager.AppSettings["DomainName"];
webresponse = (HttpWebResponse)request.BeginGetResponse( .GetResponse();
if (webresponse.ContentType.StartsWith("image/"))
{
using (WebClient tmpClient = new WebClient())
{
client.DownloadFile(url, postThumbnailsTemp + "\\" + fileName);
}
if (SavePostImage(postThumbnailsTemp + "\\" + fileName, postId))
return true;
}
if (webresponse.ContentType.StartsWith("text/html") || webresponse.ContentType.StartsWith("application/xhtml"))
{
var resultStream = webresponse.GetResponseStream();
doc.Load(resultStream);
The question is if it might be better to use a async call here? Like the HttpWebRequest.BeginGetResponse? This would mean that the user might be redirected to the post page before the URL webpage is read and stored.
If you are using web api for example, you can change your api controller action to be async.
If you do so, the response will NOT return to the client until the task has completed but it will also not block other client/threads!
Example
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody]MyObject obj)
Within the method you should also use the async await pattern to create your custom request...
Have some articles for further information of how to build async web apis
http://blogs.msdn.com/b/webdev/archive/2013/09/18/scaffolding-asynchronous-mvc-and-web-api-controllers-for-entity-framework-6.aspx
http://www.dotnetcurry.com/showarticle.aspx?ID=948
and maybe watch this video

Categories

Resources