0

I've created both an ASP.NET MVC project which includes the Web API and I created an empty project where only Web API was selected and I'm trying to understand why they are behaving differently.

Both of them from what I can tell have the routing definition defined as follows:

config.MapHttpAttributeRoutes();

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

But I'd like to understand why the functions that are defined in the controller are behaving differently.

In my ASP.NET MVC Solution, I can create multiple functions under the one controller:

public IEnumerable<Product> GetAllProducts()
{
    return products;
}

public IHttpActionResult GetProduct(int id)
{
    var product = products.FirstOrDefault((p) => p.Id == id);
    if (product == null)
    {
        return NotFound();
    }
    return Ok(product);
}

I don't have to add any attributes, well at least for gets and I can call individual function as:

http://localhost/api/test/GetProduct/1 http://localhost/api/test/GetProducts

In the Web API only solution, I had to define it as:

public IHttpActionResult HelloWorld()
{
    return Ok("Hello World");
}

but the above will not work unless I add the [HttpGet] attribute to my HelloWorld function.

Also I don't seem to be able to define multiple functions within the one controller as it is done the in ASP.NET MVC Solution. Defining the same function as above just does not work or even if I define the functions below

[HttpGet]
public IHttpActionResult HelloWorld()
{
    return Ok("Hello World");
}

[HttpGet]
public IHttpActionResult GetTime()
{
    return Ok(DateTime.Now.ToString());
}

I get the following error:

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
    Multiple actions were found that match the request: HelloWorld on type 
    MyProject.Controllers.TestController GetTime on type 
    MyProject.Controllers.TestController
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
    at 
    System.Web.Http.Controllers.ApiControllerActionSelector.
    ActionSelectorCacheItem.SelectAction(HttpControllerContext 
    controllerContext) at System.Web.Http.ApiController.
    ExecuteAsync(HttpControllerContext controllerContext, CancellationToken 
    cancellationToken) at System.Web.Http.Dispatcher.
    HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
</StackTrace>

When I define a single function, it works but contrarily to a Web API defined in my ASP.NET MVC solution, when I call the below

http://localhost/api/test/HelloWorld

It doesn't seem to care what the function name is called as it will work if I call any of the following:

http://localhost/api/test http://localhost/api/test/GoodBye

and will only fail if I provide an invalid controller name i.e.

http://localhost/api/mytest

Can you explain the difference between the 2 and ideally what do I have to do to get a stand-alone Web API to behave the same way as it does when defined in Asp.net MVC

Thanks.

UPDATE-1

Below are 2 good examples where the behavior is clearly different but I can't see why as both are called "Web API with ASP.NET MVC".

Creating Simple Service with ASP.NET MVC Web API to be accessed by Windows Store and Windows Phone Application

Getting Started with ASP.NET Web API 2 (C#)

1
  • @Ashiquzzaman It might be but I've just provided 2 links which highlights my problem as both are referred to as ASP.NET MVC Web API and yet their definition and behavior are different which is what I'm trying to understand and hopefully be provided with a resolution as to how to make it behave as it is was defined in an ASP.NET MVC Web App. Commented Mar 8, 2018 at 11:23

1 Answer 1

1

Edit:

I'm sry at first I misunderstood your enquiry and therefore gave you the wrong answer to your question.

In Web Api you can't define two functions that serve the exact same path. But you can overload them like you would with Functions.

public IEnumerable<Product> GetAllProducts() {}
public IHttpActionResult GetProduct(int id) {}

These two function differ in so far that they serve different paths:

localhost/api/products/
localhost/api/products/{id}/

The following functions on the other hand both serve localhost/api/test/

[HttpGet]
public IHttpActionResult HelloWorld()
{
    return Ok("Hello World");
}

[HttpGet]
public IHttpActionResult GetTime()
{
    return Ok(DateTime.Now.ToString());
}

Your second concern has been the naming and mostly why you can't define HelloWorld() without [HttpGet]. That is because Web Api automatically maps functions that have a keyword such as Get or Delete as part of their name to the corresponding Http Function.

Adding the Http-Attribute is only needed if the function name does not conform to these naming conventions or shall serve multiple Http-Methods. It's described here

I hope your questions are now answered.

Orig:

The Default Routing and subsequent decision on what Function is to be executed is different between MVC and Web API

Default Web Api:

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

Default Mvc:

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

For Web Api the Routing is dependant on the controller name and further which Http-Method has been selected as well as the controller actually having a function the has been tagged with this method. Hence the and further Tags

Mvc on the other hand routes via the controller name and the action name to the desired functionality.

Web Api 2 adds further possibilies in letting you define AttributeRoutes. You may want to look further on this topic here and here

Sign up to request clarification or add additional context in comments.

8 Comments

Both my standalone web api project and my asp.net mvc web app (where web api was selected) both include the Default Web API you provided in your answer but hopefully the link you provided will help. Thanks
You will find the different routes in different files. The MVC one is in RouteConfig.cs and the API one is in WebApiConfig.cs. That way you can define different Routing behaviours in your solution For Controllers and Api Controllers
Both projects already have the WebApiConfig.cs with the 'default web api' mapping defined in it.
If you check the 2 links I've provided, it's pretty much the same. Both are defined in the WebApiConfig.cs, both inherit from ApiController and yet their behaviour are different.
Thanks for the detailed clarification. I'm currently reading the links you provided but I'm still confused as to how GetAllProducts() and GetProduct() are ok to be defined as is in the Microsoft sample and not in my project. I've created a new project at home where my controller is called 'DocumentController' which inherits from ApiController and it has one function called GetById(int id) but If I call localhost/document/getbyid/1 it doesn't work but if I call localhost/document/1, it does. I understand api don't include action but does it in the Microsoft sample? Thanks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.