4

Let's say I have a Controller that handles a CRUD scenario for a 'Home'. The Get would look something like this:

    [HttpGet]
    public ActionResult Index(int? homeId)
    {
        Home home = homeRepo.GetHome(homeId.Value);

        return Json(home, JsonRequestBehavior.AllowGet);
    }

So far so good. Then I add a post action for adding new ones.

    [HttpPost]
    public ActionResult Index(Home home)
    {
        //add the new home to the db

        return Json(new { success = true });
    }

Awesome. But when I use the same scheme to handle puts (updating an existing home)...

    [HttpPut]
    public ActionResult Index(Home home)
    {
        //update existing home in the db

        return Json(new { success = true });
    }

We run into a problem. The method signatures for Post and Put are identical, which of course C# doesn't like. I could try a few things, like adding bogus parameters to the signature, or changing the method names to directly reflect CRUD. Those are hacky or undesirable, though.

What is the best practice for going about preserving RESTful, CRUD style controllers here?

3
  • Why do you consider changing the mehod names hacky or undesirable? The methods serve different purposes, so I would say they would deserve different names. Commented Feb 8, 2011 at 22:59
  • Because a RESTful approach requires they all resolve to the same url, just with different HttpMethods (Create = Post, Read = Get, Update = Put, Delete = Delete). There are a lot of reasons for it, but mostly it will make the javascript api I build on top of this much easier to write. Smaller, too. Commented Feb 8, 2011 at 23:11
  • 1
    Right, then Matt's solution works great. Keeps your external api RESTful, while keeping your C# code compiling. Commented Feb 8, 2011 at 23:20

2 Answers 2

13

This is the best solution that I know of:

[HttpPut]
[ActionName("Index")]
public ActionResult IndexPut(Home home) 
{
     ...
}

Basically the ActionNameAttribute was created to deal with these scenarios.

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

1 Comment

A gentleman and a scholar. That looks about as elegant as I can get away with :).
0

HttpPut and HttpDeletes are restricted by some firewalls so at times simply HttpPost and HttpGet are used. If a record ID is passed in (or some other criteria) you know its an update. Granted - this is for you to determine, httpput may work just fine for you, this is just a warning on it, it usually isn't a big deal.

Either method used - beware of users trying to inject false IDs into the page in order to forcing updates of records they don't have access to. I get around this issue by hashing in this case home.HomeId on the view when we render it

ViewData["IdCheck"] = Encryption.ComputeHash(home.HomeId.ToString());

in your view:

    <%: Html.Hidden("IdCheck", ViewData["IdCheck"]) %>

in your HttpPost or HttpPut method (whichever is doing the update)

 if (Encryption.ComputeHash(home.HomeId.ToString()) != (string)Request.Form["IdCheck"])
 {
       throw new Exception("Hashes do not match");
}

Again - this same security issue exists no matter which method you use to do your update if you are trusting form data.

2 Comments

We have a number of measures in place, but I hadn't considered hashing the ids. Interesting.
check out nycdotnetdev.com/Download.aspx and select "1/20/2011 Hack-Proofing your ASP.NET Web Forms & MVC Web Applications" download one if you want some more details on this one

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.