0

I know this question has been asked and answered in numerous areas as I've searched and seen many different answers and examples; however, I'm unable to apply any of those and get this working.

I'm trying to put together an RPC style apicontroller in MVC 4. In the aipcontroller, I have two methods I'm trying to execute sending and receiving JSon: TestFunction1 & TestFunction2. If I comment out either one, the other works fine.

When I try to include them both, it fails with the following (common) error:

Multiple actions were found that match the request:
    TestFunction1 on type test.api.TestController
    TestFunction2 on type test.api.TestController"

As best as I can figure, I'm following the examples I've found and I've read SO QnAs until I'm blind and I still can't figure out what I'm doing wrong.

Can someone help me fix and understand this?

Edit: Additional Note - If I comment out TestFunction2 and don't change my javascript action to match, I still get a call to TestFunction1.

My Controller methods:

    [HttpPost, ActionName("TestFunction1")]
    public HttpResponseMessage TestFunction1(SomeModel somemodel)
    {   SomeModel otherModel = new SomeModel() {
            id = 7,
            username = "other API-PostSomeModel Username",
            email = "other API-PostSomeModel email",
            password = "other API-PostSomeModel passowrd"
        };

        if (ModelState.IsValid) {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, somemodel);
            var serializer = new JavaScriptSerializer();

            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = somemodel.id }));
            response.Content = new StringContent(serializer.Serialize(otherModel));

            return response;
        }
        else {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }
    }

    [HttpPost, ActionName("TestFunction2")]
    public HttpResponseMessage TestFunction2(SomeModel somemodel)
    {   SomeModel otherModel = new SomeModel() {
            id = 7,
            username = "other API-TestFunction Username",
            email = "other API-TestFunction email",
            password = "other API-TestFunction passowrd"
        };

        var serializer = new JavaScriptSerializer();
        var resp = new HttpResponseMessage() {
            Content = new StringContent(serializer.Serialize(otherModel))
        };

        resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        return resp;
    }

The model:

public class SomeModel
{   [Key]
    public long id { get; set; }
    public string username { get; set; }
    public string password { get; set; }
    public string email { get; set; }

    public SomeModel() {}
    public SomeModel(long _id, string usrname, string pswd, string _email) {
       id = _id;
        username = usrname;
        password = pswd;
        email = _email;
    }   
}

My routing:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        //Route Catches the GET PUT DELETE typical REST based interactions (add more if needed)
        routes.MapHttpRoute(
            name: "API Default",
            routeTemplate: "api/{controller}/{id}",
            defaults: new {
                id = RouteParameter.Optional,
                httpMethod = new HttpMethodConstraint("GET", "PUT", "DELETE")
            }
        );

        //This allows POSTs to the RPC Style methods http://api/controller/action
        routes.MapHttpRoute(
            name: "API RPC Style",
            routeTemplate: "api/{controller}/{action}",
            defaults: new {
                httpMethod = new HttpMethodConstraint("POST"),  
            }
        );

        //Finally this allows POST to typical REST post address http://api/controller/
        routes.MapHttpRoute(
            name: "API Default 2",
            routeTemplate: "api/{controller}/{action}",
            defaults: new {
                httpMethod = new HttpMethodConstraint("POST"),  
            }
        );

        routes.MapRoute(
             name: "Default",
             url: "{controller}/{action}/{id}",
             defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

My javascript:

 function jsTestFunction(id, username, password, email) {
    alert("Verify data:" + "\n\r" + id + "\n\r" + username + "\n\r" + password + "\n\r" + email);
    var obj = { 
        'id' : id,
        'username' : username,
        'password' : password,
        'email' : email,
    };
    var postdata = JSON.stringify(obj);
    $.ajax({
        type: "POST",
        url: "api/Test/TestFunction2/",
        dataType: "json",
        traditional: true,
        data: postdata,
        contentType: "application/json; charset=utf-8",
        success: function (responsedata) {
            var temp0 = responsedata['id'];
            var temp1 = responsedata['username'];
            var temp2 = responsedata['password'];
            var temp3 = responsedata['email'];
            if (!responsedata.error) {
                alert("The process was successful: " + "\n\r" + temp0 + "\n\r" + temp1 + "\n\r" + temp2 + "\n\r" + temp3);
            }
            else {
                alert("An error occured during the process: " + responsedata.msg);
                $('#reservation-result').html("Error :" + responsedata.msg).fadeIn(2000);
            }
        },
        error: function (error) {
            alert("There was an error posting the data to the server: " + error.responseText);
        }
    });
 }
Lee
  • 255
  • 4
  • 16

1 Answers1

0

I finally fixed it. It was fairly obvious the problem was in the routing when I could comment out TestFunction2 and still call TestFunction1 when I was calling TestFunction2 in the javascript.

I also noticed I had my mapping in RouteConfig.cs. That probably has nothing to do with the problem; except, it should have been in WebApiConfig to be doing it correctly. Functionally, I don't think it had anything to do with it.

What finally made the fix was when I swapped the order of the routes "API RPC Style" with "API Default". Then it immediately began working. Now I can execute the API POST calls in an RPC fashion and it works correctly.

I can't say that I completely understand the routing mechanisms; however, I do know that order matters. It is first match is selected, not best match. In this case, it makes sense; hence, I'll run with it.

Lee
  • 255
  • 4
  • 16