4

I have a Web API that worked perfectly on development with all kind of HTTP requests (on the same controller), once I moved it to production (shared server, I don't even have access to it) the DELETE requests stopped working (the others are working fine), I get a 404 error:

Requested URL https://www.example.com:443/Rejected-By-UrlScan~/API/Users/DeleteUser/1

Physical Path d:\xx\yy\example.com\Rejected-By-UrlScan

Logon Method Anonymous

Logon User Anonymous

This is (a part of) the web.config:

 <system.web>
    <customErrors mode="Off"/>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="WebDAVModule" />
    </modules>
    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>

The Delete Action:

[Authorize]
[RoutePrefix("Users")]
public class UsersController : ApiController
    {
    [HttpDelete]
    [Route("DeleteUser/{id:int}")]
    public void Delete(int id)
    {
        _UsersRepository.Delete(id);
    }

And the AJAX call:

deleteUser = function (id, callback) {
    $.ajax({
        url: "../API/Users/DeleteUser/" + id,
        type: "DELETE",
        success: function () {
            callback;
        }
    });
}

WebApiConfig.cs:

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Web API routes
        config.MapHttpAttributeRoutes();


        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        //create json formatter and remove all others
        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        jsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
        config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
        config.Formatters.Remove(config.Formatters.XmlFormatter);
    }

An example of a working call on the same Controller:

getUsers = function (callback) {
    $.get("../API/Users/GetUsers/", callback);
}

And the Action:

[Route("GetUsers")]
public IEnumerable<User> GetUsers()
{
    return _UsersRepository.GetUsers();
}
user3378165
  • 6,546
  • 17
  • 62
  • 101
  • Why did you access as anonymous though `UsersController` has `[Authorize]`? It's not strongly related to 404 issue but strange. – Youngjae Jul 13 '17 at 07:09
  • @Youngjae I'm using a `bearer token` and I see it set up properly in my headers, not sure why it has "anonymous".. I think the 404 error occurs because of the `Rejected-By-UrlScan` that causes the url to change but I don't know what to do about it, would you know? – user3378165 Jul 13 '17 at 07:18
  • I have no idea, but it would be good to post your `WebApiConfig.cs` or `Startup.cs` also. – Youngjae Jul 13 '17 at 07:20
  • @Youngjae I posted it, thank you. – user3378165 Jul 13 '17 at 08:16

3 Answers3

5

In your IIS do you have the URLScan extension configured ?

https://www.iis.net/downloads/microsoft/urlscan

UrlScan is a security tool that restricts the types of HTTP requests that IIS will process.

The "Rejected-By-UrlScan" in your URL suggests that the extension may be configured to reject "Delete" requests.

You can ask your Administrator of the Server hosting the IIS about whether Delete requests are configured to be allowed in the IIS.

Subbu
  • 2,130
  • 1
  • 19
  • 28
1

The URL is wrong in the JS snippet. It should be

deleteUser = function (id, callback) {
    $.ajax({
        url: "[Application_Path]/Users/DeleteUser/" + id,
        type: "DELETE",
        success: function () {
            callback;
        }
    });
}

[RoutePrefix("Users")] overrides the default routing, so there should be no "API" in the URL.

You should remove the [Application_Path] and put your virtual directory name or use the @Url.Action

Haitham Shaddad
  • 4,336
  • 2
  • 14
  • 19
0

I had to got it to work so I changed the type of the request from DELETE to POST and it works perfectly:

[Authorize]
[RoutePrefix("Users")]
public class UsersController : ApiController
    {
    [HttpPost]
    [Route("DeleteUser/{id:int}")]
    public void Delete(int id)
    {
        _UsersRepository.Delete(id);
    }

deleteUser = function (id, callback) {
    $.ajax({
        url: "../API/Users/DeleteUser/" + id,
        type: "POST",
        success: function () {
            callback;
        }
    });
}
user3378165
  • 6,546
  • 17
  • 62
  • 101