Rewriting the URL for a Controllers Action Method - asp.net-mvc

I have a controller called Person and it has a post method called NameSearch.
This method returns RedirectToAction("Index"), or View("SearchResults"), or View("Details").
The url i get for all 3 possibilities are http://mysite.com/Person/NameSearch.
How would i change this to rewrite the urls to http://mysite.com/Person/Index for RedirectToAction("Index"), http://mysite.com/Person/SearchResults for View("SearchResults"), and http://mysite.com/Person/Details for View("Details").
Thanks in advance

I'm assuming your NameSearch function evaluates the result of a query and returns these results based on:
Is the query valid? If not, return to index.
Is there 0 or >1 persons in the result, if so send to Search Results
If there is exactly 1 person in the result, send to Details.
So, more of less your controller would look like:
public class PersonController
{
public ActionResult NameSearch(string name)
{
// Manage query?
if (string.IsNullOrEmpty(name))
return RedirectToAction("Index");
var result = GetResult(name);
var person = result.SingleOrDefault();
if (person == null)
return RedirectToAction("SearchResults", new { name });
return RedirectToAction("Details", new { id = person.Id });
}
public ActionResult SearchResults(string name)
{
var model = // Create model...
return View(model);
}
public ActionResult Details(int id)
{
var model= // Create model...
return View(model);
}
}
So, you would probably need to define routes such that:
routes.MapRoute(
"SearchResults",
"Person/SearchResults/{name}",
new { controller = "Person", action = "SearchResults" });
routes.MapRoute(
"Details",
"Person/Details/{id}",
new { controller = "Person", action = "Details" });
The Index action result will be handled by the default {controller}/{action}/{id} route.
That push you in the right direction?

Related

C#.NET MVC Route Aliasing

I've been searching and searching for away to make old URL like we used to do in aspx pages where you could have an alias pointing to a page like www.domain.com/my-great-alias point to www.domain.com/alias.aspx. I want to do the same thing in MVC but can not figure out how to make this happen in the route table. Where www.domain.com/my-great-alias would show up to the end user as such but point to www.domain.com/alias/2
Does this make sense to anyone else what I'm looking for?
// router
routes.MapRouteLowercase(
"Alias",
"{id}",
new
{
controller = "alias",
action = "select",
id = UrlParameter.Optional
}
);
// Alias controller
public ActionResult Select()
{
return View("select");
}
// Recipe Controller
public ActionResult Select()
{
return View();
}
You should be able to do this utilizing route config and parameters (as long as it's in the same domain):
Routing
routes.MapRoute(
name: "AliasRoute",
url: "{id}",
defaults: new { controller = "Alias" }
);
Controller
public class AliasController : Controller
{
public ActionResult Index(string id)
{
//DO SOME DATABASE STUFF HERE TO LOOKUP THE CORRESPONDIND CONTROLLER AND ACTION
var controllerAction = lookupControllerActionInDatabase(id);
return View(controllerAction.ViewName);
//OR
//DO CONDITIONAL CHECKS HERE AND RETURN THE APPROPRIATE VIEW
if (id == "my-great-alias") {
return View("Alias");
} else if (id == condition1) {
return View("viewForCondition1");
} else if (id == condition2) {
return View("viewForCondition2");
}
//AND SO ON...
}
}

How to pass a list in a get request

I have an url that works for passing a List of strings
/Home/Index?Person%5B0%5D=Myname&Person%5B1%5D=Yourname
Unencoded it is
/Home/Index?Person[0]=Myname&Person[1]=Yourname
The Action Method is
public ActionResult(List<string> person)
{
...
}
The Parameter List person will be correctly filled with the values Myname and Yourname.
I need to redirect to this url using RedirectToAction
I would usually do
RedirectToAction("Index","Home",new {Parameter1=value1})
But obviously I cant use Person%5B0%5D as a parameter name, because it has ivalid characters.
How can I create such a link or should I use a different URL - scheme?
hi i worked on your query and finally got the result just check this code find weather it work with your query.
Controller code :
public ActionResult showString()
{
try
{
IEnumerable<string> persons = new[] { "myname", "urname" };
var values = new RouteValueDictionary(
persons
.Select((sampleper, index) => new {sampleper, index })
.ToDictionary(
key => string.Format("[{0}]", key.index),
value => (object)value.sampleper
)
);
return RedirectToAction("details", values);
}
catch (Exception)
{
throw;
}
}
and another action method is details with list as parameter
public ActionResult details(IEnumerable<string> persons)
{
ViewBag.person = persons;
return View();
}
it also works if you pass the link as
http://localhost:2266/Home/details?%5B0%5D=myname&%5B1%5D=urname
the view of details action method is
#{
ViewBag.Title = "details";
}
<h2>details</h2>
<ul>
#foreach (var i in ViewBag.person)
{
<li>#i</li>
}
</ul>

MVC4 Razor - Trying to get id in url for a blog post

All Im trying to do is get my url to have the blogid appending to it much like the following...
http://localhost/blog/blogpost/17
Here is my Controller...
public ActionResult BlogList(){ return View(_repository); }
public ActionResult BlogPost(string id)
{
ViewData["id"] = id;
if (ModelState.IsValid)
{
return RedirectToAction("BlogPost", new { id = id });
}
return View(_repository);
}
Now here is my route.config maproute
routes.MapRoute(
"MyBlog", // Route name
"blog/{action}/{id}", // URL with parameters
new { controller = "Blog", action = "blogpost", id =
UrlParameter.Optional } // Parameter defaults
);
Now I can get the url to appear when I click on a blog in the blogList. The page doesn't display the blog it displays a redirect loop message. If I omit the following code ...
if (ModelState.IsValid)
{
return RedirectToAction("BlogPost", new { id = id });
}
then I can display the blog. The url wont have the id value. Like this...
http://localhost/blog/blogpost/
What am I doing wrong?
The following code should work with your route:
// http://localhost/blog/bloglist
public ActionResult BlogList()
{
return View(_repository); // show all blog posts
}
// http://localhost/blog/blogpost/1
public ActionResult BlogPost(int? id = null)
{
if (id.HasValue == false || id.Value < 1)
{
// redirect to 404 page or BlogList
throw new NotImplementedException();
}
var blogPostObj = _repository.Find(id.Value);
if (blogPostObj == null)
{
// again redirect to 404
throw new NotImplementedException();
}
return View(blogPostObj);
}
Remove the BlogList() which takes 0 parameter
public ActionResult BlogList(){ return View(_repository); }
This is not required, since your id is type of string which can be null
The below code can be help you
public ActionResult BlogPost(string id)
{
var model=new ModelObject();
if(id!=null)
{
var model=Blogs.Find(id); //find it from repo
return View(model);
}
return View(model);
}
From your code it does not look like the id field is optional. Therefore I would change the route.
routes.MapRoute(
"MyBlog", // Route name
"blog/blogpost/{id}", // URL with parameters
new { controller = "Blog", action = "blogpost" },
new { id = #"(\d)+"} //ensures value is numeric.
);
RouteData.Values["id"] + Request.Url.Query

stackoverflow URL rewrite

How does SO perform the URL rewrite if we only put in the question ID?
questions/{id}/{whatever}
to
questions/{id}/{question-slug}
I've been working for some time with MVC and I have it working (routes, action, everything) so that it picks up the right content based on the provided ID.
However, the part after the {id} (the slug part) stays the same as typed in. So if someone typed in content/5/foobar it will display the right content but will leave the foobar in there.
In the controller (or somewhere else, please suggest where) I would need to go into the DB and pull out the right slug, put it in the route data and then perform a redirect to the same action with this correct data, I guess?
This is a try with Execute Result override. It works but does not redirect or replace/display the correct URL in browser:
protected override void Execute(System.Web.Routing.RequestContext requestContext) {
if (requestContext.RouteData.Values["id"] != null) {
string currentSlug = _repository.Find(int.Parse(requestContext.RouteData.Values["id"].ToString())).Slug;
if (requestContext.RouteData.Values["slug"] != null) {
requestContext.RouteData.Values.Remove("slug");
}
requestContext.RouteData.Values.Add("slug", currentSlug);
}
base.Execute(requestContext);
}
This is another, nicely working, version of a Display action, so you can see what it does and get an idea what I want:
//
// GET: {culture}/directory/5/{slug}
public virtual ActionResult Display(int id, string slug)
{
var model = _repository.Find(id);
if (model != null) {
if (!model.Slug.Equals(slug, System.StringComparison.OrdinalIgnoreCase)) {
return RedirectToActionPermanent(pndng.DirectoryEntry.ActionNames.Display, pndng.DirectoryEntry.Name, new { id = model.Id, slug = model.Slug });
}
return View(model);
}
// no model found
return InvokeHttp404(HttpContext);
}
This one performs permanent redirect (it does what I want) but is it right?
I guess I need a redirect to refresh the browser URL, don't I?
public ActionResult Details(int id, string slug)
{
var session = MvcApplication.CurrentRavenSession;
var blogPostRelations = session
.Query<BlogPost, BlogPosts_WithRelatedData>()
.Where(x => x.IntId == id)
.As<BlogPostRelations>()
.FirstOrDefault()
;
if (blogPostRelations == null)
return HttpNotFound();
if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });
return View(blogPostRelations);
}
Notice the:
if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });
So your #2 approach is the right one.
You could write a custom route for this:
public class QuestionsRoute : Route
{
public QuestionsRoute()
: base(
"questions/{id}/{slug}",
new RouteValueDictionary(new
{
controller = "questions",
action = "index",
slug = UrlParameter.Optional
}),
new RouteValueDictionary(new
{
id = #"\d+"
}),
new MvcRouteHandler()
)
{ }
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
var id = rd.GetRequiredString("id");
var slug = rd.Values["slug"] as string;
if (string.IsNullOrEmpty(slug))
{
slug = GoFetchSlugFromDb(id);
if (string.IsNullOrEmpty(slug))
{
return null;
}
httpContext.Response.RedirectToRoutePermanent(new
{
action = "index",
controller = "questions",
id = id,
slug = slug
});
return null;
}
return rd;
}
private string GoFetchSlugFromDb(string id)
{
// TODO: you know what to do here
throw new NotImplementedException();
}
}
which will be registered in Application_Start:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("questions", new QuestionsRoute());
}
Now your QuestionsController will be pretty simple:
public class QuestionsController: Controller
{
public ActionResult Index(int id, string slug)
{
...
}
}

ASP.NET MVC: Server Validation & Keeping URL paramters when returning the view

I currently have the following code for the POST to edit a customer note.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
else
{
var _customer = _customerRepository.GetCustomer(new Customer() { CustomerID = Convert.ToInt32(note.CustomerID) });
var _notePriorities = _customerRepository.GetNotePriorities(new Paging(), new NotePriority() { NotePriorityActive = true });
IEnumerable<SelectListItem> _selectNotePriorities = from c in _notePriorities
select new SelectListItem
{
Text = c.NotePriorityName,
Value = c.NotePriorityID.ToString()
};
var viewState = new GenericViewState
{
Customer = _customer,
SelectNotePriorities = _selectNotePriorities
};
return View(viewState);
}
}
If Validation fails, I want it to render the EditNote view again but preserve the url parameters (NoteID and CustomerID) for something like this: "http://localhost:63137/Customers/EditNote/?NoteID=7&CustomerID=28"
Any ideas on how to accomplish this?
Thanks!
This action is hit by using a post. Wouldn't you want the params to come through as part of the form rather than in the url?
If you do want it, I suppose you could do a RedirectToAction to the edit GET action which contains the noteId and customerId. This would effectively make your action look like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
//It's failed, so do a redirect to action. The EditNote action here would point to the original edit note url.
return RedirectToAction("EditNote", "Customers", new { id = note.CustomerID.ToString() });
}
The benefit of this is that you've removed the need to duplicate your code that gets the customer, notes and wotnot. The downside (although I can't see where it does it here) is that you're not returning validation failures.

Resources