I have a database management class which has multiple methods to reach different endpoints on a REST API. Everything appears to be working except for this one issue. When the app is started, I am trying to reach an endpoint the exact same way I reach the other endpoints. For some reason, this one completely breaks the app and throws a NullReferenceException without any information.
I have confirmed that the client is not null, and the URL and endpoint works fine in Postman. I honestly have no idea what would be causing this exception, and the fact that it doesn't show any information about the exception just makes it worse.
private async void InitDatabase()
{
HttpResponseMessage response = await client.GetAsync("System?Guid=1");
string responseString = await response.Content.ReadAsStringAsync();
SysParams sysParams = JsonConvert.DeserializeObject<SysParams>(responseString);
}
The error occurs when the first line is executed where client.GetAsync is called.
For some reason, it started working after I had made the call without awaiting it.
Related
I have a problem loading a 3D model on an online server, the error shown is related to accessing the Forge API, locally works smoothly however when mounted on the server or a website is made marks the following error "Failed to load resource: the server responded with a status of 404 (Not Found)", then "onDocumentLoadFailure() - errorCode:7".
As I comment, what I find stranger is that, locally, it works. Attached the segment of the code where it displays the error.
function getAccessToken() {
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", '/api/forge/toke', false); //Address not found
xmlHttp.send(null);
return xmlHttp.responseText;
}
Thank you very much in advance.
Are you sure the code you're running locally and the code you've deployed are really the same?
The getAccessToken function doesn't seem to be correct, for several reasons:
First of all, there seems to be a typo in the URL - shouldn't it be /api/forge/token instead of /api/forge/toke?
More importantly, the HTTP request is asynchronous, meaning that it cannot return the response immediately after calling xmlHttp.send(). You can find more details about the usage of XMLHttpRequest in https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest.
And finally, assuming that the function is passed to Autodesk.Viewing.Initializer options, it should return the token using a callback parameter passed to it (as shown in https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/viewer_basics/initialization/#example).
With that, your getAccessToken should probably look more like this (using the more modern fetch and async/await):
async function getAccessToken(callback) {
const resp = await fetch('/api/forge/token');
const json = await resp.json();
callback(json.access_token, json.expires_in);
}
I've already found the issue. When I make the deploy I have to change the url where the request is made for the public or the name of the domain. For example: mywebsite.com/aplication-name/api/forge/token.
So I'm wracking my brain here. I have a Blazor Server App that I've created, and to it I've added a few ApiControllers. I am getting what seems to me to be strange errors, only with the production environment. For some reason the Request.Body is being disposed before I ever get to read it. I've tried reading with a StreamReader, copying into a new MemoryStream, what's weird is, it will work for maybe a dozen requests, then stops working and starts throwing either "Reading not allowed after stream is completed" or "IFeatureCollection has been disposed" errors. I can get it to work flawlessly in debug mode with IIS Express in VS. But it will not work consistently on IIS server. Oddly enough, it WILL work consistently when calls are sent with Postman. Just really odd. So basically what I have as an example is, an ApiController, ProfileController, and it just has 1 POST method
[HttpPost]
public async void Post()
{
String bodyContent = String.Empty;
using(StreamReader rdr = new StreamReader(Request.Body))
{
bodyContent = await rdr.ReadToEndAsync();
}
// use body content xml, generate response xml
String responseXML = "ResponseText";
Response.ContentType = "application/xml";
Response.WriteAsync(responseXML);
}
So I get errors some times when reading the request stream above, sometimes that works then I get an error that the Response has been disposed when I try to set ContentType
Is there something about Blazor that is consuming the Request/Response streams ahead of the API routing? This just really baffles me.
// public async void Post()
public async Task Post()
async void methods are not awaitable, the aspnet framework has no way of knowing that your action is still running and returns the response immediately.
what seems to me to be strange errors
Yes, it can accidentally succeed. Threading and asynchrony errors can be very undeterministic.
public async Task<E.Translations> LoadTranslations(int Id)
{
using (HttpClient client = new HttpClient())
{
E.Translations Translations = new E.Translations();
Translations = await client.GetJsonAsync<E.Translations>(Config.GetEndpointURI($"{TRANSLATION}{Id}")).ConfigureAwait(true);
return Translations;
}
}
When using the pattern above to load JSON data into a class, in this case Translations, the method works as expected when a set of data is received with an HTTP 200 OK.
However, when an HTTP response of 204, 'No Content', is returned from the API the process appears to proceed no further with no examinable value of the class to be populated.
I've attempted examining the class for null and also tried wrapping a try/catch block around the GetJsonAsync part of the method to no avail. The process seems to halt at the GetJsonAsync call and with debugging being rather thin on the ground with Blazor it's not easy to determine what's actually happening at this point.
What I'd ideally like to accomplish would be to test the class to be populated for null or any other property value but this doesn't seem possible at the moment?
I am making some calls to an api that syncs and saves appointments to/from my application and mail agenda which is most commonly Outlook mails. The calls to the api are made from a web application and it is working fine for some time but then immediately after a few hours, the calls are failed. This continues for some time and starts to work again after some time.
The DefaultConnectionLimit was set to 100 in the beginning and during this scenario, the process stopped working after some time (Say 30 mins to 1 hour). Then DefaultConnectionLimit was set to 20 and in this case, it worked fine for 3-4 hours and stopped working after that. I don't know if this is the actual cause but just mentioning.
The code where the call to the api is made from the web application is mentioned below :
public bool SyncNewAppToExch(string encryptedAppSyncDetails)
{
try
{
string result = string.Empty;
JArray paramList = new JArray();
paramList.Add(encryptedAppSyncDetails);
var emailApiUrl = ConfigurationManager.AppSettings["emailApiUrl"].ToString();
Uri baseAddress = new Uri(emailApiUrl);
var url = "/api/EmailProcess/ManualSaveAppointments";
HttpClient client = new HttpClient();
client.BaseAddress = baseAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Task.Run(() => client.PostAsJsonAsync(url, paramList)).Wait(5000);
var responseMessage = true;
if (responseMessage)
return true;
else
return false;
}
catch (Exception ex)
{
return false;
}
}
The exception that follows the api call failure reads :
Exception : System.AggregateException: One or more errors occurred. System.Threading.Tasks.TaskCanceledException: A task was canceled. --- End of inner exception stack trace --- at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task1.get_Result()
If you are making a new HttpClient object each time you want to make a call, you are not using it appropriately. HttpClient may continue to use sockets even if it is no longer being used and this will likely cause socket exhaustion under load. You can see more on this topic here
You should create a single instance and reuse it. If you are using .Net core it would be a better idea to use the HttpClientFactory.
In addition, using Task.Run to call an async method is not wise. You are setting yourself up for a deadlock. It would be much better to mark your method as async and await, if possible. Since you are effectively doing fire and forget, the way you have done this if your App Domain shuts down this work will be lost.
If you need to do this, you should at least consider registering your task as such:
HostingEnvironment.QueueBackgroundWorkItem(ct => SendMailAsync(user.Email));
The short answer is that it is difficult to say what your issue is, it could be one of several problems.
Strange one here, code calls the method, and the method grabacat is executed on the server (I debug it and step through right to the end). The code returns to the client, but the response it received was 500 Internal Server Error with the above message. So it's saying it couldn't find the web API method that it just called successfully.
using (var response = await client.PostAsXmlAsync("cats/grabacat", mycatprefs))
{
if (response.IsSuccessStatusCode) // 500 cats/grabacat not found
Controller code:
[Route("~/api/cats/grabacat")]
[HttpPost]
public async Task GrabACat()
{
}
After debugging, if I change it to public async Task<SomeObject> GrabACat() then it works OK. This lets me return an object back to the client. However I don't want to return anything back; I want it to be equivelent to calling a void method. It will examine the status code to determine if it was successful.
I have got it working by changing GrabACat to Task and returning new object(); but I am not sure why this is required. It seems crude to return an empty object just to get it to work.
Any ideas?
The WebAPI method has a Route attribute like this:
[Route("~/api/cats/grabacat")]
Which means the URL is wrong in the POST request - you are missing the /api prefix:
using (var response = await client.PostAsXmlAsync("api/cats/grabacat", mycatprefs))
//snip