Passing Multiple Get Parameters to WebApi - asp.net-core-mvc

I am working on a asp.net core 2.2 application. I want to pass two parameters(token and refresh token) to the asp.net core 2.2 web api to retrieve new token. When I am passing the values, i am getting an error
An unhandled exception occurred while processing the request.
AggregateException: One or more errors occurred. (Response status code does not indicate success: 404 (Not Found).)
System.Threading.Tasks.Task.Wait(int millisecondsTimeout, CancellationToken cancellationToken)
HttpRequestException: Response status code does not indicate success: 404 (Not Found).
Is this right way to pass multiple parameters and route it?
requestUrl is build as below:
string requestUrl = string.Format(Token_RefreshUserToken + "/{0}"+"/{1}", token,refreshToken);
requestUrl value is(web api controller name is 'Token'):
"Token/Refresh/eyJhbGciOiJIQrI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InJlZnJhbmNpc0BzdXlhdpdGkuY54tIiwiZXhwIojxNTYwMzMyOTk7hCJpc3MiOiJodHRwOi8vd3d3LnNlY3WeaXR5Lm9yZyIsImF1ZCI3rdh0dHA6Ly93d3cuc2VjdXJpdHkub3JnIn0.2Iw0VS_OgMjfpgt5V27mjCuLLqzlZBgRMpYgCTEHRP88E/IDwRYkf9idsVrBhBJJ5ymS+8RrZuSBSl+wywuKCs+Bw="
Client:
Task<TokenModel> userToken = _commonHelper.RecreateUserToken(tokenModel.TokenVal, tokenModel.RefreshToken);
userToken.Wait();
public async Task<TokenModel> RecreateUserToken(string token, string refreshToken)
{
string url = string.Format(WebApiConstants.Token_RefreshUserToken + "/{0}"+"/{1}", token,refreshToken);
var statusResponse = await _ApiHelper.GetAsync(url);
tokenData = await statusResponse.Content.ReadAsAsync<TokenModel>();
return tokenData;
}
Web Api method :
[HttpGet]
[Route("Refresh/{token}/{refreshToken}")]
public async Task<TokenValue> Refresh(string token, string refreshToken){ //logic }

It seems that request containing double escape sequence caused the problem.In development mode, try to run the web api project with Kestrel instead of IIS express.
ASP.NET Core application could be hosted on variety of web servers (IIS, Kestrel, Nginx, Apache, ...). All these web servers know nothing about request filtering (and particularly enabling of double escape) which is a native IIS feature. It's a hosting concern and ASP.NET Core application should not deal with it directly. If URL like http://youserver.com/Home/Phone/+12345 will reach ASP.NET Core pipeline, plus sign will not be treated in any special way and will get to string model as + character.
When you host your application on IIS, web.config is still in use, so you could configure <requestFiltering allowDoubleEscaping="true"/> as for usual ASP.NET application.
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
If you want to host application in another Web server, you should check how it handle special characters. Kestrel will just pass such URLs as is, so you don't need to take any specific actions if hosted on Kestrel.
Refer to here

Related

Web Api call returns 302 error code (on Authentication failed) and additional response with login page

I am facing a strange issue and unable to find a way out. I have a web api application which is working fine until it times out. At this point when i make a ajax call server response is empty and an additional response is received with Login URL.
I thought of catching response and read location header to identify if it contains login URL with no success. How should we handle such scenario in web api ajax calls?
You could set the SuppressFormsAuthenticationRedirect property to prevent this behavior. For example in your global.asax:
protected void Application_EndRequest(object sender, EventArgs e)
{
HttpApplication context = (HttpApplication)sender;
context.Response.SuppressFormsAuthenticationRedirect = true;
}
Setting this will have a global impact over both your ASP.NET MVC and Web API parts.
If you want to do this only for your Web API endpoints, you could inspect the context.Request.Url and conditionally do it only for /api endpoints.
If you are using newer versions of the framework you might also consider reading this post.

Can't seem to get fiddler to Proxy HttpClient

I've been having issues getting fiddler to pick up the traffic of a self-hosted asp.net web api. My situation might be a little different in that the same application that is hosting the web api is also consuming it (yes we have reasons to do this :) ). We are using HttpClient. Here are the things I've tried:
Adding an HttpClientHandler and setting up the proxy.
added the following to app.config
<system.net>
<defaultProxy>
<proxy bypassonlocal="False" usesystemdefault="True" proxyaddress="http://localhost:8888"/>
</defaultProxy>
Tried to hit the api from a separate .net client client (thinking the same process consuming the api that is hosting it was not allowing the traffic to be captured since it was all Intra-process).
Now if i open a web browser or postman locally and hit the api then traffic will be captured correctly
Here is the client code:
var handler = new HttpClientHandler();
handler.UseProxy = true;
handler.Proxy = new WebProxy("http://127.0.0.1",8888);
var client = new HttpClient(handler) {BaseAddress = new Uri(new Uri("http://localhost:8085"), "api/companies")};
HttpResponseMessage response;
using (client)
{
response = client.GetAsync(client.BaseAddress).Result;
}
var result = response.Content.ReadAsAsync<IEnumerable<Company>>().Result;
Now ideally i would want just to be able to open fiddler on a running app and capture traffic (even in production) without having to change the source code.
Unfortunately, the .NET Framework is hardcoded to bypass the proxy for Localhost addresses (see my feature request here: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6359204-support-the-loopback-token-in-proxy-bypass-lists)
To workaround this, change your request URL from http://localhost:8085 to http://localhost.fiddler:8085 and Fiddler will pick up the request.

CRM dynamics web api (400) Bad Request

I have a crm dynamics plugin that makes a web api call but I am getting the following error:
The remote server returned an error: (400) Bad Request
I am using the following code
using (WebClient client = new WebClient())
{
string URI = "http://myserver/api/myaction";
string myParameters = string.Format("param1={0}", param1);
using (WebClient wc = new WebClient())
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string HtmlResult = wc.UploadString(URI, myParameters);
}
}
When I profile and debug this with the Plugin Registration tool the web api call returns a valid result and does not error.
Any ideas what is causing this infuriating issue?
UPDATE:
The plugin is running in sandbox mode and is on premise.
We have tried using async HttpClient but this requires the referencing of additional dlls which causes it own issues (adding the dlls to the GAC/ ILMerge) hence trying to get a working solution with WebClient initially which requires no additional dll referencing.
The issue turned out to be caused by an IIS binding issue.

Request.CreateResponse vs returning POCOs in ASP.NET Web API

I see a lot of samples on the web for ASP.NET Web API that use Request.CreateResponse to generate responses. If you create a new Web API project in Visual Studio, the default API controllers return IEnumerable<string> or string. What's the difference in usage?
Returning a HttpResponseMessage allows you to control all different aspects of the returned HTTP response directly. If you return a POCO you have to hope that the framework does what you want. And maybe it will, and maybe it won't.
Request.CreateResponse can generate other http message, ex.404,500.
If just return,the http message will be 200 OK.
In my code, if get need authorized, I will return like this:
throw new HttpResponseException(HttpStatusCode.Unauthorized);
write this,you unnecessary change the return value.

Using ajaxSetup beforeSend for Basic Auth is breaking SignalR connection

I have a WebApi secured with Basic Auth which is applied to the entire Api using a AuthorizationFilterAttribute. I also have SignalR Hubs sitting on several of my Api Controllers.
Alongside this I have a web page which makes use of my WebApi. The web page is mostly written in Backbone, so in order to make calls to my secured WebApi, I have added the following jquery
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
This works for communicating with my Api Controllers, but adding the above code has broken the connection to my SignalR Hubs, specifically:
XMLHttpRequest cannot load http://localhost:50000/signalr/negotiate?_=1366795855194.
Request header field Authorization is not allowed by Access-Control-Allow-Headers.
Removing the jqXHR.setRequestHeader() line restores my SignalR Hub connection but breaks the Api calls.
Given the above, I could do something hacky and only set the request header if the request being made isn't to /signalr but that just feels dirty...
Is there a cleaner way around this?
Am I just doing something silly? Has anyone else ran in to this?
What I didn't mention before is that I have a DelegatingHandler which sends back the correct Headers to any request coming in to my WebApi. This works perfectly for any requests to my WebApi but I wrongly assumed that this would also apply to SignalR requests.
As SignalR relies on several different transport methods, it doesn't seem reasonable to assume I have access to Authorization headers in the first place - they're not a requirement of all WebSockets implementations for example (see here)
My current solution has been to make use SignalR's HubPipeline (detailed here). Using this, I believe I can pass the Basic Auth credentials in a query string and write a separate module for handling Authorization for the SignalR requests:
Passing the Query string
$.connection.hub.qs = "auth=" + MyBase64EncodedAuthString;
The Filter
public class SignalrBasicAuthFilterAttribute: Attribute, IAuthorizeHubConnection {
public bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) {
var authString = request.QueryString["auth"];
// ... parse, authorize, etc ...
return true;
}
}
Registering the Filter
var globalAuthorizer = new SignalrBasicAuthFilterAttribute();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));
Additionally...
Note that because it's not a reliable assumption to send an Authorization header with SignalR requests, for the aforementioned reasons, I am still filtering my $.ajaxSetup to only affect non-SignalR requests:
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if (settings.url.indexOf("/signalr") == -1)
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
In doing this, I'm leaving SignalrBasicAuthFilterAttribute class to take on full responsibility for Authorizing SignalR requests.
Further Reading:
http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx
http://eworldproblems.mbaynton.com/2012/12/signalr-hub-authorization/
SignalR authentication within a Controller?
I think the real solution for the issue will be to make sure that "Authorization" is part of the allowed Headers(Access-Control-Allow-Headers) returned from the signalR response for "negotiate" request.
You could register the header in your web.config just like this possibility.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Headers" value="Authorization" />
</customHeaders>
</httpProtocol>

Resources