Send space in route mvc - ajax

I have to implement search with MVC3, where user can search any word or words, now if i write only a sigle word its work fine and my route will be like
/search/toy
and toy is recognise by my controller method.
But if i want to search something with space like 'kid toy' then route have a space and in my controller method it doesn't recognise it as a word and throw error like
/search/kids%20toy
Has anyone implement such thing in his project plz help.
Thanks in advance.

Looks like you have an action called "Toy".
// maps to /search/
public class Search : Controller
{
// maps to /search/toy
public ActionResult Toy()
{
}
}
If you haven't modified the default routes at all, you need to use {controller}/{action}/{id}.
(Of course you'll have to look into routing if you want to do different kind of routes. Ask google for ASP.NET MVC routing)
Here's the quickest way:
// maps to /search
public class Search : Controller
{
// maps to /search/for/{id}
public ActionResult For(string id)
{
// search for id
}
}
Which could be used as /search/for/kids%20toy.
Or you can use querystring for parameters named something else than id.
// maps to /search
public class Search : Controller
{
// maps to /search/ by default, check route config
public ActionResult Index(string query)
{
// search for query
}
}
To be able to use {controller}/{action}/{query} or {controller}/{query} you'll have to create a route, but you can address that one by
/search/?query=kids%20toy

Related

How to assign multiple MVC routes to one method and determine the used route?

I have the following code:
public IActionResult Up(int id)
{
return Move(id, "up");
}
private IActionResult Move(int id, string action)
{
// Do something based on the action
switch (action)
{
case "up":
break;
case "down":
break;
}
}
This works fine and is easy to maintain. But now I've thought that I could refactor the code by combining the methods:
[Route("item/up/{id}")]
[Route("item/down/{id}")]
public IActionResult Move([FromRoute]string action, [FromRoute]int id)
{
}
The link /item/up/155 will hit this method while the link /item/up2/155 returns NotFound, as expected.
The problem now is, that when I check the value of action, then it does not contain the value up, but the value Move.
This seems odd as the controller name is not transformed into ItemController. So one could argue that the value should be up. But assuming this is the design and won't change, then how can I find the actual value?
I can parse Request.Path.Value (="/item/up/155"), but I'd prefer not to as I would like to keep things simple.
So I am looking for an easy way to assign multiple routes to one method and then determine what the value of the action parameter in the used route path was.
Instead of hard coding the direction as 'up' and 'down' in the route declaration, you can treat that as a parameter. Since you used the keyword 'action' as a parameter, during the parameter binding the actual action method selected by the framework will be assigned to it.
You can try the following code -
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[Route("item/{direction}/{id}")]
public string Move([FromRoute]string controller, [FromRoute]string action, string direction, string id)
{
return string.Format("Controller={0} Action={1} Direction={2} Id={3}", controller, action, direction, id);
}
}

Is it possible to report back the route name used when calling a Web API?

Is it possible to report back the route name used when calling a Web API?
I want to do some diagnostics in a "foo" project to see what route is called based on how/what I call. Is there a way for the action/api to see what route is used to reach it? Some sort of "route reflection"?
You can use Request.GetRouteData() to get the route details for an action.
public class TestController : ApiController
{
[HttpGet]
public HttpResponseMessage Index()
{
var route = Request.GetRouteData();
return Request.CreateResponse(HttpStatusCode.OK);
}
}

Url routing - infinite url

I use asp.net mvc3 and I want to write route that has no end..
I mean something like that:
www.site.com/Cameras/{id}={string}/{id}={string}/{id}={string}/{id}={string}.....
where the id represent a filter id and the string represent a value of that filter..
I have many types of filters and in the future I want to be able to add more without any dependence..
How should this kind of route should look? And how do I start to deal these parameters?
What you need to do is write a catchall route and then interpret it like this:
routes.MapRoute("Cameras", "cameras/{*url}",
new { controller = "Cameras", action = "Index" }
);
public ActionResult Index(string url)
{
var ids = url.split('/');
// now do what you need with the ids
}
You should use urls like this:
/cameras/id1/id2/id3/id4

Recommended API design with ASP.NET MVC3

I'm working with ASP.NET MVC 3. I'm kind of new to it. I think I'm starting to get the hang of it. But there is something that I'm trying to do, that I think makes sense, but maybe I'm wrong.
I'm trying to create an API around Order objects in my database. In order to get all of the orders in the system, I was going to expose an API that looks like the following:
/orders/
In cases where I wanted to get a specific Order, I would simply append an ID. In other words, the URL would look like this:
/orders/12345
In an effort to accomplish this, I created the following controller:
public class OrdersController : Controller
{
// GET: /Orders/
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
string result = "list of orders";
return Json(result, JsonRequestBehavior.AllowGet);
}
//
// GET: /Orders/{orderID}
public ActionResult Index(int id)
{
string result = "order:" + id;
return Json(result, JsonRequestBehavior.AllowGet);
}
}
In my AreaRegistration class, I have the following:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"OrderList",
"{controller}/{action}",
new { action = "Index", controller="Orders" }
);
context.MapRoute(
"Order",
"{controller}/{action}/{id}",
new { action = "Index", controller = "Orders" }
);
}
When I attempted to access "/orders/", via the browser address bar, I get the JSON like I would expect. However, if I attempt to access "/orders/12345", I receive a 404. What am I missing?
Thank you
You need to also define proper routes in global.asax or use the default route which looks like {controller}/{action}/{id} where controller is defaulted to "Home", action is defaulted to "Index" and id is optional.
So /orders works because you have defined controller (orders), default action (Index) and missing id (which doesn't matter as it is optional)
But when you try /orders/12345 then you have defined controller (orders), action (12345) and missing id
So to make this work with only the default route the request should be /orders/index/12345
edit: for registering area routes you should use AreaRegistration class

MVC Routes based on POST parameters

We have an a PHP application that we are converting to MVC. The goal is to have the application remain identical in terms of URLs and HTML (SEO and the like + PHP site is still being worked on). We have a booking process made of 3 views and in the current PHP site, all these view post back to the same URL, sending a hidden field to differentiate which page/step in the booking process is being sent back (data between pages is stored in state as the query is built up).
To replicate this in MVC, we could have a single action method that all 3 pages post to, with a single binder that only populates a portion of the model depending on which page it was posted from, and the controller looks at the model and decides what stage is next in the booking process. Or if this is possible (and this is my question), set up a route that can read the POST parameters and based on the values of the POST parameters, route to a differen action method.
As far as i understand there is no support for this in MVC routing as it stands (but i would love to be wrong on this), so where would i need to look at extending MVC in order to support this? (i think multiple action methods is cleaner somehow).
Your help would be much appreciated.
I have come upon two solutions, one devised by someone I work with and then another more elegant solution by me!
The first solution was to specify a class that extends MVcRouteHandler for the specified route. This route handler could examine the route in Form of the HttpContext, read the Form data and then update the RouteData in the RequestContext.
MapRoute(routes,
"Book",
"{locale}/book",
new { controller = "Reservation", action = "Index" }).RouteHandler = new ReservationRouteHandler();
The ReservationRouteHandler looks like this:
public class ReservationRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
// First attempt to match one of the posted tab types
var action = ReservationNavigationHandler.GetActionFromPostData(request);
requestContext.RouteData.Values["action"] = action.ActionName;
requestContext.RouteData.Values["viewStage"] = action.ViewStage;
return base.GetHttpHandler(requestContext);
}
The NavigationHandler actually does the job of looking in the form data but you get the idea.
This solution works, however, it feels a bit clunky and from looking at the controller class you would never know this was happening and wouldn't realise why en-gb/book would point to different methods, not to mention that this doesn't really feel that reusable.
A better solution is to have overloaded methods on the controller i.e. they are all called book in this case and then define your own custome ActionMethodSelectorAttribute. This is what the HttpPost Attribute derives from.
public class FormPostFilterAttribute : ActionMethodSelectorAttribute
{
private readonly string _elementId;
private readonly string _requiredValue;
public FormPostFilterAttribute(string elementId, string requiredValue)
{
_elementId = elementId;
_requiredValue = requiredValue;
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (string.IsNullOrEmpty(controllerContext.HttpContext.Request.Form[_elementId]))
{
return false;
}
if (controllerContext.HttpContext.Request.Form[_elementId] != _requiredValue)
{
return false;
}
return true;
}
}
MVC calls this class when it tries to resolve the correct action method on a controller given a URL. We then declare the action methods as follows:
public ActionResult Book(HotelSummaryPostData hotelSummary)
{
return View("CustomerDetails");
}
[FormFieldFilter("stepID", "1")]
public ActionResult Book(YourDetailsPostData yourDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[FormFieldFilter("stepID", "2")]
public ActionResult Book(RoomDetailsPostData roomDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[HttpGet]
public ActionResult Book()
{
return View();
}
We have to define the hidden field stepID on the different pages so that when the forms on these pages post back to the common URL the SelectorAttributes correctly determines which action method to invoke. I was suprised that it correctly selects an action method when an identically named method exists with not attribute set, but also glad.
I haven't looked into whether you can stack these method selectors, i imagine that you can though which would make this a pretty damn cool feature in MVC.
I hope this answer is of some use to somebody other than me. :)

Resources