1

I have a web api solution with some models and controllers.

This is an example of my model:

public class Category
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
}

And this is his controller:

public class CategoriesController : ApiController
{
    private FrigoWebServiceContext db = new FrigoWebServiceContext();

    // GET: api/Categories
    [HttpGet]
    public string GetCategories()
    {
        return JsonConvert.SerializeObject(db.Categories.ToList());
    }

    // GET: api/Categories/5
    [ResponseType(typeof(string))]
    public string GetCategory(int id)
    {
        Category category = db.Categories.Find(id);
        if (category == null)
        {
            return null;
        }

        string jsonCategory = JsonConvert.SerializeObject(category);
        return jsonCategory;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool CategoryExists(int id)
    {
        return db.Categories.Count(e => e.Id == id) > 0;
    }
}

Now, this is the config:

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

but calling the following sites I'm not getting anything

NOTE: I published with IIS the api with "myAppName" path name

But noone of those is working

this is the error:

Error HTTP 404.0 - Not Found Desired resource has been removed, renamed or it's temporally unavaible

I've seen some questions from the internet and I tried to use them but I can't figure out why this is not working.

Any help will be appreciated, it's my first time with WebApi

this is my Web.Config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="FrigoWebServiceContext" connectionString= [***] />
  </connectionStrings>
  <appSettings></appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <httpModules>
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
    </httpModules>
  </system.web>
  <system.webServer>
    <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>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <remove name="ApplicationInsightsWebTracking" />
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
    </modules>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>
Pier Giorgio Misley
  • 5,305
  • 4
  • 27
  • 66

1 Answers1

3

If you are not using the Route attribute to specify / override method names AND you are not specifying the default method names in the route then Web API uses the default action verbs Get, Post, Put, Delete as the method names. This means you have to change your method like so:

see the method name changes only, do not pay attention to the return type which is another gripe I have with your sample code. You should let the Web API framework use the configured serializer and not return string but return IHttpActionResult by default. The why and how is out of scope for this question but I will not perpetuate a bad practice by leaving string as the return type on the method signature.

public class CategoriesController : ApiController
{
  [HttpGet]
  public IHttpActionResult Get()

  // or to pass in an an int and return only 1 category
  [HttpGet]
  public IHttpActionResult Get(int id)

Which now allows you to call your api like this

  • /Api/Categories/
  • or /Api/Categories/128 with the 2nd method

If you want to use method names other than those 4 (get/put/post/delete) then you can either change your routing in the WebApiConfig.cs or use the Route attribute.

For WebApiConfig.cs only change you could do this:

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

Which now allows you to call your api like this

  • /Api/Categories/GetCategories/
  • /Api/Categories/GetCategory/1234

If you want to use the Route attribute you could do this:

[RoutePrefix("api/categories"]
public class CategoriesController : ApiController
{
  [HttpGet]
  [Route("")]
  public IHttpActionResult GetCategories()

  [HttpGet]
  [Route("{id:int}")]
  public IHttpActionResult GetCategory(int id)

Which now allows you to call your api like this

  • /Api/Categories/
  • or /Api/Categories/128 with the 2nd method

Edit

As per comments below... See also HTTP 404 Page Not Found in Web Api hosted in IIS 7.5. Adding UrlRoutingModule to the web.config fixed the problem as it was being caused by both that and routing configuration..

Community
  • 1
  • 1
Igor
  • 60,821
  • 10
  • 100
  • 175
  • Thanks for this deep and well descripted solution but I can't figure why I'm still getting the same error. I've also fixed the return following your suggestion. I didn't know the best practice was using IHttpActionResult but now I'm using it. I'm starting to think the problem might be in my IIS or in my config. I'm posting the web.config I'm using in my question. if possible can you have a look at it? thanks a lot also for your suggestions – Pier Giorgio Misley Oct 11 '16 at 07:49
  • Note: I've just tried and after your suggestion it's working on my local machine, but still not working on my server. Might it be caused by the web.config? – Pier Giorgio Misley Oct 11 '16 at 07:57
  • Ok, I figured out from [this SO answer](http://stackoverflow.com/a/14457141/4700782). it worked for me, if you add it in your question I will mark it as the answer since both your and his solved my problem. Thanks again – Pier Giorgio Misley Oct 11 '16 at 08:16
  • @PierGiorgioMisley - good deal, I am glad you got it working. I edited my answer. – Igor Oct 11 '16 at 10:41
  • 1
    @PierGiorgioMisley - Using `IHttpActionResult` allows for returning Http status codes (with or without serialized data) which can more easily help you return an error based on various conditions (like not authenticated, or bad data model sent to method, etc). Very cool that you switched over, best of luck! – Igor Oct 11 '16 at 10:42