Verify application for Loader.Io testing - c#

I am trying to do some load testing with
https://loader.io/
I am currently stuck at the stage of "verifying" my localHost application to make sure I am the one controlling it.
I have added this end point:
[HttpGet("/loaderio-a65421134i3ia3d110vcv0120d1ac14b/")]
[Authorize()]
public StreamReader GetLoaderIO()
{
var file = System.IO.File.OpenText(#"C:\Users\User\Downloads\loaderio-a65421134i3ia3d110vcv0120d1ac14b.txt");
return file;
}
When I run a GET request to this URL
http://localhost:5012/loaderio-a65421134i3ia3d110vcv0120d1ac14b/
I successfully step in my end point, what do I need to return in order for the LoaderIO to be happy? Do I have to return the stream so it can be downloaded?

I can see three potential issues with your code.
First, you are targeting a localhost address instead of a deployment address (i.e. http://yourapi.com or 159.254.102.69). To fix that issue you will need to either deploy your code somewhere or open http ports from your machine.
Second the file you are trying to retrieve my not be at the same location or might not even be accessible so a simpler way would be to write the string directly (done multiple time to verify on loader.io works like a charm) like below:
[HttpGet]
[Route("loaderio-a65421134i3ia3d110vcv0120d1ac14b")]
public HttpResponseMessage GetLoaderIoVerification()
{
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent("loaderio-a65421134i3ia3d110vcv0120d1ac14b", Encoding.UTF8, "text/plain");
return response;
}
Finally, there is that Authorize attribute that will try to authenticate the loader.io request that needs to be a resource as accessible as this one: https://media4.giphy.com/media/LXONhtCmN32YU/giphy.gif In order to do so you will need to remove it.
Once those three points are corrected you will be able to verify your api for loader.io. Hope it helps.

Related

How to clean string coming from API in C#

I am using C#
in my code, I call API
This API returns a string.
But the problem is when I read the API it comes with backslashes and quotations.
So if the returned value is Black\White's colors
It becomes "\"Black\\\\White's colors\""
or empty string is "\"\""
I wonder if there is a way to parse string the in a right way.
here is my code
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string str = client.GetStringAsync(url).Result;
Like this
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string str = await client.GetStringAsync(url);
//choose this if using NewtonsoftJson
string parsedWithNewtonsoft = JsonConvert.DeserializeObject<string>(str);
//choose this if using STJ
string parsedWithSystemTextJson = JsonSerializer.Deserialize<string>(str);
Choose one of the last two lines according to your preferred installed Json parser (manage nuget packages for the project and install either newtonsoft or system.text.json)
Don't use Result; use async proper (which means you have to make your method calls async all the way up the chain). If you strive to turn all your async calls synchronous then your app will spend a lot of tine sitting around doing nothing, waiting for network io to finish, when that time could be put to doing other useful work
Also, HttpClient is not supposed to be created anew every time you want to use it. Either configure your DI with services.AddHttpClient(); passing in options as necessary or if you aren't using DI/not writing a service of your own, you can get some ideas on how to use HttpClientFactory to manufacture HttpClients for you form this question - you may even be able to configure the default request headers as part of the manufacture so you don't need to set them in code
Finally, I should point out that I think there's a chance you're doing a lot more work than you need to if your API you're using publishes a swagger document; if it does you can use a tool like AutoRest (or the "add rest client" feature of visual studio, which uses AR), NSwag, WebApiClientGen etc and tell it "here is the api I want to use" and it'll make everything you need to call the api and return c# objects; you don't need to code any of this low level stuff, pushing data around and parsing responses, yourself

Autodesk Forge Error trying to access the API online

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.

Asynchronous file upload response never makes it back to client (or takes longer than it should)

We are having an issue with our Application where we are never getting a response back to the client (Chrome in this case) from a pretty simple asynchronous file upload call. It also bogs down our server for up to 2 minutes. Below is our Controller method:
public async Task<HttpResponseMessage> Post(string id, string fileName)
{
string[] allowedAttachmentFileTypes = ConfigurationManager.AppSettings["AttachmentsSetting"].Split(',');
string extension = Path.GetExtension(fileName);
bool extensionAllowed = allowedAttachmentFileTypes.Any(allowedAttachmentFileType => allowedAttachmentFileType.ToLower().Trim() == extension.ToLower().Trim());
if (extensionAllowed)
{
var fileResult = await Request.Content.ReadAsStreamAsync();
//...do async database stuff with fileResult
return Request.CreateResponse(HttpStatusCode.OK, result);
}
else
{
//this never makes it back to client
var response = new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType)
{
Content = new StringContent(ConfigurationManager.AppSettings["AttachmentsSetting"])
};
return response;
}
}
What I am mainly concerned with at the moment is that we are testing with what would in our system be an invalid file extension so that it would go to the else clause and just return the bad response. When we put a breakpoint here, it hits our controller and eventually hits our return in the else clause, and works as expected, but in Chrome, it still shows "Pending".
Another thing is it seems to be dependent on the size of the file we send to the Controller, even though we don't really do anything with the file unless the extension is valid. An invalid file that is 26,939KB never gives us a server response. While one that is 17,432KB gave us one, although it still took a minute.
One other thing I should add: This is more inconsistent, but at times if we do have a valid file extension on a bigger file, like say the 26,939KB one, we would get "There is no longer an HttpContext available." when trying to copy the file to the file system
This ended up being a firewall issue. Nothing code related.

How to clean up existing response in webapi?

There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29

System.Net.WebClient unreasonably slow

When using the System.Net.WebClient.DownloadData() method I'm getting an unreasonably slow response time.
When fetching an url using the WebClient class in .NET it takes around 10 sec before I get a response, while the same page is fetched by my browser in under 1 sec.
And this is with data that's 0.5kB or smaller in size.
The request involves POST/GET parameters and a user agent header if perhaps that could cause problems.
I haven't (yet) tried if other ways to download data in .NET gives me the same problems, but I'm suspecting I might get similar results. (I've always had a feeling web requests in .NET are unusually slow...)
What could be the cause of this?
Edit:
I tried doing the exact thing using System.Net.HttpWebRequest instead, using the following method, and all requests finish in under 1 sec.
public static string DownloadText(string url)
var request = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
While this (old) method using System.Net.WebClient takes 15-30s for each request to finish:
public static string DownloadText(string url)
{
var client = new WebClient();
byte[] data = client.DownloadData(url);
return client.Encoding.GetString(data);
}
I had that problem with WebRequest. Try setting Proxy = null;
WebClient wc = new WebClient();
wc.Proxy = null;
By default WebClient, WebRequest try to determine what proxy to use from IE settings, sometimes it results in like 5 sec delay before the actual request is sent.
This applies to all classes that use WebRequest, including WCF services with HTTP binding.
In general you can use this static code at application startup:
WebRequest.DefaultWebProxy = null;
Download Wireshark here http://www.wireshark.org/
Capture the network packets and filter the "http" packets.
It should give you the answer right away.
There is nothing inherently slow about .NET web requests; that code should be fine. I regularly use WebClient and it works very quickly.
How big is the payload in each direction? Silly question maybe, but is it simply bandwidth limitations?
IMO the most likely thing is that your web-site has spun down, and when you hit the URL the web-site is slow to respond. This is then not the fault of the client. It is also possible that DNS is slow for some reason (in which case you could hard-code the IP into your "hosts" file), or that some proxy server in the middle is slow.
If the web-site isn't yours, it is also possible that they are detecting atypical usage and deliberately injecting a delay to annoy scrapers.
I would grab Fiddler (a free, simple web inspector) and look at the timings.
WebClient may be slow on some workstations when Automatic Proxy Settings in checked in the IE settings (Connections tab - LAN Settings).
Setting WebRequest.DefaultWebProxy = null; or client.Proxy = null didn't do anything for me, using Xamarin on iOS.
I did two things to fix this:
I wrote a downloadString function which does not use WebRequest and System.Net:
public static async Task<string> FnDownloadStringWithoutWebRequest(string url)
{
using (var client = new HttpClient())
{
//Define Headers
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
//dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(responseContent);
return responseContent;
}
Logger.DefaultLogger.LogError(LogLevel.NORMAL, "GoogleLoginManager.FnDownloadString", "error fetching string, code: " + response.StatusCode);
return "";
}
}
This is however still slow with Managed HttpClient.
So secondly, in Visual Studio Community for Mac, right click on your Project in the Solution -> Options -> set HttpClient implementation to NSUrlSession, instead of Managed.
Screenshot: Set HttpClient implementation to NSUrlSession instead of Managed
Managed is not fully integrated into iOS, doesn't support TLS 1.2, and thus does not support the ATS standards set as default in iOS9+, see here:
https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/ats
With both these changes, string downloads are always very fast (<<1s).
Without both of these changes, on every second or third try, downloadString took over a minute.
Just FYI, there's one more thing you could try, though it shouldn't be necessary anymore:
//var authgoogle = new OAuth2Authenticator(...);
//authgoogle.Completed...
if (authgoogle.IsUsingNativeUI)
{
// Step 2.1 Creating Login UI
// In order to access SFSafariViewController API the cast is neccessary
SafariServices.SFSafariViewController c = null;
c = (SafariServices.SFSafariViewController)ui_object;
PresentViewController(c, true, null);
}
else
{
PresentViewController(ui_object, true, null);
}
Though in my experience, you probably don't need the SafariController.
Another alternative (also free) to Wireshark is Microsoft Network Monitor.
What browser are you using to test?
Try using the default IE install. System.Net.WebClient uses the local IE settings, proxy etc. Maybe that has been mangled?
Another cause for extremely slow WebClient downloads is the destination media to which you are downloading. If it is a slow device like a USB key, this can massively impact download speed. To my HDD I could download at 6MB/s, to my USB key, only 700kb/s, even though I can copy files to this USB at 5MB/s from another drive. wget shows the same behavior. This is also reported here:
https://superuser.com/questions/413750/why-is-downloading-over-usb-so-slow
So if this is your scenario, an alternative solution is to download to HDD first and then copy files to the slow medium after download completes.

Categories