I have a Web Api project with this route config
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
"DefaultApiRoute",
"api/v1/{controller}/{action}");
I have two post method
[HttpPost]
public IHttpActionResult RetrieveTestNoParam()
{
return new JsonResult<string>("This is a test", new JsonSerializerSettings(), Encoding.UTF8, this);
}
[HttpPost]
public IHttpActionResult RetrieveTest(string input)
{
return new JsonResult<string>(input, new JsonSerializerSettings(), Encoding.UTF8, this);
}
The first one is working but the second one gives this respone
{
"Message": "No HTTP resource was found that matches the request URI 'http://test.dev.local/api/v1/NewsApi/RetrieveTest'.",
"MessageDetail": "No action was found on the controller 'NewsApiController' that matches the request."
}
This is what I see in fiddler
POST http://test.dev.local/api/v1/NewsApi/RetrieveTest HTTP/1.1
Host: test.dev.local
Connection: keep-alive
Content-Length: 261
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Content-Type: application/javascript
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
Postman-Token: c2ba631b-4bfd-9379-bf40-0ca1a6a8a3bc
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,nl;q=0.6
Cookie: ASP.NET_SessionId=4kgfwd2u3pwusfdvdsrkt2vt; SC_ANALYTICS_GLOBAL_COOKIE=ddd9185a3e8940c9823e81b7d38cdf20|False; sc_expview=0
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="input"
Dit is de input
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="czczcsdcsdf"
sdfsfsdfsdff
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa--
Any ideas?
Other questions I have about Web Api:
Can a controller contain multiple get or post methods?
Do I need the actionname attribute and what does this attribute do?
Regards
Danny
Related
Intro
There is a #GetMapping attribute, as the following in one of our projects:
#GetMapping(path = "/", produces = SaConstants.SA_MEDIA_TYPE)
public HttpEntity<Resource<Home>> get(HttpServletResponse response) {
In the SaConstants class:
public static final String SA_MEDIA_TYPE="application/sa+json";
When I access the page from any internet browser, I am getting the proper response that I want - and my breakpoint in the controller is being triggered.
The browser is sending the following headers:
Host: 127.0.0.1:8001
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: io=Qt74kp5V5ziUNIxlAAAG
When I make a request to the page, without an Accept header, the page is not working.
If I add to postman the following Accept header, everything works:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Question
My question are:
why does it work even if the Accept: header of the request doesn't match the produces attribute of the Rest Controller?
Why does it fail if no Accept header is provided (given the first question).
"*/*" means all types, this header is by default provided by most of the popular browsers
Asp MVC 5 app deployed on IIS 8.5.
Need to enable ajax request from a number of clients.
Server-side I have In WebApiConfig.cs
config.EnableCors();
In controller:
[EnableCors(origins: "http://localhost:59901", headers: "*", methods: "*", SupportsCredentials = true)]
public class ItemController : Controller
Client side
$("#getItem").on("click", function (e) {
var myurl = "http://servername/item/details/1"
$.ajax({
url: myurl,
type: "GET",
dataType: "JSON",
xhrFields: {
withCredentials: true
},
contentType: "application/json; charset=utf-8",
error: function (jqXHR, textStatus, errorThrown) {
$('#result').text(jqXHR.responseText || textStatus);
},
success: function (result) {
$('#result').text(result);
}
});
});
Running client from VisualStudio Origin is http://localhost:59901.
Running the ajax request I get the following in fiddler:
1. Preflight request/response
OPTIONS http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4
HTTP/1.1 200 OK
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://localhost:59901
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:54 GMT
Content-Length: 0
2. GET request without credentials/ 401 error response
GET http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/json; charset=utf-8
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:54 GMT
Content-Length: 1352
Proxy-Support: Session-Based-Authentication
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Autorizzazione negata: accesso negato a causa di credenziali non valide.</title>
....
</head>
<body>
<div id="header"><h1>Errore del server</h1></div>
....
</body>
</html>
3. GET request with NTLM token for auth / response without Allow CORS header
GET http://vrtsrv01.webdev.local/item/details/1 HTTP/1.1
Host: vrtsrv01.webdev.local
Connection: keep-alive
Authorization: Negotiate <...NTLM TOKEN HERE ...>
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost:59901
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/json; charset=utf-8
Referer: http://localhost:59901/Home/Index
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,it;q=0.6,it-IT;q=0.4
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.5
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Sat, 13 May 2017 15:34:58 GMT
Content-Length: 8557
{"id":1, .....}
QUESTION
Why after enabling MVC app for CORS and seeing the right response to preflight request, the response obtained after NTLM authentication does not contain the expected Access-Control-Allow-Origin header?
I'm not sure that it will help you, but it might help someone else looking to have both NTLM and CORS enabled.
CORS enabling
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
//SupportsCredentials = true means that we will add Access-Control-Allow-Credentials to the response.
config.EnableCors(corsAttr);
}
}
SupportsCredentials = true means that we will add Access-Control-Allow-Credentials to the response.
Other solutions,
global.asax.cs - properly reply with headers that allow caller from another domain to receive data
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.Request.HttpMethod == "OPTIONS")
{
Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,MaxDataServiceVersion");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
Context.Response.End();
}
}
SOLVED (...for now...)
The invoked action was a controller action returning Json. This does not work with CORS. I need to create an API controller, cannot use the existing controller. This leads to code duplication, but I have no time now to refactor the whole application to use a single controller both for MVC and API
I'm trying to POST a simple JSON object to a RESTfull server using the following code:
var messages:Array = new Array ();
messages.push ({"name":"MyName"});
var vars: URLVariables = new URLVariables();
vars.data = JSON.stringify(messages);
var urlRequest:URLRequest= new URLRequest("http://localhost:8080/xxx/player/createAccount");
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = vars;
var hdr:URLRequestHeader = new URLRequestHeader("Content-type", "application/json");
urlRequest.requestHeaders.push(hdr);
_urlLoader = new URLLoader();
_urlLoader.addEventListener(Event.COMPLETE, onXMLDataLoaded);
_urlLoader.load(urlRequest);
My object is a simple one, it contains a field called {"name" : "MyName"}
The server fails to recognize the request's data.
the request on the network monitor shows this:
POST http://localhost:8080/xxx/player/createAccount HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 42
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost:8080
X-Requested-With: ShockwaveFlash/15.0.0.223
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:8080/xxx/flashClient/lobby.swf
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,he;q=0.6
Cookie: JSESSIONID=1841C3CBE7511794A4EEF8A1A0BD56DD
data=%5B%7B%22name%22%3A%22MyName%22%7D%5D
A working post request looks like this on the network monitor tool:
POST http://localhost:8080/xxx/player/createAccount HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 20
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36
Origin: chrome-extension://cdjfedloinmbppobahmonnjigpmlajcd
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,he;q=0.6
Cookie: JSESSIONID=1841C3CBE7511794A4EEF8A1A0BD56DD
{ "name" : "MyName"}
Any ideas how can I make the first request perform like the second one?
If you're content type is application/json, then you don't want to use URLVariables for your data:
//this is causing the problem because it's encoding your JSON string so it's url safe.
var vars: URLVariables = new URLVariables();
vars.data = JSON.stringify(messages);
Instead, assign the stringified JSON directly to the URLRequest's data property like in the following example:
var urlRequest:URLRequest= new URLRequest("http://localhost:8080/xxx/player/createAccount");
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = JSON.stringify({"name":"MyName"});
var hdr:URLRequestHeader = new URLRequestHeader("Content-type", "application/json");
urlRequest.requestHeaders.push(hdr);
_urlLoader = new URLLoader();
_urlLoader.addEventListener(Event.COMPLETE, onXMLDataLoaded);
_urlLoader.load(urlRequest);
P.S. There is a good tutorial that can help with understanding REST paradigm.
I have a webapi2 controller method as below:
[Route("shipment/{shipmentId:long}/quotes/register")]
public HttpResponseMessage ProvideQuote(long shipmentId, [FromBody]RegisterQuote quote)
{
HttpResponseMessage response;
response = Request.CreateResponse(HttpStatusCode.Accepted, String.Format("quote of price {0} for shipment {1} has been registred", quote.QuotePrice, shipmentId));
return response;
}
now the issue is that when I test the method using my REST client, the quote is always null.
here is how I am testing
parameter
now the response I get is:
as you can see that the query string parameter is being passed correctly, but the body parameter is not passed. any idea what am I doing wrong.
Edit 1:
Request Header:
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
Authorization: Bearer Hhz54k1BLyPMJxucSeq4pLwhS3Y4Ez5WCoEMzhe-uH7gHMFMRjHE2Im9juinMLhqaHVZmkVrWetEiCsYbaduzLas7rYf-D3p40lH_q3IDEn2rdt122qpiHvnUr7Cz2b6GXiPYLGDMQFOMN0lbkYmoZe95sxXDRvDfpdJw4G2Fk3Ri1A25F3qAZCnBhjA-BLoL-2eAjxX-RPCGAXjaNLjT4zsxRJH8NP5qC7azPrWCDKRuK282hnTbKViQjMBDflwlxdPhTNkiCBtxWn03xRcxH9GD1z5Ca0Qinn5gUS7qWwCt9zoZtHcbwFY1kvxyx7x5yCuyEfrGHgKG1s7zjTPjNwU0eV7cC6xQA2GsOAnqADxMDyRryCRKLY7WcyQftRhZ70WbtSW2PI0F7qmDr8n0wvktmKglusLEDf4ib925n-ajVTyMl7v9O-9OsdgCj_GSNE6_bszd3Ak1yUurs-VoQ
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,kn;q=0.6
BTW I am not sure what happened to all my images though!
Regards
Kiran
The issue here is that you are sending Json content in the body but have the content-type header as application/x-www-form-urlencoded...change the content-type header to application/json or text/json if want to send data in json...
I'm trying to get breeze to work with my webapi/odata service against an Entity framework model with a sql backend.
I've got it to retrieve data from my database, bit am having trouble when I do a createEntity() and then call saveChanges().
I've configured my batch route like this
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// Web API routes
config.Routes.MapHttpBatchRoute(
routeName: "WebApiBatch",
routeTemplate: "odata/$batch",
batchHandler: new System.Web.Http.Batch.DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer));
When I call save changes I get an http 500 server error, with the message:
Invalid 'HttpContent' instance provided. It does not have a content type header with a value of 'application/http; msgtype=request'.
Parameter name: content
the stream sent to the server is :
POST http://gx9020-01:91/odata/$batch HTTP/1.1
Accept: multipart/mixed
DataServiceVersion: 2.0
Content-Type: multipart/mixed;boundary=batch_9245-db9a-4873
MaxDataServiceVersion: 3.0
Referer: http://localhost:61678/WebForm1.aspx
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 731
DNT: 1
Host: gx9020-01:91
Pragma: no-cache
--batch_9245-db9a-4873
Content-Type: multipart/mixed; boundary=changeset_0952-3d90-c3e2
--changeset_0952-3d90-c3e2
Content-Type: application/http
Content-Transfer-Encoding: binary
POST odata/MAP_Counterparty HTTP/1.1
Content-ID: 1
DataServiceVersion: 2.0
Accept: application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1
Content-Type: application/json
MaxDataServiceVersion: 3.0
{"MAP_CounterpartyID":-1,"SOURCE_SYSTEM":null,"TARGET_SYSTEM":null,"SOURCE_CODE":null,"TARGET_CODE":null,"TARGET_CODE2":null,"DRT_ID":null,"CREATE_DATETIME":null,"MODIFY_DATETIME":null,"Create_User":null,"Modify_User":null}
--changeset_0952-3d90-c3e2--
--batch_9245-db9a-4873--
How can I get the saveChanges() working?
I found the problem. I was using DefaultHttpBatchHandler instead of DefaultODataBatchHandler.