Answered by:
Getting a 405 on HEAD requests

Question
-
User-1608281605 posted
Hi all;
I have an WEB API 2 app running as an app service on Azure. Works fine for GET and POST calls. But HEAD calls return a 405. Any idea what I need to do?
thanks - dave
Sunday, January 20, 2019 5:50 PM
Answers
-
User475983607 posted
david@windward.net
So do you think this is WCF?The code snippet is certainly WCF. Can you explain the actual problem you are trying to solve? What URL should handle the HEAD request and why?
Let's assume the GetTest() method, then...
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1 : IService1 { [WebInvoke(Method ="*", ResponseFormat= WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "GetTest")] public string GetTest() { HttpRequestMessageProperty request = OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty; if (request != null) { if (!(request.Method == "GET" | request.Method == "HEAD")) { throw new WebFaultException(System.Net.HttpStatusCode.MethodNotAllowed); } } string AssmVersion = "1.2.3"; DateTime mostRecentTime = DateTime.Now; string mostRecentError = "Test Error"; return $"Windward update REST service version {AssmVersion}; " + $"Newest AutoTag version: {ConfigurationManager.AppSettings["AutoTagVersion"]}; -- " + $"Most recent exception {mostRecentTime:G} : {mostRecentError}"; }
I recommend that you read the Web API and go through a few tutorials so you have an idea what Web API looks like. You'll also want to go through the WCF Getting started tutorials so you know what WCF looks like.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/getting-started-tutorial
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/getting-started-sample
WCF is old, vast, and very complex... Here's the REST section.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/ajax-service-with-json-and-xml-sample
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, January 30, 2019 10:58 PM
All replies
-
User475983607 posted
Have you defined a head action?Sunday, January 20, 2019 6:19 PM -
User36583972 posted
Hi david,
Hi all;
I have an WEB API 2 app running as an app service on Azure. Works fine for GET and POST calls. But HEAD calls return a 405. Any idea what I need to do?
thanks - dave
When you debug on your development PC, there will be the same error?The HEAD method is almost identical to GET, except without the response body. In other words, if GET /users returns a list of users, then HEAD /users will make the same request but won't get back the list of users.
The following link may helpful for you.
Adding HTTP HEAD support to ASP.NET Web API
https://www.strathweb.com/2013/03/adding-http-head-support-to-asp-net-web-api/Besides, you can include all necessary code snippets for anyone else to be able to reproduce your issue from scratch along with a detailed description about the results including any exception messages or you can upload your demo to OneDrive. We can download it and debugging. This will help us quickly analyze your problem.
Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.
Best Regards,
Yong Lu
Monday, January 21, 2019 8:07 AM -
User-1608281605 posted
Hi Yohann;
Thank you for your reply. One follow-up question - where do I put:
config.MessageHandlers.Add(new HeadHandler());
I don't have any config object in my code. In Global.asax.cs (inherits from HttpApplication) I do have:
RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Service)));
??? - thanks - dave
Monday, January 21, 2019 5:38 PM -
User36583972 posted
Hi david,david@windward.net
Hi Yohann;
Thank you for your reply. One follow-up question - where do I put:
config.MessageHandlers.Add(new HeadHandler());
I don't have any config object in my code. In Global.asax.cs (inherits from HttpApplication) I do have:
RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Service)));
??? - thanks - dave
In Global.asax.cs file:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MessageHandlers.Add(new HeadHandler()); config.MapHttpAttributeRoutes(); //...................... } }
For more detailed:
Configuring ASP.NET Web API 2:
https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/configuring-aspnet-web-api
Best Regards,Yong Lu
Tuesday, January 22, 2019 1:30 AM -
User-1608281605 posted
Hi;
I'm worried as this is a major change from what I presently have and it may screw up my server. My entire Global.asax.cs is:
public class Global : HttpApplication { private static ILog log; void Application_Start(object sender, EventArgs e) { RegisterRoutes(); log4net.Config.XmlConfigurator.Configure(); log = LogManager.GetLogger(typeof(Global)); log.Info($"Update REST server version {VersionNumbers.VERSION_STR} started, running under user {WindowsIdentity.GetCurrent().Name}"); } private void RegisterRoutes() { // The class providing the REST service RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Service))); } void Application_End(object sender, EventArgs e) { log?.Info("update REST server closed"); } void Application_Error(object sender, EventArgs e) { log?.Error($"Application_Error({sender}, {e})"); } }
And my services are as follows:
public class Service { [WebInvoke(UriTemplate = "Service/version", Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)] public XmlElement GetVersion(XmlElement root) { // ... } }
Is adding the code you listed going to screw this up?
thanks - dave
Tuesday, January 22, 2019 7:28 PM -
User36583972 posted
Hi david,Hi;
I'm worried as this is a major change from what I presently have and it may screw up my server. My entire Global.asax.cs is:
public class Global : HttpApplication { private static ILog log; void Application_Start(object sender, EventArgs e) { RegisterRoutes(); log4net.Config.XmlConfigurator.Configure(); log = LogManager.GetLogger(typeof(Global)); log.Info($"Update REST server version {VersionNumbers.VERSION_STR} started, running under user {WindowsIdentity.GetCurrent().Name}"); } private void RegisterRoutes() { // The class providing the REST service RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Service))); } void Application_End(object sender, EventArgs e) { log?.Info("update REST server closed"); } void Application_Error(object sender, EventArgs e) { log?.Error($"Application_Error({sender}, {e})"); } }
And my services are as follows:
public class Service { [WebInvoke(UriTemplate = "Service/version", Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)] public XmlElement GetVersion(XmlElement root) { // ... } }
Is adding the code you listed going to screw this up?
thanks - dave
You can Register the HeadHandler in Application_Start method.
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { //------------------- GlobalConfiguration.Configure(RegisterHeadHandler); } public static void RegisterHeadHandler(HttpConfiguration config) { config.MessageHandlers.Add(new HeadHandler()); } }
Besides, as you have tips, you are worried as this is a major change from what you presently have and it may screw up your server. So, I suggest you need to contact with your development team and make a test on your side.
Best Regards,
Yong Lu
Wednesday, January 23, 2019 1:49 AM -
User-1608281605 posted
GlobalConfiguration is in the System.Web.Http namespace. I can't find that in the assemblies presented in Visual Studio. Do I need to load some optional module to get it? And I'm running in an Azure App Service - that will work there - correct?
Besides, as you have tips, you are worried as this is a major change from what you presently have and it may screw up your server. So, I suggest you need to contact with your development team and make a test on your side.
I am the dev team for this.
thanks - dave
Wednesday, January 30, 2019 5:22 PM -
User475983607 posted
As I understand Web API does not handle HTTP HEAD by default which is why you are getting the 405. Did you follow my advice and add a Head Action to your controllers?
[HttpHead] public void Head() { }
Or
[HttpGet] [HttpHead] public string Get() { return "Hello World"; }
The other suggestions above are adding a global Head handler.
Wednesday, January 30, 2019 7:27 PM -
User-1608281605 posted
Hi mgebhard;
I'm sorry, I don't think there was an earlier post about [HttpHead] - I can't find it.
Will this work to add it when I presently have:
[WebGet(UriTemplate = "")] public string GetTest() { return $"Windward update REST service version {AssmVersion}; " + $"Newest AutoTag version: {ConfigurationManager.AppSettings["AutoTagVersion"]}; -- " + $"Most recent exception {mostRecentTime:G} : {mostRecentError}"; }
??? - thanks - dave
ps - All the stuff the WebAPI does for you is great, except when I need something done in the connection and it's not clear what to do.
Wednesday, January 30, 2019 8:20 PM -
User475983607 posted
I'm sorry, I don't think there was an earlier post about [HttpHead] - I can't find it.I asked if you defined a Head Action. The [HttpHead] attribute is what maps an action method to a route and HTTP action in Web API 2.
Will this work to add it when I presently have:
[WebGet(UriTemplate = "")] public string GetTest() { return $"Windward update REST service version {AssmVersion}; " + $"Newest AutoTag version: {ConfigurationManager.AppSettings["AutoTagVersion"]}; -- " + $"Most recent exception {mostRecentTime:G} : {mostRecentError}"; }
I can't answer the question because there are several unknown variables.
Also this construct...
[WebGet(UriTemplate = "")]
is used in WCF System.ServiceModel.Web not Web API 2. Is this really a WCF application and not Web API 2 as originally stated? Can you explain the problem you are trying to solve? Why are Head requests causing issues?
ps - All the stuff the WebAPI does for you is great, except when I need something done in the connection and it's not clear what to do.IMHO, Web API is extremely clear and straight forward. Simply decorate the action method with one of the action selectors from System.Web.Http.
What's unclear is what technology you are actually implementing. It looks like WCF. I do agree that WCF is very complex though. Can you clarify?
Wednesday, January 30, 2019 8:47 PM -
User-1608281605 posted
Is this really a WCF application and not Web API 2 as originally stated?
I inherited this code and I was told it was Web API 2. But that could be wrong.
What I'm trying to do is handle HEAD requests because that is used to see if our RESTful service is alive. Everything else in it works fine, just need to add this.
The service.cs is (just the key parts):
[ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] // NOTE: If this class is renamed, remember to update the global.asax.cs file public class Service { [WebGet(UriTemplate = "")] public string GetTest() { return $"Windward update REST service version {AssmVersion}; " + $"Newest AutoTag version: {ConfigurationManager.AppSettings["AutoTagVersion"]}; -- " + $"Most recent exception {mostRecentTime:G} : {mostRecentError}"; } [WebInvoke(UriTemplate = "Service/version", Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)] public XmlElement GetVersion(XmlElement root) { // ... } }
And Global.asax.cs is:
public class Global : HttpApplication { private static ILog log; void Application_Start(object sender, EventArgs e) { RegisterRoutes(); log4net.Config.XmlConfigurator.Configure(); log = LogManager.GetLogger(typeof(Global)); log.Info($"Update REST server version {VersionNumbers.VERSION_STR} started, running under user {WindowsIdentity.GetCurrent().Name}"); } private void RegisterRoutes() { // The class providing the REST service RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Service))); } void Application_End(object sender, EventArgs e) { log?.Info("update REST server closed"); } void Application_Error(object sender, EventArgs e) { log?.Error($"Application_Error({sender}, {e})"); } }
So do you think this is WCF?
thanks - dave
Wednesday, January 30, 2019 9:57 PM -
User475983607 posted
david@windward.net
So do you think this is WCF?The code snippet is certainly WCF. Can you explain the actual problem you are trying to solve? What URL should handle the HEAD request and why?
Let's assume the GetTest() method, then...
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1 : IService1 { [WebInvoke(Method ="*", ResponseFormat= WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "GetTest")] public string GetTest() { HttpRequestMessageProperty request = OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty; if (request != null) { if (!(request.Method == "GET" | request.Method == "HEAD")) { throw new WebFaultException(System.Net.HttpStatusCode.MethodNotAllowed); } } string AssmVersion = "1.2.3"; DateTime mostRecentTime = DateTime.Now; string mostRecentError = "Test Error"; return $"Windward update REST service version {AssmVersion}; " + $"Newest AutoTag version: {ConfigurationManager.AppSettings["AutoTagVersion"]}; -- " + $"Most recent exception {mostRecentTime:G} : {mostRecentError}"; }
I recommend that you read the Web API and go through a few tutorials so you have an idea what Web API looks like. You'll also want to go through the WCF Getting started tutorials so you know what WCF looks like.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/getting-started-tutorial
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/getting-started-sample
WCF is old, vast, and very complex... Here's the REST section.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/ajax-service-with-json-and-xml-sample
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, January 30, 2019 10:58 PM -
User-1608281605 posted
Ok - I guess this isn't an easy change.
Thank you for all the help.
Wednesday, January 30, 2019 11:24 PM -
User475983607 posted
Ok - I guess this isn't an easy change.What is not easy? Can you explain the requirements and what URL should handle the head request? For example, if the URL is /service then simply change the UriTemplate.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1 : IService1 { [WebInvoke(Method ="*", ResponseFormat= WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "/service")] public string GetTest()
Thursday, January 31, 2019 12:13 AM