Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting "No action was found" from WebApi

I am a WCF dev, new to MVC. Trying to integrate my WCF API as ApiControllers into an MVC application (still big question if it's a worthy effort).

I have this request from a jQuery plugin:

 POST http://localhost:18698/Api/Public/DoAction HTTP/1.1 
 ....
 Content-Type: application/json; charset=UTF-8 Accept:
 application/json, text/javascript, */*; q=0.01

 {"myParam":"test"}

My controller looks like this:

public class PublicController : ApiController
{
    [HttpPost]
    public string DoAction(string myParam)
    {
        return "Test";
    }
} 

And, the routing piece looks like this:

    config.Routes.MapHttpRoute(
        name: "PublicApi",
        routeTemplate: "api/{controller}/{action}"
    );

I am getting this error:

{
    "Message": "No HTTP resource was found that matches the request URI 'http://localhost:18698/Api/Public/DoAction'.",
    "MessageDetail": "No action was found on the controller 'Public' that matches the request."
}

Methods that don't accept any JSON parameters work fine, but the ones that accept JSON parameters don't work. I have to be able to pass complex JSON to the methods. In WCF, translation from JSON to objects was handled for me by WCF.

Do you know why I am getting this error? Would I be able to pass/receive complex JSON as seamlessly in MVC as I did in WCF?

like image 405
user1044169 Avatar asked Nov 20 '12 12:11

user1044169


People also ask

How do you implement a generic action in Web API?

But the framework is very extensible and if you get a very good understanding of Routing and Action Selection in ASP.NET Web API and learn how routing, controller selection, action selection, parameter binding and action invocation work, then you can implement some customization for the framework to support generic ...

How do I return a view from Web API action?

So, if you want to return a View you need to use the simple ol' Controller . The WebApi "way" is like a webservice where you exchange data with another service (returning JSON or XML to that service, not a View). So whenever you want to return a webpage ( View ) for a user you don't use the Web API.


2 Answers

If you examine the JSON you were sending {"myParam":"test"} then you will see what Darin points out i.e. you need a Model to contain your property e.g. run {"myParam":"test"} into the following tool: http://json2csharp.com/ and you get:

public class RootObject
{
    public string myParam { get; set; }
}

Your previous method signature with the simple type of string would have been treated by WebApi as a UrlParameter by default (the same as public string DoAction([FromUri]string myFoo)). You can prove this as leaving you code as is this url should work:

http://localhost:50381/Api/Public/DoAction?myParam=something

The body serialiser using JSON.NET won't be able to parse a simple .NET type on it's own and therefore you need to create a simple Model to host it on. This will then use the from body binder public string DoAction([FromBody]RootObject myFoo)

like image 85
Mark Jones Avatar answered Oct 18 '22 13:10

Mark Jones


As always start by defining a view model:

public class MyModel
{
    public string MyParam { get; set; }
}

then have your controller action take this view model as parameter:

public class PublicController : ApiController
{
    [HttpPost]
    public string DoAction(MyModel model)
    {
        return "Test_" + model.MyParam;
    }
}

finally invoke the controller action:

<script type="text/javascript">
    $.ajax({
        url: '@Url.HttpRouteUrl("PublicApi", new { controller = "public", action = "doaction" })',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({ "myParam": "test" }),
        sucecss: function (result) {
            console.log(result);
        }
    });
</script>

Remark: You are violating the RESTful conventions by including the action name in your routes. In RESTful routes you are working with resources, not with actions. So your controller represents the resource you are manipulating and the HTTP verbs represent the actions you are calling. So you would use action names such as Get, Post, Patch and Delete and based on the HTTP verb used by the client, the routing engine will automatically dispatch to the corresponding action.

like image 20
Darin Dimitrov Avatar answered Oct 18 '22 15:10

Darin Dimitrov