MVC 6 Web Api Duplicate http Actions (Post) - asp.net-mvc

This seemed so simple to me but I'm missing the boat.
I have one controller that handles two different types of POST actions.
[HttpPost("")]
public JsonResult Post([FromBody]Category mdl)
{ ... snip... }
[HttpPost("")]
public JsonResult Post([FromBody]SubCategory mdl)
{ ... snip... }
The only difference is the object parameter in the signature. Initially I thought this would suffice that MVC would be able to differentiate but it failed. When I have one or the other commented out the uncommented one works.
OK so then I tried this:
[HttpPost(Name = "UpdateCat")]
public JsonResult Post([FromBody]Category mdl)
{ ... snip... }
[HttpPost(Name = "UpdateSubCat")]
public JsonResult Post([FromBody]SubCategory mdl)
{ ... snip... }
But this didn't make any difference either? So I started googling and came across this but it isn't quite what I'm after as these are different http actions sharing the same name.
Is it possible to have duplicate action names and parameter list for post and get?
What am I misunderstanding about handling different post actions?

If you want to have 2 POST methods in same web api controller, you may define a specific route pattern for the second POST method using the Route attribute.
public class CategoryController: Controller
{
[HttpPost]
public HttpResponseMessage Post([FromBody]Category mdl)
{
return Request.CreateResponse(HttpStatusCode.OK, mdl);
}
[HttpPost]
[Route("~/api/products/SaveSubCat")]
public HttpResponseMessage Post([FromBody]SubCategory mdl)
{
return Request.CreateResponse(HttpStatusCode.OK, mdl);
}
}
Now your requests will be different
api/products/ will hit the first action method and api/producs/savesucat will hit the second one.
I suggest you move your second action to a SubCategory controller and use it's default POST method.

Related

By default not redirecting to Index action method of controller

Recently I've created on controller call DashboardVideos and an action method called Index.
And after Add Or Update, I'm redirecting it to Index page using
RedirectToAction("Index", "DashboardVideos").
but this code redirecting it to /DashboardVideos/ and it says
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
so the issue is by default it's supposed to load Index page when I say /Dashboard
But its not, same url pattern working with all other controller (So I don't think there's anything wrong with routing pattern).
Any help would be appreciated.
Code:
public class DashboardVideosController : BaseController
{
private readonly IDashboardVideosComponent socialTagComponent;
public DashboardVideosController()
{
socialTagComponent = ComponentFactory.Get<IDashboardVideosComponent>();
}
// GET: DashboardVideos
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult AddUpdate(DashboardVideosModel socialTagChannel)
{
//Save data to database
return RedirectToAction("Index", "DashboardVideos");
}
}
Simply write this if both actions are in same controller.
public ActionResult AddUpdate(DashboardVideosModel socialTagChannel)
{
//Save data to database
return RedirectToAction("Index");
}
Try to take a look at your "RouteConfig" class and you can specify custom routes there. Also It is possible if the call comes from AJAX it can go directly to action without redirecting. Did you tried to Debug the code?

How can you have both PUT and POST routing attributes on a controller action?

PUT and POST do a very similar thing in REST. The assumption being a POST means create a new entry and PUT means update an existing entry.
I had always assumed you could only have a single routing attribute on a controller action method, but now I have a situation where I want a method to respond to either HttpPost or HttpPut.
Update:
Tried a few variations and the actions were not hit if more than one routing attribute was applied. Like these:
[HttpPost]
[HttpPut]
public ActionResult Include(int id, int order, int parent)
{
return "...some result";
}
[HttpPost, HttpPut]
public ActionResult Include(int id, int order, int parent)
{
return "...some result";
}
The question now is: How do you respond to both PUT and POST requests in the same controller action?
There's builtin way to do that. Use AcceptVerbsAttribute
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Put)]
public ActionResult Include()
{
}

Difference between Private methods and Actions decorated with NonAction in Asp.Net MVC

in Asp.Net MVC if I decorate an action method with attribute NonAction then it wont be allowed to be called by the user visiting the site.
same happens when I make it private
So whats the difference between the two and is there a special purpose for which NonAction attribute has been made?
For example whats the difference between
[NonAction]
public ActionResult SomeAction(){}
And
private ActionResult SomeAction(){}
in the context of asp.net MVC of course I know one is public and the other one is private
That's the only difference. The attribute is used when you want a method that has a signature that would make it an action, but that you don't want to be an action.
An example for a use for that is a method that action methods call to produce the ActionResult for them:
[NonAction]
public JsonResult JsonInfo(string id, string value) {
return Json(new { id = id, value = value });
}
public JsonResult GetBusInfo() {
return JsonInfo("4", "Bus");
}
public JsonResult GetCarInfo() {
return JsonInfo("8", "Car");
}
The reason to make it public instead of private would be so that actions in other controllers could also use it.
Both works same with action method,you can use them seperately or together.
[NonAction]
private ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
FEED_TBL fEED_TBL = db.FEED_TBL.Find(id);
if (fEED_TBL == null)
{
return HttpNotFound();
}
return View(fEED_TBL);
}
If declare it like the above code then when we will try to go to details action method it will not go to it.Rather it will show the error.
{{ HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.}}
This shows that our detail link on view does found any reference to details action method and our controller to.

MVC3 RESTful API Routing & Http Verb Handling

I want to build a RESTful Json Api for my MVC3 application. I need help with handling multiple Http Verbs for the manipulation of a single object instance.
What I've read/studied/tried
MVC attributes (HttpGet, HttpPost, etc.) allow me to have a controller with multiple actions sharing the same name, but they still must have different method signatures.
Route constraints happen in the routing module before MVC kicks in and would result in me having 4 explicit routes, and still require individually named controller actions.
ASP.NET MVC AcceptVerbs and registering routes
Building a custom Http Verb Attribute could be used to snatch the verb used to access the action and then pass it as an argument as the action is invoked - the code would then handle switch cases. The issue with this approach is some methods will require authorization which should be handled at the action filter level, not inside the action itself.
http://iwantmymvc.com/rest-service-mvc3
Requirements / Goals
One route signature for a single instance object, MVC is expected to handle the four main Http Verbs: GET, POST, PUT, DELETE.
context.MapRoute("Api-SingleItem", "items/{id}",
new { controller = "Items", action = "Index", id = UrlParameter.Optional }
);
When the URI is not passed an Id parameter, an action must handle POST and PUT.
public JsonResult Index(Item item) { return new JsonResult(); }
When an Id parameter is passed to the URI, a single action should handle GET and DELETE.
public JsonResult Index(int id) { return new JsonResult(); }
Question
How can I have more than one action (sharing the same name and method signature) each respond to a unique http verb. Desired example:
[HttpGet]
public JsonResult Index(int id) { /* _repo.GetItem(id); */}
[HttpDelete]
public JsonResult Index(int id) { /* _repo.DeleteItem(id); */ }
[HttpPost]
public JsonResult Index(Item item) { /* _repo.addItem(id); */}
[HttpPut]
public JsonResult Index(Item item) { /* _repo.updateItem(id); */ }
For RESTful calls, the action has no meaning, since you want to differ only by HTTP methods. So the trick is to use a static action name, so that the different methods on the controller are only different in the HTTP method they accept.
While the MVC framework provides a solution for specifying action names, it can be made more concise and self-explaining. We solved it like this:
A special attribute is used for specifying RESTful methods (this matches to a special action name):
public sealed class RestfulActionAttribute: ActionNameSelectorAttribute {
internal const string RestfulActionName = "<<REST>>";
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
return actionName == RestfulActionName;
}
}
The controllers use it in combination with the HTTP method attributes:
public class MyServiceController: Controller {
[HttpPost]
[RestfulAction]
public ActionResult Create(MyEntity entity) {
return Json(...);
}
[HttpDelete]
[RestfulAction]
public ActionResult Delete(Guid id) {
return Json(...);
}
[HttpGet]
[RestfulAction]
public ActionResult List() {
return Json(...);
}
[HttpPut]
[RestfulAction]
public ActionResult Update(MyEntity entity) {
return Json(...);
}
}
And in order to bind those controllers successfully, we use custom routes with the static action name from the beforementionned attribute (which at the same time also allow for customizing the URLs):
routes.MapRoute(controllerName, pathPrefix+controllerName+"/{id}", new {
controller = controllerName,
action = RestfulActionAttribute.RestfulActionName,
id = UrlParameter.Optional
});
Note that all your requirements can be easily met with this approach as far as I can tell; you can have multiple [HttpXxx] attributes on one method to make one method accept multiple HTTP methods. Paired with some smart(er) ModelBinder this is very powerful.

How Does One Differentiate Between Routes POSTed To In Asp.Net MVC?

I have two actions, one that accepts a ViewModel and one that accepts two parameters a string and an int, when I try to post to the action, it gives me an error telling me that the current request is ambiguous between the two actions.
Is it possible to indicate to the routing system which action is the relevant one, and if it is how is it done?
You can decorate it with HttpGet HttpPost
Look under "Overriding the HTTP Method Verb"
http://www.asp.net/learn/whitepapers/what-is-new-in-aspnet-mvc
You can also use the ActionName attribute. Look under "ActionNameAttribute"
http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
You can't overload controller actions, though as Raj said, you can differentiate them by allowing them to respond to different requests (get, post, etc).
You might also find this helpful: How a Method Becomes An Action.
This is how it's done
A simplified example:
[HttpGet] // this attribute is't necessary when there are only 2 actions with the same name
public ActionResult Update(int id)
{
return View(new Repository().GetProduct(id));
}
[HttpPost]
public ActionResult Update(int id, Product product)
{
// handle POST data
var repo = new Repository();
repo.UpdateProduct(product);
return RedirectToAction("List");
}
And if you'd need two actions that would have completely same signature (same name and exactly the same number of parameters of the same type) in that case you would have to use another attribute like this:
public ActionResult SomeAction(int id)
{
return View(new Repository().GetSomething(id));
}
[HttpPost]
[ActionName("SomeAction")]
public ActionResult SomeActionPost(int id)
{
// handle POST data
var repo = new Repository();
repo.UpdateTimestamp(id);
return View(repo.GetSomething(id));
}

Resources