locked
Getting a 405 on HEAD requests RRS feed

  • 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.

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-and-action-selection

    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