GetAsync and PostAsJsonAsync methods passing parameters JsonReaderException error - asp.net

I am trying to build a client side of making requests. So i do not know how i pass parameters on GetAsync method. The same problem on PostAsJsonAsync method.
Here is my code:
public static async Task<List<Users>> GetUsers(HttpClient client, Users users, string accessToken)
{
try
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync("/api/2.0/users/?id=5&name=name");
response.EnsureSuccessStatusCode();
List<Users> listUsers= await response.Content.ReadAsAsync<List<Users>>();
Console.WriteLine("Returned list.");
return listUsers;
}
catch (HttpRequestException e)
{
Console.WriteLine("{0}", e.Message);
Console.ReadLine();
throw;
}
}
When i make this request from postman i get the results that i want. The Users class has more variables than the 2 that i request.
GetAsync without parameters works fine. When i run the project i get the error "JsonReaderException: Input string '100.0' is not a valid integer"
Is there another option to pass arguments on url?

I changed the int type of that integer property to float and the problem solved.

Related

How to send success and error messages to jQuery AJAX call from a webmethod

I am calling an asp.net webform's webmethod using jQuery AJAX, from an aspx page. When the webmethod experiences an exception I am throwing an HttpResponseException exception. I am not sure what's the best way to return a success message. In a Web API, I would have returned a ApiController.Created(HttpStatusCode) or Ok(200). But I don't see such an option available on a webmethod. In the AJAX call I have to handle success and error accordingly. The following is my code:
[WebMethod()]
public async Task<IHttpActionResult> ProcessData(CustomerData customerData)
{
try
{
HttpClient client = new HttpClient();
HttpResponseMessage resp = await client.PostAsync(<data>);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
return ???;//how to send success message?
}
else
{
string reasonAndStatusCode = resp.StatusCode + "; " + resp.ReasonPhrase;
string errorMessage = "Method Name: ProcessData." +
"Did not process customer data." +
"Status Code and Reason: " +
reasonAndStatusCode;
HttpResponseMessage error = GenerateError(resp.StatusCode, errorMessage.ToString());
throw new HttpResponseException(error);
}
}
catch (Exception ex)
{
HttpResponseMessage error = GenerateError(HttpStatusCode.InternalServerError,
errorMessage.ToString());
throw new HttpResponseException(error);
}
}
You can change the response status code using HttpContext Current static object.
For example, if you want to send a 404 status code, see the code below.
HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.NotFound;

FCM throws 401 after some time for data message notification

I am sending data message notification from Java app server to the FCM rest endpoint. Everything works fine, data messages are received by the app without any issues, however after some time (without any noticeable trend) , FCM stars returning 401. I am using Apache common's HTTPClient library to make the http callss. This is the relevant code snippet
final HttpPost httpPost = new HttpPost("https://fcm.googleapis.com/v1/projects/proj1/messages:send");
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("Authorization", "Bearer "+ accessToken);
responseBody = httpclient.execute(httpPost, responseHandler);
And this snippet is for getting the access token for API authorization
static{
FileInputStream refreshToken = null;
refreshToken = new FileInputStream("C:/prj/proserviceaccoutkey.json");
googleCredentials=GoogleCredentials.fromStream(refreshToken).createScoped("https://www.googleapis.com/auth/firebase.messaging");
options = new FirebaseOptions.Builder() .setCredentials(googleCredentials).build();
}
// Gets called each time a data message needs to be sent
public static synchronized String getAccessToken()
{
if(googleCredentials.getAccessToken()==null)
try {
googleCredentials.refresh();
} catch (IOException e) {
e.printStackTrace();
}
return googleCredentials.getAccessToken().getTokenValue();
}
looks like googleCredentials.getAccessToken() will always return non-null, even when the cahce token in no longer valid, and this is why token was not getting refreshed in the code. Applied the following fix, and it's working now.
public static synchronized String getAccessToken()
{
if(googleCredentials!=null)
try {
googleCredentials.refresh();
} catch (IOException e) {
e.printStackTrace();
}
return googleCredentials.getAccessToken().getTokenValue();
}
Though, it's not really utilizing the cached token, as every time it will be refreshing the token, but my issue has been rsolved for now.

MobileServiceClient MobileServiceInvalidOperationException Response Content is null

I'm using the following code in a Xamarin Forms app:
HttpResponseMessage response = null;
try
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(register), Encoding.UTF8, "application/json");
response = await client.InvokeApiAsync("register", content, HttpMethod.Post, null, null);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
var def = new { Message = "" };
var errorMessage = JsonConvert.DeserializeAnonymousType(error, def);
return KloverResult.BuildError(true, errorMessage.Message);
}
}
catch (MobileServiceInvalidOperationException e)
{
if (e.Response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
string error = await e.Response.Content.ReadAsStringAsync();
var def = new { Message = "" };
var errorMessage = JsonConvert.DeserializeAnonymousType(error, def);
return KloverResult.BuildError(true, errorMessage.Message);
}
else
{
return KloverResult.BuildError(false, "Invalid username or password");
}
}
The issue that I'm having is when a MobileServiceInvalidOperationException is thrown as a result of a 500. When I try to read the content of the response (e.Response.Content) it's null. When I call the same API using Restlet I get the following response:
{
"Message": "Name jblogs is already taken."
}
This is what I expect to be in my error variable, however it's null.
My question is, should I be able to read the Content of the Response? If so, do I need to do some more setup on the client/server? The API being called is returning the error form a webapi using:
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Name jblogs is already taken.");
Any help would be appreciated.
A 500 response means that the server crashed. It's likely that there was no content in that case.
If your API is returning status=500, then it is doing the wrong thing. What you should be doing is returning a status in the 400 series - 409 (conflict) seems appropriate to me.
If your API is not returning status=500 deliberately, then the server crashed and you don't get content.
According to your description, I built my Mobile App application with a custom WebApi endpoint to test this issue. Based on my test, I leverage Microsoft.Azure.Mobile.Client 3.1.0 to invoke custom WebApi, I could retrieve the content by Response.Content.ReadAsStringAsync() when the response status is 409 or 500 and so on. Here are my code snippet, you could refer to them:
WebApi
[MobileAppController]
public class ValuesController : ApiController
{
public async Task<HttpResponseMessage> Get()
{
await Task.Delay(TimeSpan.FromSeconds(2));
return Request.CreateErrorResponse(HttpStatusCode.Conflict, "Name jblogs is already taken.");
}
}
Client App
try
{
MobileServiceClient client = new MobileServiceClient("https://bruce-chen-002.azurewebsites.net/");
var response = await client.InvokeApiAsync("/api/values", HttpMethod.Get, null);
}
catch (MobileServiceInvalidOperationException e)
{
if (e.Response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
string error = await e.Response.Content.ReadAsStringAsync();
}
}
Result

Web API External Bearer Unauthorized

I am trying to call the RegisterExternal method in Web API, after having retrieved a token from facebook. But I keep getting a 401 Unauthorized from my Web API. I am not sure I am correctly implementing the logic flow. My code is;
Ask for supported external login providers;
public async Task<List<ExternalLoginViewModel>> GetExternalLoginsAsync()
{
using (var client = GetNewHttpClient(false))
{
var response = await client.GetAsync("api/account/externalLogins?returnUrl=/&generateState=true");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<List<ExternalLoginViewModel>>();
}
}
From this, I am returned a facebook URL. I follow this and then enter in my facebook username and password. I return back to my app via a deep link and then try and call the RegisterExternal method in the web API like this, passing the facebook "access token" that is returned.
public async Task<bool> SendSubmitRegisterExternalAsync(RegisterExternalBindingModel ro, string accessToken)
{
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
}
I receive 'Unauthorized' every time. I do not know what is wrong. My Web API method looks like this, and the class is marked with the [Authorize] attribute.
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
...
I have found three different posts this evening of people asking this exact same question, and in all cases there are no replies, so I am not hopeful but if anyone can shed some light on this it would be great!
EDIT: I have also changed the method signature to 'allowanonymous' and still get unauthorized!
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[AllowAnonymous]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
I have sorted this by not using FacebookSessionClient and doing it via a WebBrowser control instead.
I use the URL from the first step (provided to me by the WebAPI). Then on the Navigated event from the WebBrowser control, i parse the Url for the access token;
public async void ParseUrlForAccessToken(string url)
{
string fieldName = "access_token";
int accessTokenIndex = url.IndexOf(fieldName, StringComparison.Ordinal);
if (accessTokenIndex > -1)
{
int ampersandTokenIndex = url.IndexOf("&", accessTokenIndex, StringComparison.Ordinal);
string tokenField = url.Substring(accessTokenIndex, ampersandTokenIndex - accessTokenIndex);
string token = tokenField.Substring(fieldName.Length);
token = token.Remove(0, 1);
await _dataService.SubmitLoginExternal("Test", token);
}
}
Then as shown above, I call SubmitLoginExternal, which is a call to the following code which uses the access token retrieved from the WebBrowser control Url to register the account (in this case a 'Test' account);
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
This has worked and now I have the user registered in my database.
The key was to use a WebBrowser control and not the FacebookSessionClient object or a WebBrowserTask. You cannot use a WebBrowserTask as you need to hook in to the navigated event once the page has loaded to call ParseUrlForAccessToken().

Web API: No MediaTypeFormatter is available to read an object of type 'IEnumerable`1' from content with media type 'text/plain'

I get this error in my client (an ASP.NET MVC application) from a call to my ASP.NET Web API. I checked and the Web API is returning the data alright.
No MediaTypeFormatter is available to read an object of type
'IEnumerable`1' from content with media type 'text/plain'.
I believe that I can inherit from DataContractSerializer and implement my own serializer which can attach the Content-Type HTTP header as text/xml.
But my question is: is that necessary?
Because if it was, it would mean that the default DataContractSerializer does not set this essential header. I was wondering if Microsoft could leave such an important thing out. Is there another way out?
Here's the relevant client side code:
public ActionResult Index()
{
HttpClient client = new HttpClient();
var response = client.GetAsync("http://localhost:55333/api/bookreview/index").Result;
if (response.IsSuccessStatusCode)
{
IEnumerable<BookReview> reviews = response.Content.ReadAsAsync<IEnumerable<BookReview>>().Result;
return View(reviews);
}
else
{
ModelState.AddModelError("", string.Format("Reason: {0}", response.ReasonPhrase));
return View();
}
}
And here's the server side (Web API) code:
public class BookReviewController : ApiController
{
[HttpGet]
public IEnumerable<BookReview> Index()
{
try
{
using (var context = new BookReviewEntities())
{
context.ContextOptions.ProxyCreationEnabled = false;
return context.BookReviews.Include("Book.Author");
}
}
catch (Exception ex)
{
var responseMessage = new HttpResponseMessage
{
Content = new StringContent("Couldn't retrieve the list of book reviews."),
ReasonPhrase = ex.Message.Replace('\n', ' ')
};
throw new HttpResponseException(responseMessage);
}
}
}
I believe (because I don't have time to test it now) that you need to explicitly set the Status Code on the responseMessage you are passing to HttpResponseException. Normally, HttpResponseException will set the status code for you, but because you are providing a responsemessage explicitly, it will use the status code from that. By default, `HttpResponseMessage has a status code of 200.
So what is happening is you are getting an error on the server, but still returning a 200. Which is why your client is trying to deserialize the text/plain body produced by StringContent, as if it were an IEnumerable.
You need to set
responseMessage.StatusCode = HttpStatusCode.InternalServerError
in your exception handler on the server.
How about just using ReadAsStringAsync if your WebAPI is expecting to return content in plain text?
response.Content.ReadAsStringAsync().Result;

Resources