Web api Post call from ajax fails - c#

I have an web api wand I call it method in an ajax with POST method, sending the parameter as data . It gives me a 404 not found error.
But when I pass the data in the query string , it works fine. Please help me fixing the matter and get it worked when calling the method with data in the body, not the query string.
Note : The web application and Web-api are running on different ports
Sending a concrete type object in query string also does not work and received to web api as null
config
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, contentType, data" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Controller
public class RiskController : ApiController
{
method
[HttpGet, HttpPost]
public DashboardContainerViewModel GetDashboardContainer(string token)
{
Ajax call
var postData = { token: priv.secToken };
$.ajax({
type: 'POST',
url: 'http://localhost:48060/api/Risk/GetDashboardContainer',
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
data: postData,
success: function (data) {
pub.dashboardHeader(data.Name);
var defaultTab = _.find(data.Dashboards, function (tab) {
return tab.IsDefault == true;
});
And I get POST http://localhost:48060/api/Risk/GetDashboardContainer 404 (Not Found)
Fiddler request headers
POST http://localhost:48060/api/Risk/GetDashboardContainer HTTP/1.1
Host: localhost:48060
Connection: keep-alive
Content-Length: 142
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:10452
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:10452/Authorised/DashBoard/DashBoard.aspx
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
token=ETvgg0YH4sx9w%2FiQL5560S20Ja4jGix%2FiBTOFGpQCliYZVilmtKiXPbk30d8FTYbhUWyFqz8%2FqT1pmI0oY6rzDGQ7krL6d2fDKDKwJhfCNFXZxnv%2BPCUj5ki5eizdWOM
Fiddler response headers
HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcRGVmYXVsdENvbGxlY3Rpb25cQ0FNTVNfUHJvZHVjdHNcX1JlbGVhc2VcMTQxMExSLUFNXFdlYiBTZXJ2aWNlXENBTU1TLlNBQVMuV2ViQVBJXENBTU1TLlNBQVMuSVJNV2ViQVBJXGFwaVxSaXNrXEdldERhc2hib2FyZENvbnRhaW5lcg==?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, contentType, data
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Date: Fri, 29 Jun 2018 05:47:22 GMT
Content-Length: 215
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:48060/api/Risk/GetDashboardContainer'.","MessageDetail":"No action was found on the controller 'Risk' that matches the request."}

This is most lilkely due to a routing error in my opinion and experience, have you tried looking at RouteConfig.cs to make sure it sets the right routes for your API?
Something like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

Your Controller method uses simple type parameter. WebApi will search for simple parameter in request URL. So if you want to POST parameter, you must tell WebApi to look at the request body.
public DashboardContainerViewModel GetDashboardContainer([FromBody] string token)
But you also need to change the format of data you are sending. Simple type data sent as application/x-www-form-urlencoded must be in format '=value' not 'token=value'
var postData = "=testData";

Related

I get a cross-origin error when making a HTTP requests

I have requests that are valid when I am making requests from browser , but through the Angular 9 app I get a 401 error.
This is the header from chrome:
Request URL: http://localhost:1234/api/Common/GetMy_List
Request Method: GET
Status Code: 401
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X-Token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: http://localhost:4200
Access-Control-Allow-Origin: *
Cache-Control: private
Content-Length: 6069
Content-Type: text/html; charset=utf-8
Date: Wed, 06 Oct 2021 12:55:39 GMT
Server: Microsoft-IIS/10.0
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: he-IL,he;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Host: localhost:1234
Origin: http://localhost:4200
Referer: http://localhost:4200/
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36
I have an angular 9 project with proxy.conf.json file that declared in package.json.
the file contain this lines:
{
"/api/*": {
"target": "http://localhost:1234",
"secure": true,
"logLevel": "debug",
"changeOrigin": true
}
}
In server side there is an asp.net api with this lines in global.asax:
public void Application_BeginRequest(object sender, EventArgs e)
{
string httpOrigin = Request.Params["HTTP_ORIGIN"];
if (httpOrigin == null) httpOrigin = "*";
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", httpOrigin);
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
if (Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.StatusCode = 200;
var httpApplication = sender as HttpApplication;
httpApplication.CompleteRequest();
}
}
In the web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<validation validateIntegratedModeConfiguration="false" />
<directoryBrowse enabled="false" />
</system.webServer>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonateBehaviour">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" maxReceivedMessageSize="2147483647">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/xxx.svc" behaviorConfiguration="ImpersonateBehaviour" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="Service1Ref.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
I noticed that I can to enter Application_BeginRequest but not into my function in the controller,which means CORES privilege issue.
so In the IIS, I added anonymous authentication and now I can make requests of GET/POST and others.
In IIS choose your site in Sites then dowble click on Authentications categoty, then=>:
Try changing your Application_BeginRequest to this. When I try using yours it fails on my code. The below code works.
protected void Application_BeginRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept, X-Token");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
HttpContext.Current.Response.End();
}
}
Browser allows any http request to the origin ( url where your http session started ). In single page applications we usually load the DOM which intern makes additional XHRs to a new domain (usually a new web app/rest api) . This is considered as a security flaw and all of the reputable and modern browsers stopped supporting this behavior.
To mitigate this you need a proxy in origin domain. All of the request to get data should pass through it.
In angular you can :
Configure the server to send the appropriate CORS headers
Configure Angular CLI proxy
I suggest using angular CLI proxy rather than adding CORS configuration.

CORS issue only on PUT on .NET5

I'm getting Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://mysiteapi.domain.com/api/v1.0/operations/1. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). when trying to do a PUT request to my .NET5 WebAPI.
These are the methods I've added CORS to the API:
public static void AddCustomCors(this IServiceCollection services, IWebHostEnvironment env, IConfiguration config)
{
var cors = config.GetSection("Cors").Get<CorsSettings>();
if (!cors.Enabled)
{
return;
}
services.AddCors(options =>
{
options.AddPolicy("Default",
builder =>
{
builder.WithExposedHeaders(cors.ExposedHeaders)
.WithHeaders(cors.Headers)
.WithMethods(cors.Methods);
.WithOrigins(cors.Origins);
});
});
}
public static void UseCustomCors(this IApplicationBuilder app, IConfiguration config)
{
var cors = config.GetSection("Cors").Get<CorsSettings>();
if (cors.Enabled)
{
app.UseCors("Default");
}
}
They are called in Startup.cs as the first methods in ConfigureServices and Configure respectively.
The settings look like this:
"Cors": {
"Enabled": true,
"Origins": [ "http://mysite.domain.com" ],
"ExposedHeaders": [ "X-Request-Id", "X-Request-Duration" ],
"Headers": [ "Content-Type", "Authorization", "X-Requested-With" ],
"Methods": [ "OPTIONS", "GET", "POST", "PUT", "DELETE" ]
}
GET requests work but not PUT. Checking the Network browser tab I see that the OPTIONS request is ok and I can see my settings being added but in the PUT request they are missing.
The OPTIONS request and response:
OPTIONS /api/v1.0/operations/1 HTTP/2
Host: mysiteapi.domain.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: authorization,content-type
Referer: https://mysite.domain.com/operation/edit/1
Origin: https://mysite.domain.com
Connection: keep-alive
TE: Trailers
HTTP/2 204 No Content
server: Microsoft-IIS/10.0
access-control-allow-origin: https://mysite.domain.com
access-control-allow-headers: Content-Type,Authorization,X-Requested-With,Origin
access-control-allow-methods: OPTIONS,GET,POST,PUT,DELETE
x-powered-by: ASP.NET
x-powered-by-plesk: PleskWin
date: Thu, 28 Jan 2021 16:21:49 GMT
X-Firefox-Spdy: h2
The PUT request and response:
PUT /api/v1.0/operations/1 HTTP/2
Host: mysiteapi.domain.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 353
Origin: https://mysite.domain.com
Connection: keep-alive
Referer: https://mysite.domain.com/operation/edit/1
TE: Trailers
HTTP/2 405 Method Not Allowed
allow: GET, HEAD, OPTIONS, TRACE
content-type: text/html
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
x-powered-by-plesk: PleskWin
date: Thu, 28 Jan 2021 16:21:49 GMT
content-length: 12591
X-Firefox-Spdy: h2
The API is on a web host running in IIS in Plesk 18.0.32. The web.config is as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\MySite.WebApi.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
</system.webServer>
</location>
</system.webServer>
<system.web>
<compilation tempDirectory="C:\Inetpub\vhosts\mysite.com\tmp" />
<customErrors mode="Off" />
</system.web>
</configuration>
I suspected this was a problem with the web.config so I've tried:
adding the Access-Control-Allow-Origin as a custom header in web.config - this resulted in an error because they were being added twice
removing the CORS stuff from the API and having them added only from web.config - resulted in errors about the preflight request
removing the header through web.config and then adding it - resulted in an error (preflight I think)
adding the configuration from https://learn.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference to the web.config - also resulted in an error
Has anyone else encountered this problem?
Include this inside the <system.webServer> xml just before <handlers> in web.config to remove webdav which might have disabled PUT requests.
<modules>
<remove name="WebDAVModule" />
</modules>

Request json Data

I getting the stuck while post the Request json data with bearer token in c#.
EX - Jsondata
"{"data":{"POLICY_NO":"29991231030","POLICY_TYPE":"1","HEGICCardNo_Var":"HC1801724-01A"}}"
response:
{StatusCode: 403,
ReasonPhrase: 'Forbidden',
Version: 1.1,
Content: System.Net.Http.StreamContent,
Headers:
{
Pragma: no-cache
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Date: Sat, 02 Mar 2019 06:21:40 GMT
Server: Microsoft-IIS/7.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Content-Length: 28
Content-Type: text/plain; charset=utf-8
Expires: -1
}}
While posting the Json data in web service Respective url with Bearer Token.
Then First Add the AuthenticationHeaderValue as Below C# Code :
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization/Bearer", TokenValue);
HttpResponseMessage messge = client.PostAsync(Url,ContentObj).Result;

Why cant I see the Content-Encoding: gzip response in my c# HttpClient response header?

I'm making a simple c# program to establish if server side compression is available/enabled on various servers. This is my request code below.
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(0, 0, 5);
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch, br");
var httpClientResponse = client.GetAsync(websiteURL).Result;
string header = httpClientResponse.Headers.GetValues("Content-Encoding").First();
}
I can see by watching the request in fiddler that compression is enabled for this request however I can't seem to extract that information from the response headers in code.
These are the full headers for request and response.
GET https://www.dobbies.com/ HTTP/1.1
Accept: text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, */*; q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36
Accept-Encoding: gzip, deflate, sdch, br
Host: www.dobbies.com
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server:
Set-Cookie: ASP.NET_SessionId=hx1rb34ottgfritgt3rciql4; path=/; secure; HttpOnly
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
X-Xss-Protection: 1; mode=block
Date: Fri, 07 Apr 2017 08:06:17 GMT
Content-Length: 16836
This is what I get when I use httpClientResponse.Headers
{
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
X-Xss-Protection: 1; mode=block
Cache-Control: private
Date: Fri, 07 Apr 2017 08:06:17 GMT
Set-Cookie: ASP.NET_SessionId=hx1rb34ottgfritgt3rciql4; path=/; secure; HttpOnly
Server:
}
As you can see header of Content-Encoding: gzip is missing in the response.
Why would this header be missing? Along with others. Give me back my headers!
Found the problem.
The HttpResponseMessage returned by HttpClient methods has two header properties:
HttpResponseMessage.Headers is an HttpResponseHeaders with generic response headers
HttpResponseMessage.Content.Headers is an HttpContentHeaders with content-specific headers like Content-Type

What the format and contentType should be?

I'm creating an Asp.net core web api to accept the multiple part http post. Here is the raw http post, There are three text strings and one uploaded binary file (can be any type of file).
POST http://localhost:5001/api/ClosingDoc HTTP/1.1
Host: localhost:5001
Connection: keep-alive
Content-Length: 6957
Accept: application/json, text/plain, */*
Origin: http://localhost:8082
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDTtxFp41DIpArUZ0
Referer: http://localhost:8082/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
------WebKitFormBoundaryDTtxFp41DIpArUZ0
Content-Disposition: form-data; name="Id"
ANYTHING001
------WebKitFormBoundaryDTtxFp41DIpArUZ0
Content-Disposition: form-data; name="docType"
Test
------WebKitFormBoundaryDTtxFp41DIpArUZ0
Content-Disposition: form-data; name="comments"
Test
------WebKitFormBoundaryDTtxFp41DIpArUZ0
Content-Disposition: form-data; name="control.PNG"; filename="control.PNG"
Content-Type: image/png
PNG
.....
I created the class ClosingDocInputFormatter : InputFormatter, now I need to added it the following code in Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
var connection = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<Models.StaticDataContext>(options => options.UseSqlServer(connection));
services.AddMvc(o => {
o.InputFormatters.Add(new ClosingDocInputFormatter());
//??? x.OutputFormatters.Add(new ClosingDocOutputFormatter()); // No need?
o.FormatterMappings.SetMediaTypeMappingForFormat(
"???", MediaTypeHeaderValue.Parse("????")) // What the strings should be?
});
services.AddCors();
}
Questions.
Do I need to define the OutputFormatter since I only need to do the post part?
The method o.FormatterMappings.SetMediaTypeMappingForFormat need two string parameters. What the values they should be?

Categories