What can cause a handler to be ignored? - authentication

We moved to a new server and my Thinktecture IdentityModel stuff broke.
Here's a super simplified repro sample. This works run locally from Visual Studio, but deployed to the server the handler is clearly not handling.
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Thinktecture.IdentityModel.Tokens.Http;
namespace WebApplication1
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configuration.MessageHandlers.Add(
new AuthenticationHandler(CreateConfiguration()));
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
private AuthenticationConfiguration CreateConfiguration()
{
var config = new AuthenticationConfiguration
{
EnableSessionToken = true,
RequireSsl = false,
SendWwwAuthenticateResponseHeaders = false
};
config.AddBasicAuthentication(
(username, password) => { return username == password; });
return config;
}
}
}
The handler is not executing. I have set up remote debugging and this revealed that
The Thinktecture assembly is loaded
Application_Start creates and adds a basic auth handler
This script is the test client
<script>
$(document).ready(function () {
var u = "bilbo";
var p = "bilbo";
var btoken = btoa(u + ":" + p);
$.ajax({
url: "api/token",
headers: { Authorization: "Basic " + btoken },
}).then(function (result) {
document.write("auth ok");
}).fail(function (error) {
document.write("auth fail");
});
});
</script>
It produces a request for api/token decorated with a basic auth header as shown:
GET http://assa.com.au/api/token HTTP/1.1
Accept: */*
Authorization: Basic YmlsYm86YmlsYm8=
X-Requested-With: XMLHttpRequest
Referer: http://assa.com.au/sandpit
Accept-Language: en-AU,en-GB;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: assa.com.au
Connection: Keep-Alive
This server responds with this 401
HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/8.5
WWW-Authenticate: Basic realm="assa.com.au"
X-Powered-By: ASP.NET
Date: Wed, 17 Feb 2016 01:36:27 GMT
Content-Length: 1293
<!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 - Unauthorized: Access is denied due to invalid credentials.</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
fieldset{padding:0 15px 10px 15px;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;}
#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
background-color:#555555;}
#content{margin:0 0 0 2%;position:relative;}
.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
-->
</style>
</head>
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
<div class="content-container"><fieldset>
<h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>
<h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>
</fieldset></div>
</div>
</body>
</html>
Visual Studio 2013 is showing valid breakpoints in the handler but they are not hit. This is why I believe the handler is not being invoked.
The response specifies a realm, but modifying handler registration to specify realm = "assa.com.au" did not affect the outcome.

The answer lies in the handling of the absence of trailing slashes.
The test page is requested as assa.com.au/sandpit which does return the right HTML.
Close inspection of the 401 response reveals that the request is for api/token which is not the correct URL for the token dispenser - it should be sandpit/api/token
Requesting the test page as assa.com.au/sandpit/ causes the requested URL to become sandpit/api/token and everything comes out in the wash.
But why is it 401? Shouldn't it be 404 not found? It turns out that the webserver was configured to respond to unauthorised requests by asking the user agent to authenticate, expressed as a 401 auth demand.
The incorrect URL left things in an unauthorised state, producing a 401 auth demand.

Related

Outlook Add-in REST call error

I'm trying to mark (flag) a message using the Outlook rest API, but I keep getting error messages. I've tried with different rest URLs but it doesn't help - the errors just varies.
Important values in the manifest for allowing this I believe are:
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.1" />
</Sets>
</Requirements>
...
<Permissions>ReadWriteItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
</Rule>
...
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
<Requirements>
<bt:Sets DefaultMinVersion="1.3">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
Here is the part I'm trying to do that causes error:
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (result)
{
if (result.status === "succeeded")
{
var accessToken = result.value;
var itemId = getItemRestId();
var restUrl = Office.context.mailbox.restUrl + "/api/v2.0/messages/" + itemId;
var request = {
url: restUrl,
type: "PATCH",
dataType: 'json',
data: { "Flag": { "FlagStatus": "Flagged" } },
headers: {
"Authorization": "Bearer " + accessToken,
"Conntent-Type": "application/json"
}
};
$.ajax(request)
.done(function (item)
{
// dome something
})
.fail(function (error)
{
// handle error
});
}
else
{
// handle error
}
});
function getItemRestId()
{
if (Office.context.mailbox.diagnostics.hostName === 'OutlookIOS')
{
return Office.context.mailbox.item.itemId;
}
else
{
return Office.context.mailbox.convertToRestId(
Office.context.mailbox.item.itemId,
Office.MailboxEnums.RestVersion.Beta
);
}
}
This code above will result in the error:
{"readyState":4,"responseText":"","status":404,"statusText":"Not Found"}
If I try to JSON.stringify() the data attribute of the request I get:
{"readyState":4,"responseText":"","status":404,"statusText":"Not Found"}
If I change the rest URL to (seen in older samples):
'https://outlook.office.com/api/beta/me/messages/'+ itemId;
And the headers attribute of the request to (seen in older samples):
headers: {
'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json'
}
Then I get the following error instead:
{
"readyState": 4,
"responseText": "{\"error\":{\"code\":\"ErrorAccessDenied\",\"message\":\"The api you are trying to access does not support item scoped OAuth.\"}}",
"responseJSON": {
"error": {
"code": "ErrorAccessDenied",
"message": "The api you are trying to access does not support item scoped OAuth."
}
},
"status": 403,
"statusText": "Forbidden"
}
Can anyone see what I'm doing wrong or missing here?
I'm debugging in Outlook 2016 and the account is Office 365.
UPDATE: Fiddler outputs
Here is the request my own sample sends (results in 403 Forbidden)
Exact error: {"error":{"code":"ErrorAccessDenied","message":"The api you are trying to access does not support item scoped OAuth."}}
PATCH https://outlook.office.com/api/beta/me/messages/AAMkAGNmMDllMTVhLTI3ZDctNDYxZS05ZWM5LTA3ZWQzMzYyNDBiOABGAAAAAAD6OQOAoKyKT6R02yYFe0bIBwD5fUzv7OgQQYAILztCFSSWAALg591rAAC382lxTQ2HQpUKZsAGTeWVAARPu37CAAA= HTTP/1.1
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
Authorization: Bearer <long token code removed...>
Referer: https://localhost:44394/MessageRead.html?_host_Info=Outlook$Win32$16.02$da-DK
Accept-Language: da-DK
Origin: https://localhost:44394
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: outlook.office.com
Content-Length: 33
Connection: Keep-Alive
Cache-Control: no-cache
{"Flag":{"FlagStatus":"Flagged"}}
Here is the request the demo project sends (results in 200 OK)
PATCH https://outlook.office.com/api/beta/me/messages/AAMkAGNmMDllMTVhLTI3ZDctNDYxZS05ZWM5LTA3ZWQzMzYyNDBiOABGAAAAAAD6OQOAoKyKT6R02yYFe0bIBwD5fUzv7OgQQYAILztCFSSWAALg591rAAC382lxTQ2HQpUKZsAGTeWVAARPu37CAAA= HTTP/1.1
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
Authorization: Bearer <long token code removed...>
Referer: https://<company.domain.com>:1443/outlookaddindemo/RestCaller/RestCaller.html?_host_Info=Outlook$Win32$16.02$da-DK
Accept-Language: da-DK
Origin: https://<company.domain.com>:1443
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: outlook.office.com
Content-Length: 47
Connection: Keep-Alive
Cache-Control: no-cache
{
"Flag": {
"FlagStatus": "Flagged"
}
}
The only difference I can see is that the 2nd request payload seems formatted for reading while data wise being identical to the previous one.
I can't seem to find the problem here - I even made sure that both projects use the same version of JQuery.
If you need write access to the item via REST, you need to specify ReadWriteMailbox in the Permissions element in your manifest. Despite it's name, ReadWriteItem doesn't give you a token with the proper scope. Any permission level other than ReadWriteMailbox gives an item-scoped token, and as the error says, the operation you're trying to do doesn't support item-scoped OAuth.
See https://learn.microsoft.com/en-us/outlook/add-ins/use-rest-api for details, but here's the relevant bit:
Add-in permissions and token scope
It is important to consider what level of access your add-in will need via the REST APIs. In most cases, the token returned by getCallbackTokenAsync will provide read-only access to the current item only. This is true even if your add-in specifies the ReadWriteItem permission level in its manifest.
If your add-in will require write access to the current item or other items in the user's mailbox, your add-in must specify the ReadWriteMailbox permission level in its manifest. In this case, the token returned will contain read/write access to the user's messages, events, and contacts.

How to disable access to cloudfront via the *.cloudfront.net url?

I created an AOI to restrict access of the s3 bucket to public.
So you can not access the s3 objects via the s3 endpoint but cloudfront can access all those objects and serve them.
I setup an Alternate Domain Names and add the SSL Certificate for this domain.
I setup route 53 with a A rule to alias cloudfront distribution
I can access the page using the Cloudfront public url (*.cloudfront.net) and mydomain.com
How can I remove the *.cloudfront.net access to my page?
This should be possible because the only service that needs this url is route 53.
Much easier than Lamda#Edge would be just to configure an ACL to block each request containing the Host header with your cloudfront distribution url.
Configure AWS WAF / ACL
You can use Lambda#Edge Viewer Request trigger. This allows you to inspect the request before the cache is checked, and either allow processing to continue or to return a generated response.
So, you can check the referer and make sure the request coming from your domain.
'use strict';
exports.handler = (event, context, callback) => {
// extract the request object
const request = event.Records[0].cf.request;
// extract the HTTP `Referer` header if present
// otherwise an empty string to simplify the matching logic
const referer = (request.headers['referer'] || [ { value: '' } ])[0].value;
// verify that the referring page is yours
// replace example.com with your domain
// add other conditions with logical or ||
if(referer.startsWith('https://example.com/') ||
referer.startsWith('http://example.com/'))
{
// return control to CloudFront and allow the request to continue normally
return callback(null,request);
}
// if we get here, the referring page is not yours.
// generate a 403 Forbidden response
// you can customize the body, but the size is limited to ~40 KB
return callback(null, {
status: '403',
body: 'Access denied.',
headers: {
'cache-control': [{ key: 'Cache-Control', value: 'private, no-cache, no-store, max-age=0' }],
'content-type': [{ key: 'Content-Type', value: 'text/plain' }],
}
});
};
For more info read the following pages:
https://stackoverflow.com/a/51006128/6619626
Generating HTTP Responses in Request Triggers
Updating HTTP Responses in Origin-Response Triggers
Finally, this article has a lot of valuable info
How to Prevent Hotlinking by Using AWS WAF, Amazon CloudFront, and Referer Checking
Also, a very simple solution is to add a CloudFront function on the viewer request event for your behaviour in question:
function isCloudFrontURL(headers) {
if(headers && headers["host"]) {
if(headers["host"].value.includes("cloudfront"))
return true
else if(headers["host"].multiValue)
return headers["host"].multiValue.some(entry => entry.value.includes("cloudfront"))
}
return false
}
function handler(event) {
if(isCloudFrontURL(event.request.headers))
return {
statusCode: 404,
statusDescription: 'Page not found',
headers: {
"content-type": {
"value": "text/plain; charset=UTF-8"
}
}
}
else
return event.request;
}
Based on #mhelf's answer, I prepared a demo in Terraform on how to set up WAF v2 for CloudFront.
Terraform resources
(1.) Configure AWS provider.
// WAF v2 for CloudFront MUST be created in us-east-1
provider "aws" {
alias = "virginia"
region = "us-east-1"
}
(2.) Create CloudFront distribution.
// CloudFront which is accessible at example.com
// and should not be accessible at ***.cloudfront.net
resource aws_cloudfront_distribution cf {
// ...
// ...
web_acl_id = aws_wafv2_web_acl.waf.arn
aliases = [
"example.com",
]
// ...
// ...
}
(3.) Finally create WAF v2.
// WAF v2 that blocks all ***.cloudfront.net requests
resource aws_wafv2_web_acl waf {
provider = aws.virginia
name = "example-waf"
description = "..."
scope = "CLOUDFRONT"
default_action {
allow {}
}
rule {
name = "cf-host-rule"
priority = 0
action {
block {
}
}
statement {
regex_match_statement {
regex_string = "\\w+.cloudfront.net"
field_to_match {
single_header {
name = "host"
}
}
text_transformation {
priority = 0
type = "LOWERCASE"
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "example-waf-cf-host-rule"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "example-waf"
sampled_requests_enabled = true
}
}
Notes
It would probably be safer/cleaner to use byte_match_statement to check the Host header value against aws_cloudfront_distribution.cf.domain_name. However, this would create a cycle between the CF and the WAF resource, which is why I used regex_match_statement.
Support for regex_match_statement has been added relatively recently in the AWS provider v4.34.0 (GH Issue 25101 / GH Pull request 22452 / GH Release v4.34.0)
WAF is a paid service, see: https://aws.amazon.com/waf/pricing/
cURL test
curl -v https://example.com
> GET / HTTP/2
> Host: example.com
> user-agent: curl/7.68.0
> accept: */*
>
< HTTP/2 200
< content-type: image/jpeg
< content-length: 9047
< date: Wed, 19 Oct 2022 13:40:55 GMT
< x-cache: Hit from cloudfront
curl -v https://***.cloudfront.net
> GET / HTTP/2
> Host: ***.cloudfront.net
> user-agent: curl/7.68.0
> accept: */*
>
< HTTP/2 403
< server: CloudFront
< date: Thu, 20 Oct 2022 08:15:44 GMT
< content-type: text/html
< content-length: 919
< x-cache: Error from cloudfront
< via: 1.1 ***.cloudfront.net (CloudFront)
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: ***
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

Arduino esp8266 device gets Bad Request error from apache server while making request from

I am sending post request from my arduino device to my hosted server it gives me 400 Bad request error.
Same code runs well in my localhost but not working on Hosted server.
My arduino code if give below.
void callApi(String ID,String path,int comm,String message,int isResponseNeeded) {
String serverPath="www.xyz.com";
String data = "{" ;
data = data + "\"id\": \""+ID+"\"," ;
data = data + "\"version\": \""+VERSION+"\"," ;
data = data + "\"command\": \""+comm+"\"," ;
data = data + "\"message\": \""+message+"\"" ;
data = data + "}" ;
Serial.print("Send data...on=>");
Serial.println(path);
if (wifiClient.connect(serverPath,80)) {
Serial.println(data);
wifiClient.println("POST /abc/xyz HTTP/1.1");
wifiClient.println("Content-Type: application/json");
wifiClient.print("Host: ");
wifiClient.println(serverPath);
wifiClient.print("Content-Length: ");
wifiClient.println(data.length());
wifiClient.print("\n");
wifiClient.print(data);
wifiClient.print("\n");
Serial.println("Data sent...Reading response..");
if(isResponseNeeded>0){
unsigned long timeout = millis();
while (wifiClient.available() == 0) {
if (millis() - timeout > 10000) {
Serial.println(">>> Client Timeout !");
break;
}
}
String response;
while(wifiClient.available()){
String line = wifiClient.readStringUntil('\n');
response=line;
Serial.println(response);
}
Serial.println(response.length());
}
out put of this code.
{"id": "_60_1_94_f_a9_3c_","version": "1.10","command": "0","message": ""}
Data sent...Reading response..
HTTP/1.1 400 Bad Request
Date: Sat, 20 May 2017 05:13:41 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Length: 324
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at ubuntu-512mb-nyc2-01.localdomain Port 80</address>
</body></html>
===========================================================
And one one more thing i have observed that. it runs GET request fine. only it cause issue while making POST request on my hosted server.
I guess that API service requires POST content and body to be application/x-www-form-urlencoded encoded.
application/x-www-form-urlencoded or multipart/form-data?

What is wrong with this HttpWebRequest/HttpWebResponse code (why is it considered a "bad" request (400))? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Based on the info from this MS link, I've got the following code in a Windows CE / Compact Framework app which calls a REST method in a Web API server app:
public static string SendXMLFile2(string uri, string data)
{
//TODO: Remove below after testing
String s = data.Substring(0, 128);
MessageBox.Show(String.Format("data length is {0}, uri is {1}, first part is {2}", data.Length, uri, s));
//TODO: Remove above after testing
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest.AllowWriteStreamBuffering=false;
myHttpWebRequest.Method="POST";
UTF8Encoding encodedData = new UTF8Encoding();
//ASCIIEncoding encodedData=new ASCIIEncoding();
byte[] byteArray=encodedData.GetBytes(data);
//myHttpWebRequest.ContentType="application/x-www-form-urlencoded";
myHttpWebRequest.ContentType = "application/xml";
myHttpWebRequest.ContentLength=byteArray.Length;
Stream newStream=myHttpWebRequest.GetRequestStream();
newStream.Write(byteArray,0,byteArray.Length);
newStream.Close();
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
return myHttpWebResponse.StatusDescription;
}
What I see is:
...and then I get, "The remote server returned an error: (400) Bad Request." The breakpoint in my REST method (on the server) is not even reached when this exception is thrown/returned.
Why? What do I have to change in the code to get the "bad" request to be considered "good"?
UPDATE
To answer mrchief, here's the server code:
[Route("api/inventory/sendXML/{userId}/{pwd}/{filename}")]
public async void SendInventoryXML(String userId, String pwd, String fileName)
{
XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
String saveLoc = String.Format(#"C:\HDP\{0}.xml", fileName);
doc.Save(saveLoc);
}
Yes, I'm ignoring userId and pwd for now.
UPDATE 2
Plugging this:
http://192.168.125.50:21608/api/inventory/sendXML/duckbilled/platypus/INV_bla.xml
...into Postman, I get:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii">
</HEAD>
<BODY>
<h2>Bad Request - Invalid Hostname</h2>
<hr>
<p>HTTP Error 400. The request hostname is invalid.</p>
</BODY>
</HTML>
??? This same uri works fine when I call it from a Winforms app created in Visual Studio 2013. Well, actually, I use localhost instead there. I get the same response as above if I use the host name instead of the IP Address. But if I use localhost from PostMan:
http://localhost:21608/api/inventory/sendXML/duckbilled/platypus/INV_bla.xml
I get:
<!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>
<title>IIS 8.0 Detailed Error - 404.0 - Not Found</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;}
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;}
.config_source code{font-size:.8em;color:#000000;}
pre{margin:0;font-size:1.4em;word-wrap:break-word;}
ul,ol{margin:10px 0 10px 5px;}
ul.first,ol.first{margin-top:5px;}
fieldset{padding:0 15px 10px 15px;word-break:break-all;}
.summary-container fieldset{padding-bottom:5px;margin-top:4px;}
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;}
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px;
font-weight:bold;font-size:1em;}
a:link,a:visited{color:#007EFF;font-weight:bold;}
a:hover{text-decoration:none;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;}
h4{font-size:1.2em;margin:10px 0 5px 0;
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif;
color:#FFF;background-color:#5C87B2;
}#content{margin:0 0 0 2%;position:relative;}
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
.content-container p{margin:0 0 10px 0;
}#details-left{width:35%;float:left;margin-right:2%;
}#details-right{width:63%;float:left;overflow:hidden;
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF;
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal;
font-size:1em;color:#FFF;text-align:right;
}#server_version p{margin:5px 0;}
table{margin:4px 0 4px 0;width:100%;border:none;}
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;}
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;}
thead th{background-color:#ebebeb;width:25%;
}#details-right th{width:20%;}
table tr.alt td,table tr.alt th{}
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;}
.clear{clear:both;}
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;}
-->
</style>
</head>
<body>
<div id="content">
<div class="content-container">
<h3>HTTP Error 404.0 - Not Found</h3>
<h4>The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.</h4>
...??? Is it just because this is a POST that is supposed to have an XML file attached, and because it's not there, it gets consumed with confusion?
UPDATE 3
I see the "." in "INV_bla.xml" was confusing PostMan. If I remove it, so that the URI is "http://localhost:21609/api/inventory/sendXML/duckbilled/platypus/INV_bla", I get instead a 500 err msg and:
<!DOCTYPE html>
<html>
<head>
<title>Root element is missing.</title>
<meta name="viewport" content="width=device-width" />
<style>
body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}
p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
pre {font-family:"Consolas","Lucida Console",Monospace;font-size:11pt;margin:0;padding:0.5em;line-height:14pt}
.marker {font-weight: bold; color: black;text-decoration: none;}
.version {color: gray;}
.error {margin-bottom: 10px;}
.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
#media screen and (max-width: 639px) {
pre { width: 440px; overflow: auto; white-space: pre-wrap; word-wrap: break-word; }
}
#media screen and (max-width: 479px) {
pre { width: 280px; }
}
</style>
</head>
<body bgcolor="white">
<span>
<H1>Server Error in '/' Application.
<hr width=100% size=1 color=silver>
</H1>
<h2>
<i>Root element is missing.</i>
</h2>
</span>
<font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">
<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
<br>
<br>
<b> Exception Details: </b>System.Xml.XmlException: Root element is missing.
<br>
<br>
<b>Source Error:</b>
<br>
<br>
<table width=100% bgcolor="#ffffcc">
<tr>
<td>
<code>
<pre>
Line 29: public async void SendInventoryXML(String userId, String pwd, String fileName)
Line 30: {
<font color=red>Line 31: XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
</font>Line 32: String saveLoc = String.Format(#"C:\HDP\{0}.xml", fileName);
Line 33: doc.Save(saveLoc);
</pre>
</code>
</td>
</tr>
</table>
<br>
<b> Source File: </b> c:\Project\git\CStore\HHS.Web\Controllers\InventoryXMLController.cs
<b> Line: </b> 31
<br>
<br>
<b>Stack Trace:</b>
<br>
<br>
<table width=100% bgcolor="#ffffcc">
<tr>
<td>
<code>
<pre>
[XmlException: Root element is missing.]
System.Xml.XmlTextReaderImpl.Throw(Exception e) +69
System.Xml.XmlTextReaderImpl.ParseDocumentContent() +305
System.Xml.XmlTextReaderImpl.Read() +213
System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options) +44
System.Xml.Linq.XDocument.Load(Stream stream, LoadOptions options) +57
System.Xml.Linq.XDocument.Load(Stream stream) +6
HHS.Web.Controllers.<SendInventoryXML>d__0.MoveNext() in c:\Project\git\CStore\HHS.Web\Controllers\InventoryXMLController.cs:31
System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__0(Object state) +50
System.Web.<>c__DisplayClass7.<Post>b__6() +15
System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action) +91
</pre>
</code>
</td>
</tr>
</table>
<br>
<hr width=100% size=1 color=silver>
<b>Version Information:</b> Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18446
</font>
</body>
</html>
<!--
[XmlException]: Root element is missing.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
at System.Xml.Linq.XDocument.Load(Stream stream, LoadOptions options)
at System.Xml.Linq.XDocument.Load(Stream stream)
at HHS.Web.Controllers.InventoryXMLController.<SendInventoryXML>d__0.MoveNext() in c:\Project\git\CStore\HHS.Web\Controllers\InventoryXMLController.cs:line 31
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__0(Object state)
at System.Web.AspNetSynchronizationContext.<>c__DisplayClass7.<Post>b__6()
at System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action)
-->
UPDATE 4
With this code (following Brinn's suggestion):
String datta = "<Content></Content>";
String s = SendXMLFile2(uri, datta);
MessageBox.Show(s); // TODO: Remove or comment out after testing
...I still get a 400 error.
UPDATE 5
There is ONE permutation that actually works in Postman to the extent that I reach the breakpoint in the server code (http://localhost:21608/api/inventory/sendXML/duckbill/platypus/INV_bla). However, when I hit F10 to step from the "XDocument doc = ..." line to the "String saveLoc = ..." line, the "Root element is missing" exception is thrown (the one shown above in all its gory glory).
I cannot use that exact same URI in my app, though, as "localhost" is URI-non-grata there.
UPDATE 6
Grasping at straws, I even tried this:
String xmlHeader = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
String crlf = "\r\n";
String datta = "<Content></Content>";
data = xmlHeader + crlf + datta + crlf;
String s = SendXMLFile2(uri, data);
...but the "400 Bad Request" err remains, causing me to rue the day I decided to hang up my spurs.
UPDATE 7
Even when I add an XML file in Postman, I get an error (500 - Internal Server Error):
UPDATE 8
Even with the code straight from the Wigley's mouth (from p. 358 of "Microsoft .NET Compact Framework"):
public static string SendXMLFile2(string uri, string data)
{
WebRequest req = WebRequest.Create(uri);
req.Method = "Post";
req.ContentType = "text/plain; charset=utf-8";
// Encode the data
byte[] encodedBytes = Encoding.UTF8.GetBytes(data);
req.ContentLength = encodedBytes.Length;
// Write encoded data into request stream
Stream requestStream = req.GetRequestStream();
requestStream.Write(encodedBytes, 0, encodedBytes.Length);
requestStream.Close();
WebResponse result = req.GetResponse();
return result.ToString();
}
...I get the "400 - Bad Request" err.
Is it possibly the data - the contents of the XML file - that is throwing a spanner/monkey wrench into the works?
Here's what that looks like (excerpt, with the great middle section elided):
<?xml version="1.0" encoding="utf-8"?>
<Command>
<INV>
<line_id>1</line_id>
<ref_no>valerie</ref_no>
<upc_code>79997000331</upc_code>
<description>ffff</description>
<department>2</department>
<vendor_id>1</vendor_id>
<upc_pack_size>1</upc_pack_size>
<id>79997000331</id>
<pack_size>1</pack_size>
<unit_cost>0</unit_cost>
<unit_list>0</unit_list>
<unit_qty>9</unit_qty>
<new_item>-1</new_item>
</INV>
<INV>
<line_id>2</line_id>
<ref_no>valerie</ref_no>
<upc_code>81127600412</upc_code>
<description>SLV EAG FF 100 BX</description>
<department>2.01</department>
<vendor_id>1</vendor_id>
<upc_pack_size>1</upc_pack_size>
<id>81127600412</id>
<pack_size>1</pack_size>
<unit_cost>0</unit_cost>
<unit_list>0</unit_list>
<unit_qty>9</unit_qty>
<new_item>0</new_item>
</INV>
. . .
<INV>
<line_id>3277</line_id>
<ref_no>valerie</ref_no>
<upc_code>00980000007</upc_code>
<description>TICTAC</description>
<department>8.8</department>
<vendor_id />
<upc_pack_size>1</upc_pack_size>
<id>00980000007</id>
<pack_size>1</pack_size>
<unit_cost>2</unit_cost>
<unit_list>3.55</unit_list>
<unit_qty>0</unit_qty>
<new_item>0</new_item>
</INV>
</Command>
UPDATE 9
I get "The remote server returned an error: (400) Bad Request" in my app. Now I do see two interesting entries in Fiddler: There are two 404s that display in Fiddler which
have "Host" vals of "localhost:21609" and "localhost:21608" (which relate to the REST calls in question), and "URL" values of /favicon.ico ... ???
What in red blazes is that about? They have a "Body" value of 4,905, a "Caching" value of "private" and "Content-Type" of text/html; charset=utf8
Why is favicon.ico problematic or even considered here?
UPDATE 10
This is Fiddler's "Log" tab contents for my "faked" call to the REST method (using Composer to add my POST URI and upload an XML file):
09:14:20:9657 [WebSocket #1439] Read from Server failed... Object reference not set to an instance of an object.
09:23:19:7275 /Fiddler.CertMaker> Invoking makecert.exe with arguments: -pe -ss my -n "CN=www.google-analytics.com, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com" -sky exchange -in DO_NOT_TRUST_FiddlerRoot -is my -eku 1.3.6.1.5.5.7.3.1 -cy end -a sha1 -m 132 -b 09/03/2013
09:23:20:1296 /Fiddler.CertMaker>64-CreateCert(www.google-analytics.com) => (0).
09:25:45:6411 [Fiddler] No HTTP request was received from (chrome:1384) new client socket, port 4235.
09:25:55:6411 [Fiddler] No HTTP request was received from (chrome:1384) new client socket, port 4241.
09:36:35:6681 [WebSocket #1473] Read from Client returned error: 0
09:36:35:7491 [WebSocket #1473] Read from Server returned error: 0
09:37:45:4031 [WebSocket #1552] Read from Client returned error: 0
09:37:45:4861 [WebSocket #1552] Read from Server returned error: 0
09:37:51:8077 [WebSocket #1575] Read from Client returned error: 0
09:37:51:8877 [WebSocket #1575] Read from Server returned error: 0
I would think maybe the "Object reference not set to an instance of an object" is indicating something in my server code might be the problem - but the key part of that is not even reached...is the fact that I'm calling async/await code in the server a possible cause of my woes???
UPDATE 11
With the only change being that "21609" becomes "21608" in my URL, Fiddler now gives me a "500" ("Internal Server Error") Result (when using 21609 I got "204" Result, but it didn't work).
With this port number, the real "meat and potatoes" code is reached on the server (the async/await code that calls XDocument.Load(), etc.
Fiddler's Inspectors.WebView tab shows me:
Is the problem that this xml does not start off with this line:
<?xml version="1.0" encoding="utf-8"?>
...and is thus not seen as valid/real XML?
UPDATE 12
Nope - even with a file that contains that xml starting line, it fails in the same way...
UPDATE 13
So depending on the client used, I get different results:
From the handheld device, I get a "/favicon.ico" err in Fiddler.
From Fiddler itself (using the "Composer" tab) I get, "Data at the root level is invalid. Line 1, position 1"
From a test Winforms app, the code works (the expected file is populated and saved where it should be) but there is no trace in Fiddler that an HTTP call was even made (there is no entry/evidence for it)...???
UPDATE 14
The server app does have this in Global.asax.cs:
RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
...so...what's the problem?
UPDATE 15
I notice that I can get trace log files generated by my server app from this location: C:\Users\\Documents\IISExpress\TraceLogFiles\
Looking there, I find the proverbial boatload of information (overload?), such as:
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<!-- saved from url=(0014)about:internet -->
<failedRequest url="http://localhost:21609/"
siteId="40"
appPoolId="Clr4IntegratedAppPool"
processId="10580"
verb="GET"
remoteUserName=""
userName=""
tokenUserName="SSCS\clay"
authenticationType="anonymous"
activityId="{00000000-0000-0000-1D00-0080020000ED}"
failureReason="STATUS_CODE"
statusCode="200"
triggerStatusCode="403.14"
timeTaken="62"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
. . .
What strikes me is the verb "GET" - this is a "POST" not a "GET" - or am I misunderstanding the meaning of the "verb" member?
UPDATE 16
I tested three different ways of calling the REST method, examining what was happening as best as I could using Fiddler and the trace log files that the server creates.
The only successful calling and execution of the server code (receiving the file, and then saving it to disk) occurred with the Winforms (Visual Studio 2013, .NET 4) app.
Here are some details gleaned from those three attempts:
[a] EXE on handheld device:
400 - Bad Request
breakpoint in server Controller code NOT reached
No activity seen in Fiddler
Summary: Fails - server is reached, but returns err msg
Pertinent contents of Log Trace file:
[ no log trace file created ]
[b] Test Winforms app:
breakpoint in server Controller code IS reached
No activity seen in Fiddler (?!?)
Method works - file is created by server code with the data it should have
Summary: works, but is "invisible" to Fiddler
Pertinent contents of Log Trace file:
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<!-- saved from url=(0014)about:internet -->
<failedRequest url="http://localhost:21608/api/inventory/sendXML/duckbill/Platypus/DSD_42314_3_20140310140842828" siteId="41" appPoolId="Clr4IntegratedAppPool" processId="8916"
verb="POST"
remoteUserName=""
userName=""
tokenUserName="NRBQ\clay"
authenticationType="anonymous"
activityId="{00000000-0000-0000-5D00-0080000000F6}"
failureReason="STATUS_CODE"
statusCode="204"
triggerStatusCode="204"
timeTaken="3666"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
[c] Fiddler "Composer"
breakpoint in server Controller code IS reached
Activity IS seen in Fiddler
Result = 500 ("Internal Server Error")
Summary: Gets further than the handheld, but fails
Pertinent contents of Log Trace file:
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<!-- saved from url=(0014)about:internet -->
<failedRequest url="http://localhost:21608/api/inventory/sendXML/duckbill/platypus/INV_bla"
siteId="41"
appPoolId="Clr4IntegratedAppPool"
processId="8916"
verb="POST"
remoteUserName=""
userName=""
tokenUserName="NRBQ\clay"
authenticationType="anonymous"
activityId="{00000000-0000-0000-4800-0080060000F6}"
failureReason="STATUS_CODE"
statusCode="500"
triggerStatusCode="204"
timeTaken="2964"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
UPDATE 17
Could it be that my encoding is wrong? It seems that might be the case, based on what I read here when researching the err msg I get ("Data at the root level is invalid. Line 1, position 1.")
This is what I'm doing in the client:
WebRequest req = WebRequest.Create(uri);
req.Method = "Post";
req.ContentType = "text/plain; charset=utf-8";
byte[] encodedBytes = Encoding.UTF8.GetBytes(data);
Should ContentType be "application/xml" or "application/x-www-form-urlencoded" (or something else) instead?
and/or should Encoding be something other than UTF8?
UPDATE 18
I noticed in C:\Users\clay\Documents\IISExpress\TraceLogFiles\ that I was getting a "403.14":
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<!-- saved from url=(0014)about:internet -->
<failedRequest url="http://localhost:21609/"
siteId="40"
appPoolId="Clr4IntegratedAppPool"
processId="1572"
verb="GET"
remoteUserName=""
userName=""
tokenUserName="SSCS\clay"
authenticationType="anonymous"
activityId="{00000000-0000-0000-0200-0080060000EB}"
failureReason="STATUS_CODE"
statusCode="200"
triggerStatusCode="403.14"
timeTaken="904"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
Which, according to this and more specifically this indicates "Directory listing denied."
Thinking this may be the crux of the problem, I researched what to do about a 403.14, and I followed Method 1 here, which is entitled "Add a default document (Recommended)" but actually contains the steps to "Enable the Directory Browsing feature in IIS"
But I still get the same triggerStatusCode ("403.14") in C:\Users\clay\Documents\IISExpress\TraceLogFiles\
So I was going to try the other method, too, but I already had a default document, so enable was not an option there (disable was).
Finally, I went with the final option, of updating the IIS Express config:
While that made the web pages look better when running the server (the 403.14 was replaced with a "localhost - /" dir listing), it made no difference when the client app attempted to send the XML file to the server. So, this last changed "fixed" the pages that display in the browser when the server is started, but I'm still seeing the "403.14" problem in the Trace log files when I try to access the server from my client app...???
UPDATE 19
With the latest change (setting the IIS config), the Trace log no longer has the "403.14":
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='freb.xsl'?>
<failedRequest url="http://localhost:21609/"
. . .
verb="GET"
. . .
failureReason="STATUS_CODE"
statusCode="200"
triggerStatusCode="200"
timeTaken="78"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
...so I guess the "400 - Bad Request" error I get from the server when calling it from the client is unrelated to this erstwhile 403.14 error. Note, too, that it the "failedRequest" is some "GET" operation (whereas my failing call from the client is an HttpPost). What is failing here I don't know, as statusCode 200 is, in fact, "OK"
The first time (only) that I start the server (or start and then call the server from the client), I get a 404 for a missing favicon, but that doesn't seem to really be a problem.
UPDATE 20
The solution was to add at a command prompt either this:
netsh http add urlacl url=http://shannon2:80/ user=everyone
...or the same for port 8080 instead of 80.
See Update 5 here.
It could, frankly, be a number of things. If the service is hosted on IIS, and you have IE, then, being a REST service, navigate to that URI, and you should get a 400.xx error. The xx part is clarified here

wcf service doesn't allow POST

I'm quite new to webervices in general and am getting stuck in (I think) configuring IIS and the webservice itself.
I created a wcf webservice in MVS 2010 and hosted it on IIS7.5 on windows 7.
I use soapUI 4.5.0 to post a message generated from the same wsdl description I created the webservice contract with. Issue is that I get 405 due to the fact that http POST not seems to be supported by the webservice or webserver.
Even though I had the idea the error I get would be sufficient to solve my problem, my lack of knowledge about IIS and webservices makes I can't find the right solution.
Below as much information as I could think of. Hope it is of any help and someone can guide me in the right direction.
Configurations made in IIS:
Authorization rule: allow, all users
Directory browsing: enabled
Handler mappings: features permissions: read, script and execute
Handler mappings: added *.wsdl -> ProtocolSupportModule -> GET, HEAD, OPTIONS, TRACE, POST
Application pools: added entry with identity NetworkService using
.net fw 4.0
This is the message sent:
RAW:
POST http: x.x.x.x:21378/ HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="/BootNotification"
XML:
<soap:Envelope xmlns:soap="org/2003/05/soap-envelope" xmlns:ns="urn://Ocpp/Cs/2012/02/">
<soap:Header/>
<soap:Body>
<ns:bootNotificationResponse>
<ns:status>Accepted</ns:status>
<ns:currentTime>${now}</ns:currentTime>
<ns:heartbeatInterval>900</ns:heartbeatInterval>
</ns:bootNotificationResponse>
</soap:Body>
</soap:Envelope>
This is the result returned:
I truncated it to limit the size of this post.
RAW:
HTTP/1.1 405 Method Not Allowed
Cache-Control: private
Allow: GET, HEAD, OPTIONS, TRACE
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Thu, 07 Jun 2012 07:58:09 GMT
Content-Length: 5611
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns=".org/1999/xhtml">
<head>
<title>IIS 7.5 Detailed Error - 405.0 - Method Not Allowed</title>
<style type="text/css">
...
...
...
<div class="content-container">
<fieldset><legend>Most likely causes:</legend>
<ul> <li>The request sent to the Web server used an HTTP verb that is not allowed by the module configured to handle the request.</li> <li>A request was sent to the server that contained an invalid HTTP verb.</li> <li>The request is for static content and contains an HTTP verb other than GET or HEAD.</li> <li>A request was sent to a virtual directory using the HTTP verb POST and the default document is a static file that does not support HTTP verbs other than GET or HEAD.</li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><legend>Things you can try:</legend>
<ul> <li>Verify the list of verbs enabled for the module handler this request was sent to, and ensure that this verb should be allowed for the Web site.</li> <li>Check the IIS log file to see which verb is not allowed for the request.</li> <li>Create a tracing rule to track failed requests for this HTTP status code. For more information about creating a tracing rule for failed requests, click here. </li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><legend>Links and More Information</legend>
This error means that the request sent to the Web server contained an HTTP verb that is not allowed by the configured module handler for the request.
<p>View more information »</p>
</fieldset>
</div>
</div>
</body>
</html>
XML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ".org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns=".org/1999/xhtml">
<head>
<title>IIS 7.5 Detailed Error - 405.0 - Method Not Allowed</title>
<style type="text/css">
...
</head>
<body>
<div id="header"><h1>Server Error in Application "SHENZIWEBSERVICEDEPLOYED"</h1></div>
<div id="server_version"><p>Internet Information Services 7.5</p></div>
<div id="content">
<div class="content-container">
<fieldset><legend>Error Summary</legend>
<h2>HTTP Error 405.0 - Method Not Allowed</h2>
<h3>The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used.</h3>
</fieldset>
</div>
<div class="content-container">
...
</div>
<div class="content-container">
<fieldset><legend>Most likely causes:</legend>
<ul> <li>The request sent to the Web server used an HTTP verb that is not allowed by the module configured to handle the request.</li> <li>A request was sent to the server that contained an invalid HTTP verb.</li> <li>The request is for static content and contains an HTTP verb other than GET or HEAD.</li> <li>A request was sent to a virtual directory using the HTTP verb POST and the default document is a static file that does not support HTTP verbs other than GET or HEAD.</li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><legend>Things you can try:</legend>
<ul> <li>Verify the list of verbs enabled for the module handler this request was sent to, and ensure that this verb should be allowed for the Web site.</li> <li>Check the IIS log file to see which verb is not allowed for the request.</li> <li>Create a tracing rule to track failed requests for this HTTP status code. For more information about creating a tracing rule for failed requests, click here. </li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><legend>Links and More Information</legend>
This error means that the request sent to the Web server contained an HTTP verb that is not allowed by the configured module handler for the request.
<p>View more information »</p>
</fieldset>
</div>
</div>
</body>
</html>
This is part of the generated servicecontract (wsdl /language:CS /serverInterface
// CODEGEN: The optional WSDL extension element 'PolicyReference' from namespace 'http://schemas.xmlsoap.org/ws/2004/09/policy' was not handled.
[ServiceContract(Name = "CentralSystemServiceSoap", Namespace = "urn://Ocpp/Cs/2010/08/")]
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.Web.Services.WebServiceBindingAttribute(Name="CentralSystemServiceSoap", Namespace="urn://Ocpp/Cs/2010/08/")]
public interface ICentralSystemServiceSoap {
/// <remarks/>
[OperationContract]
[System.Web.Services.Protocols.SoapHeaderAttribute("chargeBoxIdentity")]
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("/BootNotification", RequestElementName = "bootNotificationRequest", RequestNamespace = "urn://Ocpp/Cs/2010/08/", ResponseElementName = "bootNotificationResponse", ResponseNamespace = "urn://Ocpp/Cs/2010/08/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("status")]
RegistrationStatus BootNotification(string chargePointVendor, string chargePointModel, string chargePointSerialNumber, string chargeBoxSerialNumber, string firmwareVersion, string iccid, string imsi, string meterType, string meterSerialNumber, out System.DateTime currentTime, [System.Xml.Serialization.XmlIgnoreAttribute()] out bool currentTimeSpecified, out int heartbeatInterval, [System.Xml.Serialization.XmlIgnoreAttribute()] out bool heartbeatIntervalSpecified);
I didn't understand how your service is built and what you have done there, but from my experience, this is a simple way to create a wcf RESTful service that supports POST requests:
http://www.codeproject.com/Articles/201901/CREATE-RESTful-WCF-Service-API-Using-POST-Step-By
Update according to the comments:
try using that:
[OperationContract]
[WebInvoke(Method = "POST")]
[System.Web.Services.Protocols.SoapHeaderAttribute("chargeBoxIdentity")]
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("/BootNotification", RequestElementName = "bootNotificationRequest", RequestNamespace = "urn://Ocpp/Cs/2010/08/", ResponseElementName = "bootNotificationResponse", ResponseNamespace = "urn://Ocpp/Cs/2010/08/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("status")]
RegistrationStatus BootNotification(string chargePointVendor, string chargePointModel, string chargePointSerialNumber, string chargeBoxSerialNumber, string firmwareVersion, string iccid, string imsi, string meterType, string meterSerialNumber, out System.DateTime currentTime, [System.Xml.Serialization.XmlIgnoreAttribute()] out bool currentTimeSpecified, out int heartbeatInterval, [System.Xml.Serialization.XmlIgnoreAttribute()] out bool heartbeatIntervalSpecified);
UPDATE
try doing that:
On IIS 7.5 -> YourWebsite -> Handler Mappings
Choose "Add module mapping" option on the right side of the panel
In "Request path" field enter *.wsdl
In "Module" field enter "ProtocolSupportModule"
Click on "Request restrictions" and go to Verbs tab
Enter POST verb
Save changes