Simple mvc routing issue - asp.net-mvc-4

I'm trying to submit a form from partial view, but keep getting 404.
Here's the form:
#model PMP.WebUI.Models.ViewModel.VMTakeQuiz
#using (Html.BeginForm("Quiz", "QuizController", FormMethod.Post, new { id = "take-quiz-form" }))
{
..
<input type="submit" name="LaunchQuiz" value="Launch Quiz!" class="submit-button" />
..
}
Here's the map route assignment (it's the second assignment after the usual ignore axd's one):
routes.MapRoute(
"Quiz",
"Quiz/Quiz",
new { controller = "Quiz", action = "Quiz" }
);
And here's the controller and its action:
public class QuizController : Controller
{
[HttpPost]
public ActionResult Quiz(VMTakeQuiz quiz)
{
return null;
}
}
What I'm getting is 404 on: Requested URL: /QuizController/Quiz
What should I change to route the form submit to the given action?

Pass just controller name without 'controller' postfix like
#using (Html.BeginForm("Quiz", "Quiz", FormMethod.Post, new { id = "take-quiz-form" }))
{
..
Requested URL should be: /Quiz/Quiz

For controller you don't need to append controller suffix with their names
#using (Html.BeginForm("Quiz", "Quiz", FormMethod.Post, new { id = "take-quiz-form" }))
Also try to have different name for your views and controllers. :)

Related

How to link from View in Area to the root controller?

I'm new to MVC, still learning ins and outs by converting .NET App to MVC.
I have trouble linking to another Action in my controller from the page inside of the "Area" section.
I created Areas and still have the default route set up.
The Area has the following structure:
Area
- Admin
- Controller
UserController.cs
-Model
-Views
User
Index.cshtml
Index.cshtml has a link that should call "Index" action in AccountController to open "Default" view:
<div class="pagenavigator">#Html.ActionLink("Main Menu", "Index", new { area = "", controller="Account" })</div>
The default structure of the application is the following:
- Controller
AccountController.cs
- Views
- Account
Default.cshtml
Login.cshtml
My default structure has also controller folder that has a controller with Login (default) action set in RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);
Here is Account Controller:
public class AccountController : Controller
{
public ActionResult Login(string returnUrl)
{
StringBuilder sb = new StringBuilder();
sb.Append("Web Security Administration Portal<br/><br/>");
ViewBag.ReturnUrl = returnUrl;
ViewBag.Message = sb.ToString();
return View();
}
public ActionResult Index()
{
return View("Default");
}
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
bool authenticated = Security.AuthenticateLANUser(model.UserName, model.Password);
if (!authenticated)
{
Session["authenticated"] = false;
System.Text.StringBuilder errorMsg = new System.Text.StringBuilder();
errorMsg.Append("Invalid Login/Password entered.");
errorMsg.Append("We were not able to authenticate you in in Active Directory based on the information entered, ");
errorMsg.Append("but we recorded your attempt for audit purposes.");
ModelState.AddModelError("", errorMsg.ToString());
return View(model);
}
else
{
return View("Default");
}
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
}
What should I do if I need to link to "Default" view defined under default application route, from Index.cshtml defined under Area, so when I click the link, my "AccountController" gets called with the correct "Index" action?
In short, I need to find out the way to link from "Area" section to a controller's action in default application section, so the another correct Action gets called, which is not specified in default route mapping
Right now, the link is broken.
When I view the link in the source, I see the following: <a href="/Account/Index">, but when I click on the link, I'm getting the error saying: The resource cannot be found with Requested URL: /login.aspx
Here is AdminAreaRegistration:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}

form submit always hit in mvc index method while enable unobtrusive javascript enabled

MY form element submit is not working while enable unobtrusive javascript mode. it always hits in index method. how to resolve this issue. while enable unobtrusive mode with form submit successfully.
public ActionResult Index()
{
var Data = value;
ViewBag.dataSource = Data;
return View();
}
public ActionResult frmbtn()
{
return View("Index");
}
[HttpPost]
public void Formposting()
{
// it not hit while enable unobtrusive in webconfig
. . .
}
You didn't show view code it's difficult to locate the problem. you can match your code with given below:
#using (Html.BeginForm("Formposting", "ControllerName", FormMethod.Post, new { id = "formid" }))
{
}
Donot forget to replace "ControllerName" with actual controller name.
Or if you have blank in beginform like below
#using (Html.BeginForm())
{
}
You need to add one more "Action" with httppost and model
public ActionResult Index(Your Model Here){ return View();}

ASP.NET MVC 4 - ListBoxFor, send selectedValue in ActionLink

I have a list of model. I want to retrieve the listBoxSelectedValue to send it in my actionLink to edit it.
This is my view :
#using (Html.BeginForm())
{
#Html.ListBoxFor(a => a.SelectedApplis, new SelectList(ViewBag.Applis,"ID","Name", Model.SelectedApplis))<br/>
#Html.ActionLink("Add","Create","Application")<br/>
#Html.ActionLink("Edit","Edit","Application", null, new { listAppId = Model.SelectedApplis})<br/>
#Html.ActionLink("Delete","Delete","Application")<br/>
}
I created a class "ListBoxApplication" with the List which will contain the selectedValue of the ListBox.
public class ListBoxApplication
{
public IEnumerable<int> SelectedApplis { get; set; }
public ListBoxApplication()
{
SelectedApplis = new List<int>();
}
}
I have 2 controllers : Application and Home
In HomeController, I created the model ListBoxApplication which contain the List. In my ViewBag.Applis, i have all my ApplicationModel.
public ActionResult Index()
{
ListBoxApplication listeApplis = new ListBoxApplication();
ViewBag.Applis = ApplicationModels.GetListApplications();
return View(listeApplis);
}
In my ApplicationController :
public ActionResult Edit(ListBoxApplication listAppId)
{
// I WANT TO RETRIEVE MY listAppId HERE, but it is always 'null'
return View();
}
So I think my problem is in the actionLink :
#Html.ActionLink("Edit","Edit","Application", null, new { listAppId = Model.SelectedApplis})
Me Edit Method is not is the actual controller (Home/Index). I need to send the selectedValue of my ListBox in my actionLink to (Application/Edit).
The listAppId is always 'null'. It doesn't retrieve the value... Is there a mistake in my actionLink ?
Thanks for advance
I don't believe that action links will trigger a postback to the server. Try this instead:
#Html.ActionLink("Delete","Delete","Application")<br/>
#Html.ActionLink("Add","Create","Application")<br/>
#using (Html.BeginForm("Detail","Application"))
{
#Html.ListBoxFor(a => a.SelectedApplis, new SelectList(ViewBag.Applis)) //not sure what the other params you had here were for, but it should work like this
<br/>
<input type="submit" name="Edit" value = "Edit"/>
#*added in response to comment*#
<input type="submit" name="Delete" value = "Delete"/>
<input type="submit" name="Add" value = "Add"/>
}
If you plan on having all of those buttons post back to the server, you could also use ajax (and javascript) to accomplish this same goal, without needing to write out a form for each individual button. Both ways would work just fine, multiple forms is technically easier though.
public ActionResult Detail(ListBoxApplication listAppId, bool Edit, bool Add, bool Delete)
{
if(//check your bools here){
}
return View();
}

Gracefully handling permalinks when using pushstate for partial view pagination

I'm looking for a clean way to handle permalinks when my application uses pushstate to load ASP.NET MVC partial views for pagination
If my controller returns a partial view (currently) then the permalink will display the partial view alone without the rest of the site defined by _Layout.cshtml.
If my controller return a regular view, the permalink works but loading the entire page into the container provided only for part of the page creates a type of Droste Effect.
The only solution I've found is to redirect the 404 to the homepage and navigate to correct page using the relevant portion of the url.
However, this prevents me from using my custom error page (which just happens to be an awesome error page).
Ok I figured out how to make this work with a double-controller setup.
NavigationController handles ajax calls and returns partial views (note there is no "Index")
public class NavigationController : Controller
{
public PartialViewResult Home()
{
return PartialView("Home", null);
}
public PartialViewResult About()
{
return PartialView("About", null);
}
...
}
Separate PermalinkController handles permalinks by returning entire regular Views (note this has an "Index" but no "Home":
public class PermalinkController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
...
}
Routes:
routes.MapRoute(
"PermalinkRouter",
"{action}",
new { controller = "Permalink", action = "Index" },
new { }
);
routes.MapRoute(
"NavigationRouter",
"Navigation/{action}/{id}",
new { controller = "Navigation", action = "Home", id = UrlParameter.Optional },
new { }
);
Views:
~/Views/Shared/_Layout.cshtml:
...
<header></header>
<div id="pageViewContainer">
#RenderBody()
</div>
<footer></footer>
...
~/Views/Navigation/Home.cshtml PartialView:
<div> Home Content </div>
~/Views/Permalink/Index.cshtml View:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("~/Views/Navigation/Home.cshtml", null)

Have Microsoft changed how ASP.NET MVC deals with duplicate action method names?

I might be missing something here, but in ASP.NET MVC 4, I can't get the following to work.
Given the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}
and it's view:
#{
ViewBag.Title = "Home";
}
#using (Html.BeginForm())
{
#Html.TextBox("order1")<br />
#Html.TextBox("order2")
<input type="submit" value="Save"/>
}
When start the app, all I get is this:
The current request for action 'Index' on controller type
'HomeController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index() on type
ViewData.Controllers.HomeController System.Web.Mvc.ActionResult
Index(System.String, System.String) on type
ViewData.Controllers.HomeController
Now, in ASP.NET MVC 3 the above works fine, I just tried it, so what's changed in ASP.NET MVC 4 to break this?
OK there could be a chance that I'm doing something silly here, and not noticing it.
EDIT:
I notice that in the MVC 4 app, the Global.asax.cs file did not contain this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
which the MVC 3 app does, by default. So I added the above to the MVC 4 app but it fails with the same error. Note that the MVC 3 app does work fine with the above route. I'm passing the "order" data via the Request.Form.
EDIT:
In the file RouteConfig.cs I can see RegisterRoutes is executed, with the following default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I still get the original error, regards ambiguity between which Index() method to call.
Because MVC4 ships with ASP.Net Web.API you can potentially reference two HttpPostAttribute (the same applies to the other attributes like HttpGet, etc.):
System.Web.Mvc.HttpPostAttribute is used by ASP.Net MVC so you need to use it on actions inside Controller derived controllers
System.Web.Http.HttpPostAttribute is used by ASP.Net Web.API so you need to use it on actions inside
ApiController derived controllers
You have acidentally referenced System.Web.Http.HttpPostAttribute in your code. Change it to use the right attribute and it should work correctly:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[System.Web.Mvc.HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}