I try to pass a param in url but my param is always null :
View :
#using (Html.BeginForm("ReferenceSearch/cab", "ProductResultList"))
{
<button type="submit" class="btn btn-default">test</button>
}
The action :
public ActionResult ReferenceSearch(string reference)
{
...
I did exactly the same in anonther place, and this one is working :
View :
#using (Html.BeginForm("Login/cab/la", "Authentication"))
{
<button type="submit" class="btn btn-default">testAuth</button>
}
The action :
public ActionResult Login(string fromcontroller, string fromAction, string param)
{
My routes :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Auth",
"{controller}/{action}/{fromController}/{fromAction}/{param}",
new { controller = "Authentication", action = "Login", fromcontroller = "", fromaction = "", param = "" });
routes.MapRoute(
"ReferenceSearchAfterLogin",
"{controller}/{action}/{reference}",
new { controller = "ProductResultList", action = "ReferenceSearch", reference = "" });
}
Can you tell me what's wrong?
#using (Html.BeginForm("ReferenceSearch", "ProductResultList"))
{
<button name ="reverence" value="submit" type="submit" class="btn btn-default">test</button>
}
The action :
public ActionResult ReferenceSearch(string reference)
{
//reference has now the Value submit
}
This is what method BeginForm should have:
Html.BeginForm(actionName, controllerName, routeValues)
The better way to pass any value in query string (or url) is to add data in routeValues part. actionName and controllerName should be used only to specific the Action and Controller where to send the request. So change your forms in this way:
Html.BeginForm("ReferenceSearch", "ProductResultList", new { #reference = "tab" })
In this way you shouldn't be any problems with routing.
Related
I have statically mapped all controllers except one ... a LookupController that I would like to operate off root.
Here are my routes:
routes.MapRoute(
name: "Root",
url: "",
defaults: new {controller = "Home", action = "Index"}
);
routes.MapRoute(
name: "Home",
url: "home/{action}/{id}");
routes.MapRoute(
name: "User",
url: "user/{action}/{id}");
routes.MapRoute(
name: "Company",
url: "company/{action}/{id}");
routes.MapRoute(
name: "Recruiter",
url: "recruiter/{action}/{id}");
routes.MapRoute(
name: "Lookup",
url: "{company}/{recruiter}",
defaults: new { controller = "Lookup", action = "Index" }
);
Everything works fine EXCEPT the last entry for Lookup.
This breaks everything, including the other routes.
Basically, I want my URLs to be:
/Home
/User
/Company
/Recruiter
/{company}/{recruiter}
Any idea how I can accomplish this?
Thank you very much in advanced!
EDIT: Adding LookupController by request:
public class LookupController : Controller
{
private RecruiterSightContext db = new RecruiterSightContext();
// GET: Lookup
public ActionResult Index(string company, string recruiter)
{
if (string.IsNullOrEmpty(company) && string.IsNullOrEmpty(recruiter))
{
TempData["errorMessage"] = "No Company or Recruiter specified in URL";
return RedirectToAction("Index", "Home");
}
// Company lookup
if (string.IsNullOrEmpty(recruiter))
{
Company foundCompany = db.Companies.FirstOrDefault(c => company.ToLower().Equals(c.Slug.ToLower()));
if (foundCompany == null)
{
return RedirectToAction("Index", "Home");
}
return RedirectToAction("Display", "Company", new {companyId = foundCompany.CompanyId});
}
Recruiter foundRecruiter = db.Recruiters.FirstOrDefault(r => r.Slug.ToLower().Equals(recruiter.ToLower()));
if (foundRecruiter == null)
{
return RedirectToAction("Index", "Home");
}
return RedirectToAction("RecruiterView", "Recruiter", new {recruiterId = foundRecruiter.RecruiterId});
}
}
If your Lookup folder exists:
try to change:
from:
routes.MapRoute(
name: "Lookup",
url: "{company}/{recruiter}",
defaults: new { controller = "Lookup", action = "Index" }
);
to:
routes.MapRoute(
name: "Lookup",
url: "company/recruiter",
defaults: new { controller = "Lookup", action = "Index" }
);
then in your Browser
Add like this:
company/recruiter
If your Lookup is different of index then i think you need to create another function that calling your Lookup like:
routes.MapRoute(
name: "Lookup",
url: "company/recruiter",
defaults: new { controller = "Lookup", action = "LookupWithParameter" }
);
then in your Controller:
public ActionResult LookupWithParameter(String Company, string recruiter)
And don't forget to create another .cshtml file to redirect the page of your Lookup which is located at your Lookup folder
Here's the scenario:
Assuming that you are currently working at your Index.cshtml page which in your Home Controller then you want to redirect into Lookup page.
Index(Home) .cshtml file:
<div id="content">
#{
if (IsPost) {
<!--this option if you don't need to change another page-->
string company = Request["Company"];
string recruiter = Request["Recruiter"];
<p>You entered: <br />
Company Name: #company <br />
Recruiter Name: #recruiter</p>
}
else
{
<form method="post" action="company/recruiter">
Company Name:<br />
<input type="text" name="Company" value="" id="idcompany" /><br />
Contact Name:<br />
<input type="text" name="Recruiter" value=""id="idrecruiter" /><br /><br />
<input type="submit" value="Submit" class="submit" />
</form>
}
}
</div>
LookupController:
public class LookupController : Controller
{
//
// GET: /Lookup/
public ActionResult MyLookup(string Company, string Recruiter)
{
// this is how to pass the value of parameter company and recruiter input from index.
//Your Action here and you can use to Debug while runnning notice that the company and the recruiter has a content from index home input
return View();
}
}
RouteConfig.cs
routes.MapRoute(
name: "Lookup",
url: "company/recruiter",
defaults: new { controller = "Lookup", action = "MyLookup" }
);
Make sure that you have a Lookup folder that contains MyLookup.cshtml
I have a blogging application and users are able to create posts, I used Entity framework to create the model from the database. In Posts I have an entry for UrlSlug.
However when I check the details of a post:
Controller:
public ActionResult Details(int id = 0)
{
Post post = db.Posts.Find(id);
if (post == null)
{
return HttpNotFound();
}
return View(post);
}
It returns a url with id at the end: http://localhost:52202/Post/Details/1
I have tried returning post.UrlSlug (throws an error) aswell as changing my RouteConfig.cs file to use urlslug instead of id (which does display the urlslug, but it cant find the page because of the controller). How can I change this so urlslug is displayed instead of the Post Table Id?
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
View:
#for (int i = 0; i < Model.Count(); i += 3)
{
<div class="row">
#foreach (var item in Model.Skip(i).Take(3))
{
<div class="col-md-4 portfolio-item">
<a href="#Url.Action("Details", "Post", new { id = item.Id })">
<img class="img-responsive" src="http://placehold.it/700x400" alt="">
</a>
<h3>
#Html.DisplayFor(modelItem => item.Title)
</h3>
<p>#Html.DisplayFor(modelItem => item.ShortDescription)</p>
</div>
}
</div>
}
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, pageSize = Model.PageSize }))
Edit
An issue I noticed is on this line:
public ActionResult Details(string urlslug)
{
Post post = db.Posts.Find(urlslug); //find only finds an eitity with a given primary key, how can I change this to find the string urlslug
An action method does not dictate the URL, it only matches a request. You need to print the slug:
#Url.Action("Details", "Post", new { slug = item.Slug })
Then add to the routing to support the URL structure you want:
routes.MapRoute(
name: "PostWithSlug",
url: "Post/Details/{slug}",
defaults: new { }
And alter the action method:
public ActionResult Details(string slug)
{
}
But besides that, you do want an ID in the URL. Otherwise you can't use the same post title twice.
You can either rename your argument in your controller to match the 'slug' name. So instead of
public ActionResult Details(int id = 0)
Use
public ActionResult Details(int urlslug = 0)
Alternative is to remove id from your route config like
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Keep in mind, what ever you argument name is in your Action, that name is used as the GET variable in your url. So if the argument is int id, then your url must be like ?id=1.
An issue I noticed on the below line:
public ActionResult Details(string urlslug)
{
Post post = db.Posts.Find(urlslug); //find only finds an eitity with a given primary key, how can I change this to find the string urlslug
You can select data with the help of urlslug by using Where instead of Find
i.e. Post post = db.Posts.Where(x=> x.urlslug == urlslug).FirstOrDefault();
How to change nopcommerce default action?
I create new action in HomeController, and want to be default page.
I change:
routes.MapRoute(
"",
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "Nop.Web.Controllers" }
);
To:
routes.MapRoute(
"",
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "NewAction", id = UrlParameter.Optional },
new[] { "Nop.Web.Controllers" }
);
But nothing has changed.
When you navigate to /Home/Index, MVC parses route as follows:
Controller: Home
Action: Index
Id:
If you navigate to /Home:
Controller: Home
Action: NewAction (from route's default action)
Id:
You can make it always activate NewAction like this:
routes.MapRoute(
"",
"{controller}/{id}", // URL with parameters
new { controller = "Home", action = "NewAction", id = UrlParameter.Optional },
new[] { "Nop.Web.Controllers" }
);
You can try like this.
//your default action
public ActionResult Index()
{
return RedirectToAction("NewAction"); //Like Response.Redirect() in Asp.Net WebForm
}
//your new action
public ActionResult NewAction()
{
//some code here
return view();
}
This question is really similar to my last one but this has to do with passing multiple parameters. My controller has two methods with the same name but one gets passed a nullable int to determine which action to take on post (I don't know if that's a good design decision). Here's the code:
public ActionResult EventDetails(int? eventID)
{
EventDetailsViewModel model = new EventDetailsViewModel();
if (eventID != null)
{
model.afterPost = false;
model.currentAttendance = getCountAttending(eventID);
model.currentUser = getCurrentUserProfile(User.Identity.Name);
model.eventDetails = getEventDetails(eventID);
model.eventRestrictions = getEventRestrictions(eventID);
model.usersAttending = getUsersAttending(eventID);
return View(model);
}
else
{
return View();
}
}
[HttpPost]
public ActionResult EventDetails(int? eventID, int? action)
{
EventDetailsViewModel model = new EventDetailsViewModel();
if (eventID != null)
{
model.afterPost = true;
model.currentAttendance = getCountAttending(eventID);
model.currentUser = getCurrentUserProfile(User.Identity.Name);
model.eventDetails = getEventDetails(eventID);
model.eventDetails["ActionID"] = action.ToString();
model.eventRestrictions = getEventRestrictions(eventID);
model.usersAttending = getUsersAttending(eventID);
return View(model);
}
else
{
return View();
}
}
the view is huge but I'll post the relevant piece:
#if(User.Identity.IsAuthenticated)
{
if (!Model.eventDetails["Event_Owned"].Equals("true"))
{
<div class="joinEventButton">
#if(Model.eventDetails["Event_Current"].Equals("true"))
{
<form method="post" action="#Url.Action("EventDetails", "Event", new{eventID = Int32.Parse(Model.eventDetails["EventID"]), action = Int32.Parse(Model.eventDetails["CODE_RequestInvitation"])})">
<input type="submit" value="Request Invitation" class="submitButton submitButton-green"/>
</form>
}
else
{
<button class="disabledButton disabledButton-grey">Request Invitation</button>
}
</div>
}
and just for good measure, my routes:
public static void RegisterRoutes(RouteCollection routes)
{
//routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
So the idea is that based on authentication and whether they own a specific event they are looking at, they will have different buttons show on the screen. This certain one is for when they want to join an event they can push a button to request an invitation. The controller knows this because of the int value being passed back as CODE_RequestInvitation. The action being returned is always null. I can't figure out what's wrong.
You problem is the use of the parameter name action (which is conflicting with the action attribute). Change it to another name and it will work. Inspect he html of the <form> element before and after the change.
You code for generating the form is awful and the use of Int32.Parse() is pointless.
#using (Html.BeginForm("EventDetails", "Event", { eventID = Model.eventDetails["EventID"], actionID = Model.eventDetails["CODE_RequestInvitation"] }, FormMethod.Post))
{
<input type="submit" value="Request Invitation" class="submitButton submitButton-green"/>
}
and post back to
[HttpPost]
public ActionResult EventDetails(int? eventID, int? actionID)
I'm looking to have a SEO friendly route for my blog using MVC 4. I have looked over several stackoverflow articles and tried to utilize the advise but, I still cant get it to work properly.
What I am try to do is when someone clicks on one of the blog post, the route displays:
blog/{blogCategory}/{blogTitle}, for example "blog/cleaning/how-to-remove-stains". I am missing something important. I have included the controller, view and route. I have two questions:
Why when I pass the blogTitle ("The rain in spain") to the controller it comes in with hyphens and spaces? I want to be able to take the title and run it through a function to make it URL friendly and put it back out to be displayed in the route.
Why does the route only partially work? Instead of displaying blog/{blogCategory}/{blogTitle} it displays blog/{blogCategory}?querystrings see example below: blog/uncategorized/the%20-rain%20in%20-spain%20-falls%20-mainly%20on%20the%20-plains?id=2. (Note: uncategorized is one of the categories)
ROUTE CONFIG:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.Canonicalize().NoWww().Pattern("([a-z0-9])([A-Z])", "$1-$2").Lowercase().NoTrailingSlash();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Blog",
"Blog/{blogCategory}/{blogTitle}",
new { controller = "Blog", action = "Details" }
).RouteHandler = new Spotless_Interiors.Models._GlobalClasses.HyphenatedRouteHandler();
// Original route map
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new Spotless_Interiors.Models._GlobalClasses.HyphenatedRouteHandler();
}
}
VIEW:
#model Spotless_Interiors.Models.MultiModels
#{
ViewBag.Title = "Blog";
ViewBag.Separator = " | ";
ViewBag.Path = Request.Path;
}
#section menuLeft {
#Html.Partial("_BlogMenu")
}
#Html.Partial("_TitleBlockPartial", Model.Company)
#if (User.Identity.IsAuthenticated) {
<div class="blog-links">
#Html.ActionLink("Create New", "Create", "Blog", new { DT_Stamp = #DateTime.Now })
#ViewBag.Separator
<a href="#Url.Action("Meta-Tag-Editor", "Dashboard", new { pageName = (string)ViewBag.pageName, path = (string)ViewBag.Path })" >MetaTag</a>
<hr />
</div>
}
<div id="blog">
#foreach (var item in Model.PagedPosts)
{
<h1>#Html.ActionLink(item.Title, "Details", new { id = item.PostID, blogCategory = item.Category.CategoryName, blogTitle = item.Title }, new { #class ="blog-title" }) </h1>
<div class="full-width">
<div class="blog-category">
<h2>#Html.DisplayFor(modelItem => item.Category.CategoryName) | #Html.DisplayFor(modelItem => item.DT_Stamp)</h2>
</div>
<div class="blog-links">
#Html.ActionLink("Read More >>", "Details", new { id = item.PostID, blogCategory = item.Category.CategoryName, blogTitle = item.Title }, new { #class ="blog-links" })
</div>
</div>
<div class="full-width">
</div>
#Html.Raw(Server.HtmlDecode(item.TruncatedBody.Replace("<img ", "<img style = 'width:100px' ")))
<div class="ribbon" style="clear:both"></div>
}
</div>
CONTROLLER:
// GET: /Blog/Details
public ActionResult Details(int id = 0, string blogCategory = "", string blogTitle = "")
{
pageName = "Blog Details";
ViewBag.pageName = pageName;
var multiModels = _globalClasses.Standard(ViewBag.pageName, Request.Path);
///multiModels.Post = db.Posts.First(i => i.PostID == id);
multiModels.Post = db.Posts.First(i => i.PostID == id);
multiModels.PostComments = db.PostComments.Where(i => i.PostPostID == id).ToList();
blogTitle = _globalClasses.UrlFriendly(blogTitle);
if (multiModels.Post == null)
{
return HttpNotFound();
}
return View(multiModels);
}
Perhaps your custom extension methods Canonicalize(?) and custom route handlers mess things up.
Concerning ASP.NET MVC this is enough:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(name:"Blog", url:"Blog/{blogCategory}/{blogTitle}",
defaults:new {controller = "Blog", action = "Details"});
routes.MapRoute(name:"Default", url:"{controller}/{action}/{id}",
defaults:new {controller = "Home", action = "Index", id = UrlParameter.Optional});
}
And controller:
public class BlogController : Controller
{
public ActionResult Details(string blogCategory, string blogTitle)
{
return Content(string.Format("category: {0}, title: {1}", blogCategory, blogTitle));
}
}
For path /blog/my%20category/my%20title, you get correct response "category: my category, title: my title".