75

I'm trying to get an API Controller to work inside an ASP.NET MVC 4 web app. However, every request results in a 404 and I'm stumped. :/

I have the standard API controller route from the project template defined like:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

The registration is invoked in Global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    // Register API routes
    WebApiConfig.Register(GlobalConfiguration.Configuration);

    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

I have a basic API controller like this:

namespace Website.Controllers
{
    public class FavoritesController : ApiController
    {       
        // GET api/<controller>
        public IEnumerable<string> Get()
        {
            return new [] { "first", "second" };
        }

        // PUT api/<controller>/5
        public void Put(int id)
        {

        }

        // DELETE api/<controller>/5
        public void Delete(int id)
        {

        }
    }
}

Now, when I browse to localhost:59900/api/Favorites I expect the Get method to be invoked, but instead I get a 404 status code and the following response:

<Error>
   <Message>
       No HTTP resource was found that matches the request URI 'http://localhost:59900/api/Favorites'.
   </Message>
   <MessageDetail>
      No type was found that matches the controller named 'Favorites'.
   </MessageDetail>
</Error>

Any help would be greatly appreciated, I'm losing my mind a little bit over here. :) Thanks!

Aliostad
  • 80,612
  • 21
  • 160
  • 208
Ted Nyberg
  • 7,001
  • 7
  • 41
  • 72
  • 2
    Have you tried testing your routes with Phil Haack's Route Tester? http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx – Robert Harvey Mar 21 '13 at 19:07
  • The route tester says the /api/Favorites request matches the api/{controller}/{id} route pattern. However, there are other external routes that match higher up in the list. Perhaps those routes are intercepting my requests... – Ted Nyberg Mar 21 '13 at 19:15
  • Cleared all other routes, still same result. :( – Ted Nyberg Mar 21 '13 at 19:20
  • why are you overriding Application_Start? By default that method will register what you have in your overridden method. Maybe the routes being registered twice is causing problems. – nitewulf50 Mar 21 '13 at 19:21
  • I have an abstract base class that I'm inheriting. I've tried skipping the inheritance, but the result remains the same. Thanks for the help, though! I'll edit the question to get rid of any confusion. :) – Ted Nyberg Mar 21 '13 at 19:23
  • From the error message, looks like its unable to find that 'type'. just to be sure, is your FavoritesController type part of another library and you have referenced it in your web application..right? – Kiran Mar 21 '13 at 19:43
  • it sounds like you've made some slight modifications from the default "HelloWorld" Web API. I'd suggest starting fresh and verify that the default ValuesController Get() works for you, then start modifying 1 piece at time testing as you go to find out what change you've made is causing your 404. – nitewulf50 Mar 21 '13 at 20:03
  • Kiran, the controller is actually part of the site, not a referenced assembly. Nitewulf, yeah, I guess I'll set up a blank MVC 4 project and see if I can get an ApiController to work in there ./ – Ted Nyberg Mar 22 '13 at 07:36
  • I had same issue - I'd deleted my controller class! – Chalky Jul 08 '15 at 09:38

22 Answers22

145

One thing I ran into was having my configurations registered in the wrong order in my GLobal.asax file for instance:

Right Order:

AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);

Wrong Order:

AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register(GlobalConfiguration.Configuration);

Just saying, this was my problem and changing the order is obvious, but sometimes overlooked and can cause much frustration.

Eric Bishard
  • 5,201
  • 7
  • 51
  • 75
  • 5
    After struggling for hours, found this answer... thanks a lot!! – Gokulnath Aug 12 '15 at 13:42
  • I love the fact that my answer has helped a lot of people in a thread where it wasn't marked as the right question and the question asker says there is nothing wrong with the code in his question. I'm suggesting him changing the order of this Global.asax and marking mine correct. lol jk! But I am glad it has helped others out! – Eric Bishard Aug 13 '15 at 00:48
  • 2
    I think that this answer is most up voted because people who come to this question are more than likely having the problem with the order as I have shown here how to do. But I don't think it is an answer to this question. I provided it as an alternate answer because I knew people coming here would most likely have the same problem I had. I do appreciate your request though! lol – Eric Bishard Oct 13 '15 at 21:15
  • Although this wasn't the solution to my specific problem, it seems to be the most helpful one. :) – Ted Nyberg Nov 09 '15 at 21:03
  • 1
    it's because RouteConfig has more universal route and it slams WebApiConfig's route? – Wachburn Feb 25 '16 at 15:12
  • Is that a statement or a question? – Eric Bishard Feb 25 '16 at 16:39
  • 2
    Just curious, in MVC5, the readme states after first creating an API controller to add in `GlobalConfiguration.Configure(WebApiConfig.Register);` on Global.asax.cs. I notice here that you have `WebApiConfig.Register(GlobalConfiguration.Configuration);`. Maybe I should just read the docs but does it make a difference which way you do it? – SomeShinyObject Sep 23 '17 at 02:47
  • 1
    @SomeShinyObject if we do it the way in the answer we have to add `GlobalConfiguration.Configuration.EnsureInitialized();`. Doing it as `GlobalConfiguration.Configure(WebApiConfig.Register);` we don't. – ᴍᴀᴛᴛ ʙᴀᴋᴇʀ Feb 05 '18 at 10:25
  • @Wachburn If you have `RouteConfig` ahead of `WebApiConfig`, even if you call a controller method assuming you are using the `WebApiConfig` route because you are inheriting from `ApiController`, you really are not. It routes it the way you've specified in `RouteConfig`, instead, and if the routes aren't the same, it can't find it, so you get a 404. – vapcguy Mar 30 '18 at 17:34
17

Had essentially the same problem, solved in my case by adding:

<modules runAllManagedModulesForAllRequests="true" />

to the

<system.webServer>

</system.webServer>

section of web.config

Zenilogix
  • 1,318
  • 1
  • 15
  • 31
  • 6
    I found that this helped me, but after doing more research I found that you should not enable this without understanding what it means. Looking at [this page on msdn](https://msdn.microsoft.com/en-us/library/cc668201.aspx) it says "If your website is running on IIS 7 and if IIS has been updated, you do not need to set runAllManagedModulesForAllRequests to true. In fact, **setting it to true is not recommended**". There is a [patch available](https://support.microsoft.com/en-us/kb/980368) that will make this setting unnecessary. – Kevin Harker Jan 26 '16 at 23:15
  • This fixed the issue of not being able to call a PATCH method in my project. – Jonathas Sucupira Jun 21 '22 at 20:48
13

I have been working on a problem similar to this and it took me ages to find the problem. It is not the solution for this particular post, but hopefully adding this will save someone some time trying to find the issue when they are searching for why they might be getting a 404 error for their controller.

Basically, I had spelt "Controller" wrong at the end of my class name. Simple as that!

user4796368
  • 139
  • 1
  • 2
  • 5
    We spent 45 minutes trying to find why an API controller was getting 404. Turns out the file has to end in "...Controller.cs". Your comment got us on track. Thanks! – Martyn Chamberlin May 08 '15 at 21:13
  • Thank you very much, been working with API on a number of projects, couldn't work out why this wasn't working when everything was set up correctly, read your post and checked, forgot to add "Controller" . Such a frustrating schoolboy error. Thank you. – Jon D Jan 14 '16 at 10:15
10

Add following line

GlobalConfiguration.Configure(WebApiConfig.Register);

in Application_Start() function in Global.ascx.cs file.

zajonc
  • 1,935
  • 5
  • 20
  • 25
Farhan Anwar
  • 101
  • 1
  • 4
  • 1
    If this code answers the question, consider adding adding some text explaining the code in your answer. This way, you are far more likely to get more upvotes — and help the questioner learn something new. – lmo Aug 27 '16 at 17:39
  • 1
    This solution worked for me with WebApi 2.0 however "WebApiConfig.Register(GlobalConfiguration.Configuration)" from the accepted answer threw an exception. – Balint Bako Feb 09 '17 at 10:56
  • whats the difference between WebApiConfig.Register(GlobalConfiguration.Configuration) and your answer? Why it was not added in app start when project was first created? – muhammad kashif Sep 19 '17 at 12:52
  • 1
    @BalintBako Depending on the exception you got, you might've just needed to import the namespace at the top of the page: `using System.Web.Http;` - I had to do this, and then adding `WebApiConfig.Register(GlobalConfiguration.Configuration);` was fine. And I had to go into the WebApiConfig class and set the namespace to not have `.App_Start` on it, so that Global.asax.cs didn't have to have `using MyProject.App_Start;` added to the top of the page. – vapcguy Mar 30 '18 at 17:16
  • best solution but need install ms web host or add ref. – udorb b Jan 12 '23 at 18:06
7

I had the same problem, then I found out that I had duplicate api controller class names in other project and despite the fact that the "routePrefix" and namespace and project name were different but still they returned 404, I changed the class names and it worked.

Aran Dekar
  • 461
  • 5
  • 12
  • I am so glad I read this. I too had everything separate but it returned 404. Changing the name of the controller fixed it. – VictorySaber Mar 12 '19 at 11:58
5

Similar problem with an embarrassingly simple solution - make sure your API methods are public. Leaving off any method access modifier will return an HTTP 404 too.

Will return 404:

List<CustomerInvitation> GetInvitations(){

Will execute as expected:

public List<CustomerInvitation> GetInvitations(){
BRass
  • 3,698
  • 2
  • 28
  • 46
4

For reasons that aren't clear to me I had declared all of my Methods / Actions as static - apparently if you do this it doesn't work. So just drop the static off

[AllowAnonymous]
[Route()]
public static HttpResponseMessage Get()
{
    return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}

Became:-

[AllowAnonymous]
[Route()]
public HttpResponseMessage Get()
{
    return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Morvael
  • 3,478
  • 3
  • 36
  • 53
3

Create a Route attribute for your method.

example

        [Route("api/Get")]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

You can call like these http://localhost/api/Get

Shakeer Hussain
  • 2,230
  • 7
  • 29
  • 52
  • 1
    Routing should be handled in the WebApiConfig automatically. This would only be needed if deviating from that pattern registered there. – vapcguy Mar 30 '18 at 17:20
3

Had this problem. Had to uncheck Precompile during publishing.

2

I'm a bit stumped, not sure if this was due to an HTTP output caching issue.

Anyways, "all of a sudden it started working properly". :/ So, the example above worked without me adding or changing anything.

Guess the code just had to sit and cook overnight... :)

Thanks for helping, guys!

Ted Nyberg
  • 7,001
  • 7
  • 41
  • 72
  • 4
    This sounds like "Build --> Clean" + "Build --> Rebuild" (and btw Rebuild does less than Clean+Build, Clean does more with temporary asp.net files cleanup) – Jon Davis Mar 11 '16 at 17:27
  • 1
    @JonDavis After a few hours of frustration...your comment helped me. The project I was working with was renamed in the past and it still had the old dll's in the folder. Build clean wouldn't clean them out but after I manually deleted them it's working now. – JeffR Dec 10 '18 at 19:36
2

I'm going to add my solution here because I personally hate the ones which edit the web.config without explaining what is going on.

For me it was how the default Handler Mappings are set in IIS. To check this...

  1. Open IIS Manager
  2. Click on the root node of your server (usually the name of the server)
  3. Open "Handler Mappings"
  4. Under Actions in the right pane, click "View ordered list"

This is the order of handlers that process a request. If yours are like mine, the "ExtensionlessUrlHandler-*" handlers are all below the StaticFile handler. Well that isn't going to work because the StaticFile handler has a wildcard of * and will return a 404 before even getting to an extensionless controller.

So rearranging this and moving the "ExtensionlessUrlHandler-*" above the wildcard handlers of TRACE, OPTIONS and StaticFile will then have the Extensionless handler activated first and should allow your controllers, in any website running in the system, to respond correctly.

Note: This is basically what happens when you remove and add the modules in the web.config but a single place to solve it for everything. And it doesn't require extra code!

k2snowman69
  • 1,849
  • 1
  • 14
  • 19
1

Check that if your controller class has the [RoutePrefix("somepath")] attribute, that all controller methods also have a [Route()] attribute set.

I've run into this issue as well and was scratching my head for some time.

Kevin R.
  • 3,571
  • 1
  • 19
  • 29
1
WebApiConfig.Register(GlobalConfiguration.Configuration);

Should be first in App_start event. I have tried it at last position in APP_start event, but that did not work.

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Ram
  • 11
  • 1
  • This is basically the same as the accepted answer, but wrong because it doesn't have to be first, just ahead of the `RouteConfig` registration, because if you call your API with a route you are using for `ApiController`, it will assume you are actually trying to route with whatever you registered for `Controller` in `RouteConfig`, instead. I won't downvote, because if someone actually does this, it will work, but the reasoning is not correct. – vapcguy Mar 30 '18 at 17:23
1

I found this in a comment here: https://andrewlock.net/when-asp-net-core-cant-find-your-controller-debugging-application-parts/

Add the following to your Program.cs:

app.UseRouting();

app.UseEndpoints(endpoints =>
{
// DP: I don't know the purpose of this, but without it, all controllers report 404
endpoints.MapControllerRoute("default", "WTF is this");
});

For me this is all it took to make it work after hours of trying to find a solution. If this doesnt work for you, try adding

builder.Services.AddControllers();
0

Add this to <system.webServer> in your web.config:

<handlers>
    <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>

Adding <modules runAllManagedModulesForAllRequests="true" /> also works but is not recommended due performance issues.

0

I have solved similar problem by attaching with debugger to application init. Just start webserver (for example, access localhost), attach to w3wp and see, if app initialization finished correctly. In my case there was exception, and controllers was not registered.

Pavel
  • 2,602
  • 1
  • 27
  • 34
0

I had the same 404 issue and none of the up-voted solutions here worked. In my case I have a sub application with its own web.config and I had a clear tag inside the parent's httpModules web.config section. In IIS all of the parent's web.config settings applies to sub application.

<system.web>    
  <httpModules>
    <clear/>
  </httpModules>
</system.web>

The solution is to remove the 'clear' tag and possibly add inheritInChildApplications="false" in the parent's web.config. The inheritInChildApplications is for IIS to not apply the config settings to the sub application.

<location path="." inheritInChildApplications="false">
  <system.web>
  ....
  <system.web>
</location>
0

I have dozens of installations of my app with different clients which all worked fine and then this one just always returned 404 on all api calls. It turns out that when I created the application pool in IIS for this client it defaulted to .net framework 2.0 instead of 4.0 and I missed it. This caused the 404 error. Seems to me this should have been a 500 error. Very misleading Microsoft!

nuander
  • 1,319
  • 1
  • 19
  • 33
0

I had this problem: My Web API 2 project on .NET 4.7.2 was working as expected, then I changed the project properties to use a Specific Page path under the Web tab. When I ran it every time since, it was giving me a 404 error - it didn't even hit the controller.

Solution: I found the .vs hidden folder in my parent directory of my VS solution file (sometimes the same directory), and deleted it. When I opened my VS solution once more, cleaned it, and rebuilt it with the Rebuild option, it ran again. There was a problem with the cached files created by Visual Studio. When these were deleted, and the solution was rebuilt, the files were recreated.

Tom
  • 11
  • 2
0

If you manage the IIS and you are the one who have to create new site then check the "Application Pool" and be sure the CLR version must be selected. In my situation, it had been selected "No Managed Code". After changed to v4.0 it started to work.

bafsar
  • 1,080
  • 2
  • 16
  • 16
0

i try above but not sucess all

add ms webhost and GlobalConfiguration.Configure(WebApiConfig.Register);

udorb b
  • 135
  • 3
0

If you are by any chance using the [Authorize] attribute, check if you are logged in. This was the problem in my case.

ProjectAlice
  • 71
  • 1
  • 4