Route with Two optional parameters in MVC3 not working - asp.net-mvc

I have a following types of url used in my Application.
localhost/admin/userdetail/id
localhost/admin/userdetail/id/true
localhost/admin/userdetail/id/true/success
Here is my Admin Controller
bool inSaveAction, string status are optional
[Authorize]
public ActionResult UserDetail(string Id, bool inSaveAction, string status)
{
}
[HttpPost, Authorize, ValidateAntiForgeryToken]
public ActionResult SaveUserDetail(UserDetailViewModel viewModel)
{
User userToSave = new User();
AdminService.UpdateUser(userToSave);
//This is calling the above function as it sending all 3 params
return RedirectToAction("UserDetail", new { Id = viewModel.Id,
inSaveAction = true, status = "success" });
}
Below case is not working
#Html.ActionLink("DisplayName", "UserDetail", new { id = Model.Id })
In Global.asax
routes.MapRoute("UserDetail",
"UserDetail/{id}",
new
{
controller = "Admin",
action = "UserDetail",
id = UrlParameter.Optional
}
);
I followed http://haacked.com/archive/2011/02/20/routing-regression-with-two-consecutive-optional-url-parameters.aspx
How can i make inSaveAction & status as optional parameter for my UserDetail action?

You're missing the parameters in your route config. In order to make this work with different parameters optional (as in Phil Haack's post), you need to define multiple routes
routes.MapRoute("UserDetail-WithStatus",
"UserDetail/{id}/{inSaveAction}/{status}",
new
{
controller = "Admin",
action = "UserDetail",
// nothing optional
}
);
routes.MapRoute("UserDetail-WithoutStatus",
"UserDetail/{id}/{inSaveAction}",
new
{
controller = "Admin",
action = "UserDetail",
// nothing optional
}
);
routes.MapRoute("UserDetail-WithoutSaveAction",
"UserDetail/{id}",
new
{
controller = "Admin",
action = "UserDetail",
id = UrlParameter.Optional
}
);
And then create links with:
#Html.ActionLink("Link", "Index", "Admin", new { id = 1, inSaveAction = true, success = "success" }, null)
You'll also need to set the optional parameters as nullable, otherwise you'll get exceptions if id or inSaveAction are missing.
public ActionResult UserDetail(int? id, bool? inSaveAction, string status)
{
}

Related

Url.routeUrl returns null (I've tried same questions)

Hi everyone I wanna get url like {Controller}/{action}/{postid}-{address}
but routUrl returns null please help me to solve it.(I'm newbie in MVC)
my route config is
routes.MapRoute(
name: "Post",
url: "Posts/Show/{postid}-{address}",
defaults: new { controller = "Posts", action = "Index", postid = "", address = "" }
);
and index.cshtml
#item.PostTitle
the url that generate is
http://localhost:59066/Posts/Show/1-Post-with-Featured-Image
but in PostsController
public ActionResult Show(string add)
{ return View();}
"string add" is null !
I wouldn't change the Routes...
try this...
#item.PostTitle
This will send PostId and Address as parameters, so you can get them in the controller like:
public ActionResult AwesomeThings(int PostId, String Address)
{
var foo = PostId;
var bar = Address;
return View(model);
}
No changes in routing,
Index.cshtml:
#item.PostTitle
Controller:
public ActionResult Show(string postid, string address)
{ return View();}
I changed the route to
routes.MapRoute("Post", "post/{postid}-{address}", new { controller = "Posts", action = "Show" ,postid="",address=""}, namespaces);
and added a route with same controller and action
routes.MapRoute("PostAddress", "post/{IdAndAdd}", new { controller = "Posts", action = "Show" }, namespaces);
routes.MapRoute("Post", "post/{postid}-{address}", new { controller = "Posts", action = "Show" ,postid="",address=""}, namespaces);
then action received "idAndAdd" correctly
public ActionResult Show(string idAndAdd)
{
var parts = SeperateAddress(idAndAdd);
if (parts == null)
return HttpNotFound();
var post = db.Posts.Find(parts.Item1);
if (post == null)
return HttpNotFound();
if (!post.Address.Equals(parts.Item2, StringComparison.CurrentCultureIgnoreCase))
return RedirectToRoutePermanent("Post", new { postid = parts.Item1, address = post.Address });
return View(post);
}
and it's worked .

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

Incorrect URL in passing value from Html.AtionLink to controller

My Controller:-ForumController
Action:Topic
ViewPage to pass parameter is
<%= Html.ActionLink("Topic", "Topic", "Forum", new { userid = "1" }, null)%>
Controller
public ActionResult Topic(String userid)
{
var topics = new topic { userId = userid };
return View(topics);
}
The parameter is getting passed but instead of getting URL Forum/Topic/1,I am getting Forum/Topic?userid=1;
Can anyone help me out
I suspect that you used the default route in Global.asax in which you have {controller}/{action}/{id}.
So you should use the same name (id):
<%= Html.ActionLink("Topic", "Topic", "Forum", new { id = "1" }, null)%>
and then:
public ActionResult Topic(String id)
{
var topics = new topic { userId = id };
return View(topics);
}
If you don't want to use {id} but some other token make sure you adjust your routes accordingly.

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)
{
...
}
}

MVC RouteDatas are confused

I am using asp.net mvc for my website project. I think i have wrong things in my routedata but i am not sure it is wrong or ok. i will explain the situation.
I am caching my action results (html outputs) in Cache with a generated key
public static string GetKeyFromActionExecutingContext(ControllerContext filterContext)
{
StringBuilder keyBuilder = new StringBuilder();
if (filterContext.IsChildAction)
keyBuilder.Append("C-");
else
keyBuilder.Append("P-");
foreach (var item in filterContext.RouteData.Values)
{
keyBuilder.AppendFormat("{0}={1}.", item.Key, item.Value);
}
return keyBuilder.ToString();
}
ex: For HomePage , generated cache key is P-Controller=Home.Action=Index and
I have also childactions in my sitemaster like LoginBox(It is in MembershipController/LoginBox)
Its cache key is C-Controller=Membership.Action=LoginBox.
Everything is okey till now.
I have also subcategories in my website like
domain/category1
domain/category1/subcategory1
domain/category1/subcategory2
domain/category2
When i am browsing a sub category from domain/category1
My generated keys are failed because my routedatas are wrong
filterContext.RouteData.Values:
Controller = Membership
Action = LoginBox
ctg1 = category1
ctg2 = ""
ctg3 = ""
Why these are mixed. It is using the "Category" routemapping but I think it must use "Default" routemapping.
My global.asax like below
routes.MapRoute(
"Category",
"{ctg0}/{ctg1}/{ctg2}/{ctg3}",
new
{
controller = "Category",
action = "Index",
ctg0 = "",
ctg1 = "",
ctg2 = "",
ctg3 = ""
},
new
{
ctg0 = new CategoryRouteConstraint(),
}
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" },
new { controller = #"[^\.]*" }
);
Also my CategoryRouteConstraint Method it is checking from db that ctg0 value is a category name
public class CategoryRouteConstraint : IRouteConstraint
{
public Boolean Match(
HttpContextBase httpContext,
Route route,
String sParameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
if ((routeDirection == RouteDirection.IncomingRequest))
{
if (values["ctg0"] != null && !string.IsNullOrEmpty(values["ctg0"].ToString()))
return Category.IsRoutingForCategory(values["ctg0"].ToString());
return false;
}
return false;
}
}
Hopefully this may help you, it will show you which routes a url matches, I was a little confused by the question.
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx

Resources