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)
Related
I am working with adding a new MVC page and have the method and calls up and running. My issue is that I am not wanting to pass in URL parameters to show in my page but need to pass in the parameters for the method when I do a redirect to my new page. Currently I have it set up like this:
Page.cs
void ToNewPage()
{
Response.RedirectToRoute(new { controller = "ControllerName", action = "ActionName", ID1 = 1, ID2 = 2 });
}
ControllerName.cs
public ActionResult ActionName(int ID1, int ID2)
{
...
return View(model);
}
Currently with my code I get the URL ~/ControllerName/ActionName?ID1=1&ID2=2. I am just wanting the URL to just be ~/ControllerName/ActionName. I know this would be easier on a frontend or maybe through javascript but needing to do this from the ToNewPage method if possible.
There are working codes:
PageController.cs
public class PageController : Controller
{
// GET: Page
public ActionResult Index()
{
return View();
}
public ActionResult ToNewPage()
{
var ids = Newtonsoft.Json.JsonConvert.SerializeObject(new { ID1 = 1, ID2= 2 });
TempData["ids"] = ids;
return RedirectToAction("Index", "NewPage");
}
}
NewPageController.cs
public class NewPageController : Controller
{
// GET: NewPage
public ActionResult Index()
{
if (TempData["ids"] != null)
{
dynamic ids = JsonConvert.DeserializeObject(TempData["ids"] as string);
ViewBag.ID1 = ids.ID1;
ViewBag.ID2 = ids.ID2;
}
return View();
}
}
NewPage\Index.cshtml
#{
ViewBag.Title = "Index";
}
<h2>NewPage</h2>
<ul>
<li>ID1: #ViewBag.ID1</li>
<li>ID2: #ViewBag.ID2</li>
</ul>
You should use TempData:
void ToNewPage()
{
TempData["ID1"]="ID1 Value"
TempData["ID2"]="ID2 Value"
Response.RedirectToRoute(new { controller = "ControllerName", action = "ActionName"
});
}
public ActionResult ActionName()
{
int ID1=int.parse(TempData["ID1"].ToString());
int ID2=int.parse(TempData["ID2"].ToString());
return View();
}
You can fill many TempDatas in many controllers and use them in many Views and controllers
Here my view.i want to pass TempData[Id] to HttpGet controller action method Index.how can i pass this values.pleae help me.thanks in advance
#if (TempData["Id"] != null)
{
using (Html.BeginForm("Index", "QuestionnaireController", FormMethod.Get))
{
<p>#SixSeconds.App_GlobalResources.Frontend.DeleteQuestionnaire</p> <input type = "submit" value = "#SixSeconds.App_GlobalResources.Frontend.OK"/>
}
}
[HttpGet]
public ActionResult Index(string idQ, string idTT, string easyLoad)
{
Project project = _getProject(idQ);
ViewBag.LanguageCode = project.ItemLanguage.Code;
ViewBag.projectType = project.ProjectType.ToString();
per ricevere un questionario
int reportCredits = 0;
foreach (ProjectReportOption pro in project.ProjectReportOptions)
{
reportCredits += pro.Display && pro.ReportType != null ? pro.ReportType.Credits : 0;
}
You can pass the data as route values:
#using (Html.BeginForm("Index", "QuestionnaireController", new { idQ = TempData["Id"] }, FormMethod.Get))
{
}
And you need to define the route:
routes.MapRoute("NameOfThisRoute",
"QuestionnaireController/Index/{idQ}",
new { controller = "QuestionnaireController", action = "Index" });
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.
Below is a very simple MVC triplet, implemented to try the things out.
It seems to work except the bit new { id = Model.StatusCode } in View, which is supposed to take the current value of Model.StatusCode and pass it as the parameter to the controller. It always pass '200', the initial value of the StatusCode (numeric value of 'Model.StatusCode'), although I change the value in the input field before hitting Submit button. How can I change my code to fix it?
I need to pass the parameter to the controller as string id since thsi controller's action is also used in routing.
Model
public class ErrorModel
{
[DisplayName("Status Code")]
public string StatusCode { get; set; }
public ErrorModel(string statusCode)
{
HttpStatusCode code;
if (! Enum.TryParse(statusCode, out code))
{
code = HttpStatusCode.NotFound;
}
StatusCode = ((int)code).ToString();
}
public ErrorModel(HttpStatusCode statusCode = HttpStatusCode.OK)
{
StatusCode = ((int)statusCode).ToString();
}
}
View
#using WebApplication1.Models
#model WebApplication1.Models.ExcelModel
#using (Html.BeginForm("StatusCode", "Error",
new { id = Model.StatusCode }, FormMethod.Post, null))
{
<p>
<div class="editor-label">
#Html.LabelFor(model => model.StatusCode)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StatusCode)
</div>
<input type="submit" value="Submit" />
</p>
}
Controller
public class ErrorController : Controller
{
static readonly List<HttpStatusCode> ErrorCodes = new List<HttpStatusCode>(){
HttpStatusCode.Unauthorized, HttpStatusCode.Forbidden, HttpStatusCode.NotFound, HttpStatusCode.InternalServerError};
public ActionResult StatusCode(string id)
{
ViewBag.Message = "";
if ((id == null) || (ErrorController.AreEqual(HttpStatusCode.OK, id)))
{
return View("StatusCode", new ErrorModel(HttpStatusCode.OK));
}
foreach (HttpStatusCode errorCode in ErrorCodes)
{
if (ErrorController.AreEqual(errorCode, id))
{
return View("HttpError", new ErrorModel(errorCode));
}
}
ViewBag.Message = "Exception " + id
+ #" is not supported, see https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx for further details";
return View("HttpError", new ErrorModel(HttpStatusCode.InternalServerError));
}
static private bool AreEqual(HttpStatusCode httpCode, string statusCode)
{
return (statusCode == ((int)httpCode).ToString());
}
}
The overload you are using Html.BeginForm will append the routevalues to the form action attribute value. So the markup of your form will be like
<form action="Error/StatusCode/200">
<input type="text" name="StatusCode" />
</form>
When the form is posted, Model binder/Route engine will map the 200 value to the Id parameter because it matches our default route configuration {controllername}/{actionname}/{id}. That is the reason you are getting the initial value but not the updated value from form.
What you should do is use change the name of the input field rendered by Html.EditorFor helper method to match to the action parameter name (Id) . so that it will overwrite the values in the Url. You can use a different overload of the EditorFor method for that. You can totally get rid of the routevalues param from your BeginForm call since your form is going to post a field with name Id.
#using (Html.BeginForm("StatusCode", "Home" ,FormMethod.Post, null))
{
#Html.EditorFor(model => model.Name,null,"Id")
<input type="submit" />
}
This will render the input field with the name property value "Id" and when you post the form, The current value of this field will be mapped to your action method parameter.
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();