GetStringAsync method not responding - json

I'm trying to get some custom columns values (longitude,latitude) from ASPNetUsers Table from the DB , When I send a Get request throw browser I get a 200 ok with the requested json .. but when I try to use GetStringAsync to deserialize the response in my xamarin app I don't get any response .
In AccountController class
// POST api/Account/GetUserPostion
[Route("GetUserPostion")]
public LocationDataToPostAsync GetUserPostion()
{
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new ApplicationUserManager(store);
LocationDataToPostAsync locationData = new LocationDataToPostAsync();
var model = manager.FindById(User.Identity.GetUserId());
locationData.UserId = User.Identity.GetUserId();
if (model.Longitude != null) locationData.Longitude = (double) model.Longitude;
if (model.Latitude != null) locationData.Latitude = (double) model.Latitude;
return locationData;
}
In ApiService class in xamarin forms app
public async Task<LocationDataToPostAsync> GetUserLocationAsync(string accessToken)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await client.GetStringAsync("http://10.0.2.2:45455/api/Account/GetUserPostion");
var location = JsonConvert.DeserializeObject<LocationDataToPostAsync>(json);
return location;
}

It is unclear from your code if the Task is awaited or you are calling .Result or .GetAwaiter().GetResult() on the Task. However, as we found out in the comments adding .ConfigureAwait(false) fixed your issue.
This indicates that the code cannot return to the context it came from, so adding .ConfigureAwait(false) the code doesn't return to the context.
In your case the context is probably the UI thread and when it tries to return the UI thread is blocked.
The most likely scenario why the UI Thread is block is because you called your Task in a wrong manner. If you call it with .Result on the UI thread you are synchronously blocking the UI thread, hence anything that tries to return to the UI thread, will deadlock, since you are blocking that.
The easy fix here is to just add .ConfigureAwait(false) in your code. The better solution would be not to block the UI thread by awaiting the Task.

Related

Exception handling using Hellang middleware in .Net Core MVC

I've used Hellang Middleware for exception handling as the global exception handling mechanism in my MVC application.
I've added the following code in the ConfigureServices method in Startup.cs:
services.AddProblemDetails(opts =>
{
// Control when an exception is included
opts.IncludeExceptionDetails = (ctx, ex) =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
opts.ShouldLogUnhandledException = (ctx, e, d) =>
{
return (d.Status.HasValue && d.Status.Value >= 500);
};
});
Also I've added UseProblemDetails() in Configure method.
However I came to know that if am using UseProblemDetails(), then UseExceptionHandler() won't work!
Hence I'am not able to figure out a method for navigating user to a common error view page.
Is there any way to redirect users to an error page while sticking on to Hellang Middleware for exception handling and logging ?
See the answer here:
https://stackoverflow.com/a/40153711/90287
You have to distinguish between the type of request, if it's an API request or a UI request to determine if a problem+details JSON should be returned or if a web page should be returned, respectively.
This is what I do near the top of the Configure method of Startup.cs:
app.UseWhen(context => context.IsApiRequest(), branch =>
{
branch.UseProblemDetails();
});
app.UseWhen(context => !context.IsApiRequest(), branch =>
{
branch.UseExceptionHandler("/Home/Error");
});
You can define your own custom HttpContext extension method:
public static class HttpContextExtensions
{
public static bool IsApiRequest(this HttpContext context)
{
return context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)
|| (context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"); // AJAX request
}
}
I had a similar problem. I solved it like the following. In this example logging a custom business fault exception:
services.AddProblemDetails(setup =>
{
setup.Map<FaultException<BusinessFault>>((context, exception) =>
{
// resolve logger
var logger = context.RequestServices.GetRequiredService<ILogger<ProblemDetails>>();
// log exception to Seq
logger.LogError(exception, "{#Exception} occurred.", exception);
// return the problem details map
return new ProblemDetails
{
Title = exception.Message,
Detail = exception.Detail.FaultMessage,
Status = exception.Detail.FaultType.ToHttpStatus(),
Type = exception.Detail.FaultType.ToString(),
Instance = exception.Detail.FaultReference
};
});
});
This is not exactly the answer to your question, but I had a similar issue in a Web API application regarding using ExceptionHandler middleware and Hellang ProblemDetails Middleware and I also came to realize I could't use them both because both change the response in their own way and affect one another.
Based on the documentation here you can use one of the configuration options of the ProblemDetails package to excute code before changing response and there you can log all the information you need.
services.AddProblemDetails(options =>
{
options.IncludeExceptionDetails = (context, ex) =>
{
var environment = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
return environment.IsDevelopment();
};
options.Map<IdentityException>(exception => new ProblemDetails()
{
Title = exception.Title,
Detail = exception.Detail,
Status = StatusCodes.Status500InternalServerError,
Type = exception.Type,
Instance = exception.ToString()
});
options.OnBeforeWriteDetails = (ctx, pr) =>
{
//here you can do the logging
logger.LogError("Exception Occurred!!!!");
logger.LogError(pr.Detail);
logger.LogError(pr.Instance);
};
});
Here, I use a custom exception with extra fields that are needed for problem details object in response, and I use the Instance field to hold the exception and log it.

Razor Component Call to HttpClient Not responding

I'm trying to call an injected HttpClient during operations within a Razor Component. When I do so during OnInitialized, the return is as expected. When I do so on an event like an input change, the client call doesn't respond.
I'm using a mix of MVC Controllers/Views with Razor Components in .Net Core 3.1.
Startup.cs
services.AddControllersWithViews()...
services.AddRazorPages()...
services.AddHttpClient<IJiraService, JiraService>("jira", c =>
{
c.BaseAddress = new Uri(Configuration.GetSection("ApplicationSettings:Jira:Url").Value);
var auth =
$"{Configuration.GetSection("ApplicationSettings:Jira:UserName").Value}:{Configuration.GetSection("ApplicationSettings:Jira:Password").Value}";
var authHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth));
c.DefaultRequestHeaders.AddAuthorization("Basic", authHeaderValue);
c.Timeout = TimeSpan.FromSeconds(20);
c.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue
{
NoCache = true
};
});
ChildComponent.razor
#inject IJiraService JiraService
#code {
public int SelectedReleaseId
{
get => ReleaseModel.SelectedReleaseId;
set
{
ReleaseModel.SelectedReleaseId = value;
ReleaseChanged().Wait();
}
}
}
#functions
{
private async Task ReleaseChanged()
{
if (ReleaseModel.SelectedReleaseId > 0)
{
var url = "...";
await JiraService.GetResponseAsync(url);
}
}
JiraService.cs
public async Task<string> GetResponseAsync(string url)
{
var resp = await httpClient.GetAsync(url); // <--- this is the call that never returns when invoked from an input control event
var respContentString = await resp.Content.ReadAsStringAsync();
if (resp.StatusCode != HttpStatusCode.OK)
{
throw new HttpOperationException(
$"Invalid response from Jira service: {resp.StatusCode}: {respContentString}");
}
return respContentString;
}
There's actually a bit of service classing in between, but this is the jist.
I've abstracted the call up to a parent component and implemented EventCallbacks all with the same result. The underlying call in the JiraService gets hit and i see a breakpoint stop on the await httpClient.GetAsync(url); but then execution just goes into the ether. There's not even an exception thrown or timeout.
It all seems so obvious now. The problem was a deadlock. This old post helped me realize that my property based #bind attribute was synchronously calling into an async/await graph. I refactored this into an #onchange function that enabled appropriate async/await behavior through the call stack and viola, await httpClient.GetAsync() behaved just like it should.
A little annoyed at the #bind behavior that takes the onchange event functionality in addition to the property value.

POST json to external API in .NET Core - Unsupported Media Type

I'm trying to code a middleman API that logs calls and other details from internal users to an external API.
When I try to POST to the external API from my Controller, I get 415 unsupported media type.
I set up my client in the controller constructor like this:
client.BaseAddress = new Uri("https://restapi.***.com/customers/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-AppSecretToken", Auth.APPSECRETTOKEN);
client.DefaultRequestHeaders.Add("X-AgreementGrantToken", Auth.AGREEMENTGRANTTOKEN);
My POST method looks like this:
var json = JsonConvert.SerializeObject(customer, Formatting.Indented);
using (var stringContent = new StringContent(json))
{
stringContent.Headers.ContentType.CharSet = "";
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.ID }, customer);
I've been looking around and found a lot of comments telling me to use Stringcontent, but I also found a couple of responses saying ByteArrayContent - none of them work.
Can anyone help me?
EDIT: When I run the code with breakpoints it seems like some of the properties in the incoming customer object are set even though I didn't set them in my Postman call.
Example; the external API returns a customernumber when I give it the 5 properties that are obligatory. But when I call my internal API from Postman, sending only those 5 obligatory properties, it autopopulates the customernumber with a 0.
Could this be the source of the error? and how do I tell .net core to not autopopulate the customernumber?
EDIT2: I changed my stringContent to include encoding and used a different overload, so the using line now says
using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
And I removed
stringContent.Headers.ContentType.Charset = "";
to reflect the fact that I tried setting the encoding.
The return code changed from 415 to 400 Bad Request when I changed that.
EDIT3:
Tried NOT serializing with Json.Net, and instead used JObjects and Jproperties;
public async Task<ActionResult<Customer>> PostCustomer([FromBody]Customer customer)
{
JObject payload = new JObject(
new JProperty("currency", customer.Currency),
new JProperty("name", customer.Name),
new JProperty("customergroup",
new JObject(new JProperty("customergroupNumber",
customer.CustomerGroup.CustomerGroupNumber)
)),
new JProperty("paymentTerms",
new JObject(new JProperty("paymentTermsNumber",
customer.PaymentTerms.PaymentTermsNumber)
)),
new JProperty("vatZone",
new JObject(new JProperty("vatZoneNumber",
customer.VatZone.VatZoneNumber)
))
);
using (var stringContent = new StringContent(payload.ToString(), Encoding.UTF8, "application/json"))
{
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.CustomerNumber }, customer);
}
Still 400 Bad Request
This is a case of capitalizing - simple really.
My POST request JSON had an object named customergroup - changed it to customerGroup, and it worked.

Reading the content of HTTP Stream before the Content stream is Complete Windows Phone 8

I am trying to get a reference to a response stream before its complete in windows phone 8.
In other .Net platforms you can do
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(myUri);
WebResponse subscribeWebResponse = null;
Stream subscribeStream = null;
subscribeWebResponse = httpRequest.GetResponse();
subscribeStream = subscribeWebResponse.GetResponseStream();
For the purpose of creating Portable class libraries I've used the HttpClientLibrary from nuget.
This Adds ref to extensions assembly Microsoft.Net.Http
this allows me to return the async request at the time the headers have been read instead of waiting for the content transfer to be complete with
var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead);
The problem I'm having is that in windows phone 8 it doesn't work correctly, and still awaits the completion of the content stream to return.
Additionally
await httpWebRequest.BeginGetResponse(callback, request)
has the same behavior as these async methods are actually waiting for the completion of the web's response to continue execution.
So, is there any way to achieve the returning the response/stream at the point that i have received the response headers without Microsoft.Http.Net package?
Even if it has to be a Windows Phone 8 Platform Specific Solution?
Possibly an extension of HttpWebRequest?
From what I can tell, ResponseHeadersRead works on the WP8 emulator as it does on the desktop.
I installed the Win8 SDK. Created a windows phone app. I added this code to the MainPage ctor. This demonstrates a very rudimentary long polling example.
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://oak:1001/longpolling")
};
client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, new CancellationToken())
.ContinueWith((t) =>
{
var response = t.Result;
response.Content.ReadAsStreamAsync()
.ContinueWith(s =>
{
var st = s.Result;
while (true)
{
var message= ReadNextMessage(st);
}
});
});
}
private static string ReadNextMessage(Stream stream)
{
int chr = 0;
string output = "";
while (chr != 10)
{
chr = stream.ReadByte();
output += Convert.ToChar(chr);
}
return output;
}
On my host dev machine I have a web api with a controller that looks like this...
public class LongPollingController : ApiController
{
public HttpResponseMessage Get()
{
Thread.Sleep(2000);
var content = new PushStreamContent( (s,c,t) =>
{
int i = 0;
while (true)
{
try
{
var message = String.Format("The current count is {0} " + Environment.NewLine, i++);
var buffer = Encoding.UTF8.GetBytes(message);
s.Write(buffer, 0, buffer.Length);
}
catch (IOException exception)
{
s.Close();
return;
}
Thread.Sleep(1000);
}
});
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = content
};
}
}
So here's the deal. I would say that what you want to do is not possible, due to platform limitations... But SignalR has a WP client and is able to manage it. So it seems to me you have two options:
1) Dig into the SignalR source code to see how they do it (I'm on my phone right now so I can't provide a link).
UPDATE: Here is the link. They do some pretty neat tricks, like setting the Timeout to -1 for long-running clients. I think you should definitely use the techniques here.
OR
2) You can move whatever you're doing over to SignalR, which would gain the benefit of having a robust infrastructure and being cross-platform compatible.
HTH

Getting an empty Facebook news feed response using Facebook C# SDK

I am using the Facebook C# SDK in my Silverlight 4 browser app to perform some requests to the Facebook Graph API. I followed the example in the SDK documentation to request the user's information (using the asynchronous method to make it work on Silverlight):
var fb = new FacebookClient(accessToken);
fb.GetAsync("/me");
fb.GetCompleted += (o, ea) =>
{
var result = (JsonObject)ea.GetResultData();
var name = (string)result["name"];
};
This way I get the JsonObject without any problem and I can read all data, but when I make request to "me/feed" or "me/home" instead of "/me":
fb.GetAsync("/me/home");
fb.GetCompleted += (o, ea) =>
{
var result = (JsonObject)ea.GetResultData();
var data = (JsonArray) result["data"];
foreach (JsonObject post in data)
{
id = (string)post["id"];
}
};
then the JsonObject is empty and I get a exception when trying to access its elements. I successfully managed to POST a message to "me/feed", but why do I receive an empty response when making a GET request? I have set the access token in the FacebookClient I'm using to make the calls, is there something else that I'm missing?
Thanks!