7

Background

I have an MVC Application with a WebAPI component. I'm using jQuery and AJAX to pass and receive data from the WebAPI. I rely on the Application_BeginRequest being fired during each call to perform some mundane task.

Problem

Application_BeginRequest always fires for GET and POST calls to the WebAPI. However, when I make PUT call to the WebAPI, the Application_BeginRequest does not fire, causing the application to not run the task. The PUT call is actually received, because the corresponding method in the controller is being executed.

I have PUT enabled in my web.config file (below). How do I enable PUT method calls to trigger the Application_BeginRequest method?

Note : Application_BeginRequest fires for PUT calls when using IIS Express, but not when using the full version of IIS.

Project : The full project can be downloaded here : BeginRequestFail.zip

Web.Config

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
  </system.web>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="PassThrough">
      <remove statusCode="404" subStatusCode="-1" />
      <remove statusCode="403" subStatusCode="-1" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="404" path="/Error/404" responseMode="ExecuteURL" />
      <error statusCode="403" path="/Error/403" responseMode="ExecuteURL" />
      <error statusCode="500" path="/Error/500" responseMode="ExecuteURL" />
    </httpErrors>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <remove name="UrlRoutingModule-4.0" />
      <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
      <remove name="WebDAVModule"/>
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.Core" publicKeyToken="2780ccd10d57b246" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.AspNet" publicKeyToken="2780ccd10d57b246" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
      </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
        </dependentAssembly>
      </assemblyBinding>
  </runtime>
</configuration>

Global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e) //Not triggered with PUT
        {
            Application["BeginRequest"] = _Scounter++;
        }
Mark Barciak
  • 71
  • 1
  • 2
  • What Managed Pipeline Mode is set in IIS? – Alexandr Nikitin Sep 09 '14 at 07:00
  • The Managed Pipeline Mode is set to Integrated, and the .Net Framework is 4.0. – Mark Barciak Sep 09 '14 at 13:16
  • What versions of IIS? – Nathan Rice Sep 09 '14 at 19:34
  • The versions are IIS7 and 7.5 – Mark Barciak Sep 09 '14 at 20:26
  • Maybe I'm missing something, but it looks like your put call is being done in another application context. I'm not that familiar with WebAPI, but you have a separate application class for the api with no request event handler. – B2K Jan 13 '15 at 16:12
  • @B2K No - the application class in the API project is not used. I guess it was created as a web project initially, but now it's just referenced from the Web project as if it was a class library. – RobSiklos Jan 14 '15 at 16:17
  • I'd suggest one of two approaches here: Try using a webapi controller in BeginRequestFail directly, to see if the issue is related to the referenced dll. Or second, configure the api as a separate application. The first would be easy to test. See http://stackoverflow.com/questions/11990036/how-to-add-web-api-to-an-existing-asp-net-mvc-4-web-application-project?rq=1 for implementation details. – B2K Jan 14 '15 at 16:54
  • I've noticed that visual studio doesn't seem to care you set anonymousAuthentication in web.config, but IIS does. – Jim Crandall Jan 26 '15 at 20:52

2 Answers2

2

Go to IIS Features mode --> Click on Handler Mappings --> Scroll through the list and locate Extensionless URL Handler --> Check all handlers before that handler to see if any thing else is registetred to handler PUT request hence hijacking PUT before it hits extensionless url handler. Hope that helps

JOAT
  • 188
  • 7
0

Your code works. Not sure about your counter, so I changed it to:

public class MvcApplication : System.Web.HttpApplication
{
    public static int BeginRequestCounter = 0;

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        BeginRequestCounter++;
    }
}

(other code removed to point out what I changed)

<p>@BeginRequestFail.MvcApplication.BeginRequestCounter</p>

Keep in mind the counter on the page won't update when you do the AJAX calls - after a page refresh you'll see the counters have incremented correctly.

Not sure why you want to reference a WebApi project in an Mvc project though? I'd either keep them separate or join them into one to avoid any weirdness. Personally my WebApi would be completely separate as it shouldn't have anything to do with any other web app - at least that's the way I'd be designing my data API.

acarter
  • 55
  • 10