I currently have two partial views on a single page, added with:
#Html.Action("_LogonBox","Account")
#Html.Action("_TrackingBox","Tracking")
each has its own form and model...
but if I enter values into the _logonbox view and submit it it causes the validation to fire on the TrackingBox and because the values in tracking box are empty it highlights the textboxes as errors.
How do I sort this out, in webforms it was simply validationGroups?
EDIT
here is the markup:
LogOn View
#model Models.LogonModel
#using (Html.BeginForm("Login", "account", FormMethod.Post, new { Id = "Login" }))
{
<div class="boxwrapper">
<div class="loginbox">
<a href="#" style="float: right; color: #fff; font-size: 95%%; padding: 5px 10px;">Forgotten
Password?</a>
<h3>
My Account</h3>
<div class="content">
<fieldset class="logincontrols">
<table>
<tr>
<td class="loginlabel">
#Html.LabelFor(m => m.UserName)
</td>
<td class="logintextbox">
#Html.TextBoxFor(m => m.UserName, new { ValidationGroup = "Account" })
</td>
</tr>
<tr>
<td class="loginlabel">
#Html.LabelFor(m => m.Password)
</td>
<td class="logintextbox">
#Html.PasswordFor(m => m.Password, new { ValidationGroup = "Account" })
<input type="image" value="Sign In" src="/Content/Images/buttons/signin.png" style="vertical-align: bottom;" ValidationGroup="Account" />
</td>
</tr>
</table>
</fieldset>
</div>
</div>
</div>}
Tracking View
#model .Models.TrackingModel
#using (Html.BeginForm("Index", "Tracking", new { Id = "Tracking" }))
{
<div class="boxwrapper">
<div class="bluebox">
<fieldset class="logincontrols">
<h3>
Shipment Tracking</h3>
<div class="content">
<p style="text-align: left;">
Please enter your reference number:</p>
#Html.TextBoxFor(m => m.TrackingNumber)
<br />
<p style="text-align: right; margin-top: 10px;">
<input type="image" value="Track Shipment" src="/Content/Images/buttons/trackingbutton.png" /> </p>
</div>
<fieldset>
</div>
</div>
}
Further EDIT
added controllers as requested
public class TrackingController : Controller
{
//
// GET: /Tracking/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(TrackingModel model)
{
return View(model);
}
[HttpPost]
public PartialViewResult _TrackingBox(TrackingModel model)
{
return PartialView(model);
}
public PartialViewResult _TrackingBox()
{
return PartialView();
}
}
public class AccountController : Controller
{
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
public PartialViewResult _Logonbox()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _Logonbox(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
//do something here
}
// If we got this far, something failed, redisplay form
return PartialView(model);
}
}
I have managed to fix this, but if someone can comment on WHY this fixes it that would be great.
I changed the #Html.Action("_partialViewName") to #Html.Partial("_partialViewName"), and this caused the same problems.
To fix this I had to include a new model object as below.
#Html.Partial("_LogonBox", new TGEFreight.UI.Web.Models.LogOnModel())
#Html.Partial("_TrackingBox", new TGEFreight.UI.Web.Models.TrackingModel())
As to why this works I dont know, this is probably due to my infancy with MVC, but this is the answer anyway.
Thanks for the help guys.
I'm guessing that both of these field sets are wrapped in the same <form>. You can get around this by having a separate <form> for each partial / child action.
Unlike webforms, MVC lets you take full advantage of HTML, meaning you can have more than 1 form on a page. In webforms, everything needed to be on 1 page so that viewstate could be persisted for the entire page during each postback.
If you are using jquery unobtrusive validation, validations only fire for the form that was submitted.
Edit
Sorry, I re-read your question and you say each of these has its own form. Can you show more of the razor markup? What does your submit button look like? Are there any jquery or javascript behaviors attached to the forms? Is validation firing on the client or the server?
Update
Have you tried using #Html.Partial instead of #Html.Action? Html.Action results in a new HTTP request to the child action method. What view does your login action on your account controller return? It could be that the login POST is calling the tracking action as a POST, and causing validation to fire on it.
I agree with #olivehour you should try using #Html.Partial instead of #Html.Action. Now when you say that if you use Partial that you can't define the action for them to use, what exactly do you mean. You should be able to define an HttpGet and HttpPost action without a problem for each of the partials, so for instance as an example you should be able to easily do the following:
public class AccountController : Controller
{
...
[HttpGet]
public ActionResult Login()
{
return PartialView();
}
[HttpPost]
public ActionResult Login(LoginModel model)
{
... Validate Model & additional logic
// return some redirect action
}
}
I noticed that in your post you are simply returning the PartialView again, was that just pseudo code? If not, at least for the login partial, I would assume that if someone logs in that the post action would redirect them to another page. In either case you would display the partial view by using #Html.Partial or #{Html.RenderPartial(...);} in your calling view. Hope that helps.
Related
I have a website where I need to redirect the users according to their role. On button click, if the user is admin, redirect to another page; else reload the same page. On button click, the index page is loaded no matter who logs in. On debugging I found out, the [HttpPost] attribute is not triggered at all.
View:
#model namespace.ViewModels.LoginVM
#{
ViewBag.Title = "Login";
}
<h1>User Login</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<br />
<div style="background-color: skyblue; width: 50%">
<div style="padding-left: 1em">
<div class="display-label" style="font-size: large">
Enter User Info<br />
<br />
</div>
<div>
<div class="editor-label">#Html.LabelFor(model => model.empID)</div>
<div class="editor-field">#Html.TextBoxFor(model => model.empID)
#Html.ValidationMessageFor(model => model.empID)
</div>
<br />
</div>
<br />
<div>
<input id="submit" type="submit" value="Submit" />
</div>
</div>
</div>
<br />
}
Controller:
public class LoginController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginVM model)
{
MySQL msql = new MySQL();
var empID= model.empID
var role = msql.Select("Select `role` from empDB where `eID` = '" + empID + "'");
if(role == "admin")
{
return RedirectToAction("Index","Home");
}
else
{
return View();
}
}
}
Your HttpPost action method name is Login. But your razor view, you used Index!
Update your Html.BeginForm method call to have the correct action method name and controllername values. Then when you click on submit, it will post the form data to /Login/Login
#using (Html.BeginForm("Login", "Login", FormMethod.Post))
{
}
I'm new to MCV and I'm learning MVC3. I created a model and a controller and view was generated for me. The generated code makes perfect sense to me. I wanted to modify the generated view and controller so that I could upload a file when I "create" a new record. There is a lot of good information out there about how to do this. Specifically I tried this: http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx
The problem is that even when I select a file (not large) and submit, there are no files in the request. That is, Request.Files.Count is 0.
If I create the controller and and view from scratch, in the same project (no model), the example works just fine. I just can't add that functionality to the generated page. Basically, I'm trying get the Create action to also send the file. For example, create a new product entry and send the picture with it.
Example Create view:
#model Product.Models.Find
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm("Create", "Find", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Find</legend>
<input type="file" id="file" />
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Example Controller:
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
if (Request.Files.Count > 0 && Request.Files[0] != null)
{
//Not getting here
}
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(find);
}
This will create the record just fine but there are not files associated with the Request.
I've also tried a controller action like this:
[HttpPost]
public ActionResult Create(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
//Not getting here
}
return RedirectToAction("Index");
}
I'm wondering if maybe you can't post a file at the same time as posting form fields? If that is the case, what are some patterns for creating a new record and associating a picture (or other file) with it?
Thanks
Create a ViewModel which has properties to handle your image and Product deatils
public class ProductViewModel
{
public string ImageURL { set;get;}
public string Title { set;get;}
public string Description { set;get;}
}
And in your HTTPGET Action method, return this ViewModel object to your strongly typed view
public ActionResult Create()
{
ProductViewModel objVM = new ProductViewModel();
return View(objVM);
}
And in your View
#model ProductViewModel
<h2>Add Product</h2>
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(m => m.Title) <br/>
#Html.TextBoxFor(m => m.Description ) <br/>
<input type="file" name="file" />
<input type="submit" value="Upload" />
#Html.HiddenFor(m => m.ImageURL )
}
Now in your HttpPost action method, accept this ViewModel and File
[HttpPost]
public ActionResult Create(HttpPostedFileBase file, ProductViewModel objVM)
{
if(file==null)
{
return View("Create",objVM);
}
else
{
//You can check ModeState.IsValid if you have to check any model validations and do further processing with the data here.
//Now you have everything here in your parameters, you can access those and save
}
}
You will have to create a ViewModel for Product (maybe ProductViewModel) and add a HttpPostedFileBase field with the same name as the field of the form and use that instead of the Product in the action of the controller.
A ViewModel is nothing but a model used for specific views. Most of the times, with extra data to generate the view or to decompose and form the model on the controller action.
public ProductViewModel
{
public string Cod { get; set; }
// All needed fields goes here
public HttpPostedFileBase File{ get; set; }
/// Empty constructor and so on ...
}
I have a login widget that is a partial view that I want updated with model validation errors when there is a problem otherwise the page should be reloaded.
I have the following
LogOn.cshtml
#{
var ajaxOpts = new AjaxOptions {OnSuccess = "success"};
}
<div id="login">
#Html.ValidationSummary(excludePropertyErrors: true)
<h2>Start by Logging in</h2>
#using (Ajax.BeginForm("LogOn", "Account", ajaxOpts))
{
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<table width="100%" border="0" cellspacing="0" cellpadding="5">
<tr>
<td>
<span class="bluey">Username:</span><br />
#Html.TextBoxFor(m => m.UserName, new {tabindex = "1", Class = "field"})
#Html.ValidationMessageFor(m => m.UserName, "*")
</td>
<td>
<span class="bluey">Password:</span><br />
#Html.TextBoxFor(m => m.Password, new {tabindex = "2", Class = "field"})
#Html.ValidationMessageFor(m => m.Password, "*")
</td>
</tr>
<tr>
<td>
<input name="login" type="submit" value="Submit" class="input_btn" tabindex="3" />
</td>
<td>#Html.CheckBoxFor(m => m.RememberMe) #Html.LabelFor(m => m.RememberMe) <span class="bluey"> | </span> #Html.ActionLink("Forgot Password?", "Password", "User")</td>
</tr>
</table>
}
</div>
<script>
function success(context) {
//var returnUrl = context.get_data().returnUrl;
//if (returnUrl) {
// window.location.href = returnUrl;
//} else {
$("#login").replaceWith(context);
//}
}
</script>
and the action that gets called is
[HttpPost]
public ActionResult LogOn(LogOnModel userDetails, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(userDetails.UserName, userDetails.Password))
{
FormsAuthentication.SetAuthCookie(userDetails.UserName, userDetails.RememberMe);
return Redirect(returnUrl);
}
ModelState.AddModelError("", "The username or password provided was incorrect");
}
return PartialView(userDetails);
}
I have it working so that when data is incorrect the partial view is redisplayed with errors however this part only works if I comment out the other lines of javascript in success(context) that are there for when the user logs in successfully and the page should be redirected.
Is there a better way to do this?
I did try returning anonymous objects with Json() that had a status property and either a returnUrl or Html however I could not figure out how to get the html that would have been generated by PartialView(userDetails) into the Json() call, and it seems like that might be the wrong way to go about things anyway.
You cannot redirect in an AJAX call. You could return a JSON object from the server pointing to the url to redirect to and then perform the actual redirect in your success callback.
function success(result) {
if (result.returnUrl) {
// the controller action returned JSON
window.location.href = returnUrl;
} else {
// the controller action returned a partial
$('#login').html(result);
}
}
Now in your controller action in case of success simply return the return url instead of redirecting:
return Json(new { returnUrl = returnUrl });
By the way you already seem to have the return url in the view: Request.Url.PathAndQuery. I don't see the point of having it transit to the server and back. You could simply return some JSON boolean indicating the success and perform the redirect in the success callback to the url.
I have a view with a couple of partial views that I bind to my model. For some reason, when I post, the model is empty, and I am not sure why.
Below is my ViewModel.
public class IndexViewModel
{
public bool AdvancedSearchOption { get; set; }
public bool ForceAdvanced { get; set; }
public bool ForceSimple { get; set; }
public string SimpleSearchCriteria { get; set; }
public string CustomerNumberCriteria { get; set; }
public string AccountNumberCriteria { get; set; }
public string NameCriteria { get; set; }
public string PhoneNumberCriteria { get; set; }
}
Here is my controller. I am filling in all the values of the viewmodel because I wanted to see if the values got to the partial views. They do get there, so it is just on the post that I am having issues.
public class HomeController : Controller
{
private ISecurityRepository SecurityRep;
public HomeController(ISecurityRepository repo)
{
SecurityRep = repo;
}
public ActionResult Index()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View(temp);
}
public ActionResult SimpleSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = true;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index",temp);
}
public ActionResult AdvancedSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = true;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria= "Acct";
temp.CustomerNumberCriteria= "Cust";
temp.NameCriteria= "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index", temp);
}
[HttpPost]
public ActionResult Index(IndexViewModel vm, FormCollection formCollection)
{
return View();
}
}
Here is my view
#model TRIOSoftware.Magnum.Models.IndexViewModel
#{
ViewBag.Title = "Search";
}
#if ((#Model.AdvancedSearchOption && #Model.ForceSimple != true) || #Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch")
}
else
{
#Html.Partial("SimpleSearch")
}
Here is my SimpleSearch partial view. I think if I can get this one working, the other will follow the same path. I do the post in the partial and I use jQuery to do it. I am not sure if either of these things could cause me issues or not. I only have all the hidden items in there because I didn't know if not having them was causing my issues.
#model TRIOSoftware.Magnum.Models.IndexViewModel
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
#using (Html.BeginForm("Index","Home"))
{
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
<div id="DefaultDiv" style="float:right">
<a id="DefaultAdvanced" href="#" class="ButtonClass">Default Simple Search</a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img src="../../Content/images/TRIO_transparent_image.gif"; alt="TRIO Software"; style="margin-left:150px; clear:left"/>
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
</div>
<div id="SearchSection" style="float: left" class="SearchText">
<img src="../../Content/images/Search.gif"; alt="Search"; style="float:left" />
</div>
<p style="clear:left;margin-left:400px">
#Html.ActionLink("Advanced Search", "AdvancedSearch", null, new { style = "clear:left" })
</p>
</div>
}
Here is the HTML code when viewing the simple search partial view:
<div id="main">
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
<form method="post" action="/">
<input type="hidden" value="False" name="ForceAdvanced" id="ForceAdvanced" data-val-required="The ForceAdvanced field is required." data-val="true">
<input type="hidden" value="False" name="AdvancedSearchOption" id="AdvancedSearchOption" data-val-required="The AdvancedSearchOption field is required." data-val="true">
<input type="hidden" value="False" name="ForceSimple" id="ForceSimple" data-val-required="The ForceSimple field is required." data-val="true">
<input type="hidden" value="Acct" name="AccountNumberCriteria" id="AccountNumberCriteria">
<input type="hidden" value="Cust" name="CustomerNumberCriteria" id="CustomerNumberCriteria">
<input type="hidden" value="Name" name="NameCriteria" id="NameCriteria">
<input type="hidden" value="Phone" name="PhoneNumberCriteria" id="PhoneNumberCriteria">
<div style="float:right" id="DefaultDiv">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="#" id="DefaultAdvanced" role="button"><span class="ui-button-text">Default Simple Search</span></a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img style="margin-left:150px; clear:left" alt="TRIO Software" ;="" src="../../Content/images/TRIO_transparent_image.gif">
<div class="SearchText" style="clear:left; float: left">
<label for="What_s_your_inquiry_:">What's your inquiry?:</label>
<input type="text" value="Testing" name="SimpleSearchCriteria" id="SimpleSearchCriteria" class="text-box single-line">
</div>
<div class="SearchText" style="float: left" id="SearchSection">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="SearchButton" ;="" href="#" role="button"><span class="ui-button-text"><img style="float:left" alt="Search" ;="" src="../../Content/images/Search.gif"></span></a>
</div>
<p style="clear:left;margin-left:400px">
<a style="clear:left" href="/Home/AdvancedSearch">Advanced Search</a>
</p>
</div>
</form>
</div>
How do I fix this problem?
Although you're selecting a partial to render, you're not passing it the model. There's an overloaded version of Html.Partial that takes a second argument that allows you to pass a model to it:
#Html.Partial("ViewName", Model);
So in your case, you'd use this:
#if ((Model.AdvancedSearchOption && Model.ForceSimple != true) || Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch", Model)
}
else
{
#Html.Partial("SimpleSearch", Model)
}
Also notice how I've removed the #s you were prefixing Model with. To better understand why, please see Introduction to ASP.NET Web Programming Using the Razor Syntax and a small reference for this same topic written by Phil Haack here.
I think #john-h hit the nail on the head with his answer. However, you might want to reduce the complexity you've created for yourself.
1) Since both ForceSimple and ForceAdvanced are Boolean, it would be assumed that when ForceAdvanced is true, then it's not "Simple", right? I'm not sure what other logic you have here.
2) Rather than creating two views and "posting" back to get the correct one, why not just use a parameter to set the search type? Or evaluate the security to set which one the user can execute. Here's an example:
Controller Actions:
//id is the search type: true is Advanced
public ActionResult Search(bool id) {
IndexViewModel viewModel = new IndexViewModel {
/* Do whatever logic here */
ForceAdvanced = (id) ? false : true,
AdvancedSearchOption = id
};
return View("search", viewModel);
}
[HttpPost]
public ActionResult Search(IndexViewModel model) {
//model.SimpleSearchCriteria = "Testing";
//model.PhoneNumberCriteria = "Phone";
return View("search", model);
}
Search View:
#using (#Html.BeginForm(new { id = #Model.AdvancedSearchOption })) {
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#if (Model.AdvancedSearchOption) {
<div>
#* if you really want, load your partial views here *#
<span>#Html.LabelFor(m => m.NameCriteria)</span>
#Html.EditorFor(m => m.NameCriteria, new { style = "width: 400px" })
<span>#Html.LabelFor(m => m.PhoneNumberCriteria)</span>
#Html.EditorFor(m => m.PhoneNumberCriteria, new { style = "width: 400px" })
</div>
}
else {
#* if you really want, load your partial views here *#
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
}
</div>
<div>
<input type="submit" value="Search" />
</div>
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
}
I had tried explicitly sending in the model to the partials with no luck. I believe that the partial views get the parent model by default if nothing is specified, so all I needed to do was to specify the model type in my partials, and I got the information.
I finally figured it out with a lot of trial and error. My issue was being caused by me trying to use jQuery to do a post. There must be some other things you need to do to update your model doing it this way. Once I changed it out and put an input control on the form for the post, I got all my data back from the parent and partial view in the controller.
I have a Partial view (Login, with username, password and Submit button), and the partial view is being used on my _layout (materpage).
So, on my _layout page, I have:
<div style="text-align: right">
#Html.Partial("_LoginPartial")
</div>
My _LoginPartial has the following code:
#if (Request.IsAuthenticated)
{
<textarea>Welcome!
[ #Html.ActionLink("Log Off", "Logout", "Account")]</textarea>
}
else
{
#Html.Partial("~/Views/Account/Index.cshtml")
}
The Index file to display the login box looks like this:
#using GalleryPresentation.Models
#model LoginModel
<script src="../../Scripts/jquery.validate.min.js" type="text/javascript"></script>
#using (Html.BeginForm("index", "Account"))
{
<table>
<tr>
<td>#Html.LabelFor(m => m.Username)</td>
<td>#Html.TextBoxFor(m => m.Username)</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Password)</td>
<td>#Html.PasswordFor(m => m.Password) kjkj</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Login"/></td>
</tr>
<tr>
<td colspan="2">#Html.ValidationSummary()</td>
</tr>
</table>
}
In my AccountCOntroller, I have the following code:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if(ModelState.IsValid)
{
var g = new GallaryImage();
var user = g.LoginUser(loginModel.Username, loginModel.Password);
if(user != null)
{
FormsAuthentication.SetAuthCookie(user.username, false);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid Username/Password");
}
return View(loginModel);
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
I have breakpoints on all methods - but they never get hit. Pressing the submit button simply changes my URL to:
http://localhost:8741/?Username=myusername&Password=mypassword
Can anyone spot the error I am making?
Since Html.BeginForm defaults to making GET requests, you are making a GET request with from your view. However, your action only accepts POST requests.
You can change #using (Html.BeginForm("index", "Account"))
to #using (Html.BeginForm("index", "Account", FormMethod.Post)).