Getting “No action was found” from WebApi

2019-04-29 13:18发布

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?

2条回答
Rolldiameter
2楼-- · 2019-04-29 13:23

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.

查看更多
聊天终结者
3楼-- · 2019-04-29 13:40

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)

查看更多
登录 后发表回答