How do you check the value that has been entered in an ASP.NET MVC #Html.TextBox and compare it with a value in the database? I want to make an easy login, and want to see if the value that has been entered in the textbox is the same as that in the database
<tr><td>Username</td><td>:</td><td>#Html.TextBox("username", new { #value = ViewBag.username })</td></tr>
I tried things like creating a viewbag and then taking it to the controller, but it didnt seem to work.
Create a viewmodel(a simple class) for this specific UI
public class LoginViewModel
{
[Required]
public string UserName { set;get;}
[Required]
[DataType(DataType.Password)]
public string Password { set;get;}
}
Now in your GET action, create an object of this class and send to your view.
public ActionResult Login()
{
var vm=new LoginViewMode();
return View(vm);
}
Now in our login view(Login.cshtml)which is strongly typed to our LoginViewModel, we will use the TextBoxFor html helper method to render the textboxes for our UserName and Password fields.
#model LoginViewModel
#using(Html.Beginform())
{
UserName
#Html.TextBoxFor(x=>x.UserName);
Password
#Html.TextBoxFor(x=>x.Password)
<input type="submit" />
}
This will render a form which has action attribute value set to /YourCotnroller/Login. now we need to have an HttpPost action method to handle the form posting
[HttpPost]
public ActionResult Login(LoginViewModel model)
{
if(ModelState.IsValid)
{
string uName=model.UserName;
string pass=model.Password.
//Now you can use the above variables to check it against your dbrecords.
// If the username & password matches, you can redirect the user to
// another page using RedirecToAction method
// return RedirecToAction("UserDashboard")
}
return View(model);
}
public ActionResult UserDashboard()
{
//make sure you check whether user is logged in or not
// to deny direct access without login
return View();
}
Try like this:
Define model property in your Model class:
public class Login{
[Required]
[Remote("IsUserNameAvaliable", "Home")]
public string username{get;set;}
[Required]
public string password{get;set;}
}
The Remote attribute that is placed will find the Method/Action with IsUserNameAvaliable in the controller name Home.
The remote attribute servers for this purpose in MVC.
public JsonResult IsUserNameAvaliable(string username)
{
//Check if there are any matching records for the username name provided
if (_dbEntity.Users.Any(c => c.UserName == username))
{
//If there are any matching records found
return Json(true, JsonRequestBehavior.AllowGet);
}
else
{
string userID = String.Format(CultureInfo.InvariantCulture,
"{0} is not available.", username);
return Json(userID, JsonRequestBehavior.AllowGet);
}
}
Now in your view strongly type the textbox
#model Application.Models.Login
#Html.TextBoxFor(m=>m.username)
#Html.ValidationMessageFor(m=>m.username)
Donot forget to include jquery validation scripts.
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
Related
Alright...this may be a bit backwards but, I only need to do it in one spot.
I have a Model
public class LoginModel : xxx.Models.PageVars
{
public Item.LoginAttempt LoginAttempt { get; set; }
public LoginModel()
{
// does a bunch of stuff here...mainly to set the layout properties from PageVar
this.LoginAttempt = new Item.LoginAttempt();
}
}
Login Attempt is a simple obj (for now)
// login attempt
public class LoginAttempt
{
public string Email { get; set; }
public string Password { get; set; }
}
My controller
public ActionResult Login()
{
return View("Login", new Models.LoginModel());
}
[HttpPost]
public ActionResult LoginAttempt(LoginAttempt model)
{
return View("Login", model);
}
In my view
#model xxx.Models.LoginModel
Is there a way to use the property of the obj/model from LoginModel for the #model.
I can get the values from FormCollection or request but...that's not optimal.
thoughts???
tnx
The model for your GET should match the model for your POST. Otherwise, you're not playing on the same field. In order to allow the binding of data from a POST to a model, the HTML Helpers will generate a name that matches the access path of the property in the view's model. In other words, in your form, based on the model being LoginModel, your field names will be LoginAttempt.Email and LoginAttempt.Password. But, in the POST action, you're accepting just LoginAttempt, so the modelbinder is expecting to see data for Email and Password, which it won't find.
There's actually not even any need for this nested class. Just put your Email and Password fields directly on LoginModel and use that for both your view and your POST parameter. Then, you won't have any issues because everything will match up.
Why don't you have the form post controller action accept the parent model LoginModel instead of LoginAttempt? That way, the default MVC model binding should automatically parse the submitted values into the LoginModel and you'll have acces to LoginAttempt.
If it isn't then your form needs to use the prefix values in the names of the properties on the form. This is done automatically when you use TextboxFor, DropdownListFor etc.
In your example, the names of the form fields should start with LoginAttempt.Email etc
I've seen it work 2 ways. First way would be to rename your LoginAttempt model parameter to be
[HttpPost]
public ActionResult LoginAttempt(LoginAttempt loginModel)
{
return View("Login", model);
}
But i would use the Bind(Prefix) option
[HttpPost]
public ActionResult LoginAttempt([Bind(Prefix="LoginModel")] LoginAttempt model)
{
return View("Login", model);
}
you can't really return model of type LoginAttempt to the view though so you'd have to do even more work to get it to work if you're set on doing it this way. You should probably be redirecting to a different page instead of returning the Login view if it succeeds. Other wise return new LoginModel() {LoginAttempt = model}
When a certain link gets clicked on my _Layout.cshtml page a prompt asks for a value. I store this value in a hidden field in the same view. Now before I finish loading Recommended.cshtml I want to see if the hidden field value matches a constant value I created. Everything works, except I can't figure out how to get the hidden value into the view about to be loaded. Could I maybe use a [HttpPost] ActionResult on _Layout.cshtml? What would be best practice in this situation?
Model:
[Bind]
public class RecommendedModel
{
[StringLength(50), Required(ErrorMessage = "This field is required.")]
public string Password { get; set; }
private const string _TOKEN = "pass";
public string Token { get { return _TOKEN; } }
}
Controller:
public ActionResult Recommended(RecommendedModel _recommendedModel)
{
if (_recommendedModel.Password == _recommendedModel.Token)
{
ViewBag.Message = "Recommended.";
return View();
}
else
{
return View("Error");
}
}
View (The hidden field is actually on my shared _Layout page):
#Html.HiddenFor(m=>m.Password)
JavaScript:
var password = prompt("What is the password?", "");
document.getElementById("Password").value = password;
EDIT: All of this code works except _recommendedModel.Password is null. It should have the string the user entered into the prompt, unless I did not map it correctly.
Your password field should be inside tag. If it is outside the form tag make sure you will pass the value from that field to the contrller using javascript/jquery
In your controller, change the ActionResult method to receive the hidden field as a parameter, like this:
public ActionResult Recommended(RecommendedModel _recommendedModel, string password)
Then, set a ViewBag variable, for example, with that parameter value and put it on your "next" View.
ViewBag.password = password;
Remember your hidden field must be inside the form element in order to be passed to the controller.
edit
#using (Html.BeginForm("ControllerName", "Recommended")) {
#Html.HiddenFor(m => m.Password)
<input name="Save" type="submit" value="Save" />
}
I have a view that is using a model and I am using that information to create a form.
I have three steps of the form that are optional or may not be shown.
The problem is that these hidden sections get posted along with the form data and break the business logic. (I have no control over the business logic)
So is there a way to tell the framework not to pass certain sections or fields? Perhaps VIA a class or something?
I know I could use AJAX to send certain sections as they are needed, but the site spec is to have them hidden and displayed as needed.
Although you could do this client-side, it won't stop malicious over-posting/mass assignment.
I suggest reading 6 Ways To Avoid Mass Assignment in ASP.NET MVC.
Excerpts:
Specify Included Properties only:
[HttpPost]
public ViewResult Edit([Bind(Include = "FirstName")] User user)
{
// ...
}
Specify Excluded Properties only:
[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
// ...
}
Use TryUpdateModel()
[HttpPost]
public ViewResult Edit()
{
var user = new User();
TryUpdateModel(user, includeProperties: new[] { "FirstName" });
// ...
}
Using an Interface
public interface IUserInputModel
{
string FirstName { get; set; }
}
public class User : IUserInputModel
{
public string FirstName { get; set; }
public bool IsAdmin { get; set; }
}
[HttpPost]
public ViewResult Edit()
{
var user = new User();
TryUpdateModel<IUserInputModel>(user);
// ...
}
Use the ReadOnlyAttribute
public class User
{
public string FirstName { get; set; }
[ReadOnly(true)]
public bool IsAdmin { get; set; }
}
Lastly, and the most recommended approach is to use a real ViewModel, instead a domain Model:
public class UserInputViewModel
{
public string FirstName { get; set; }
}
Show/Hide will not allow/disallow the value from being sent to the Controller.
Elements that are Disabled or just not editable will (99% of the time) be returned as null / minVal.
You can set the elements in the View as Disabled by using JQuery in the script:
$('#elementID').attr("disabled", true);
OR you could use a DOM command:
document.getElementById('elementID').disabled = "true";
So you can set the fields as both Disabled AND Hidden, so that it is neither displayed, nor populated. Then in your Controller you can just base the Business Logic on whether or not certain fields (preferable Mandatory fields, if you have any) are null.
You can check this in C# like this:
For a string:
if (string.IsNullOrWhiteSpace(Model.stringField))
{
ModelState.AddModelError("stringField", "This is an error.");
}
For a DateTime:
if (Model.dateTimeField == DateTime.MinValue)
{
ModelState.AddModelError("dateTimeField ", "This is an error.");
}
Just for interest sake, here is how you can Hide/Show elements on the View using JQuery:
$('#elementID').hide();
$('#elementID').show();
I have create one simple page in MVC, which is given in startup project of MVC by .net framework with slight modification in that.
I have created two models
Login
Register
Create two controllers.
LoginController
RegisterController.
Then i have use both of them to display in my home page (like facebook just an example)
Model code:
Login Model:
public class Login
{
private string email;
[Required]
public string Email
{
get { return email; }
set { email = value; }
}
private string password;
[Required]
public string Password
{
get { return password; }
set { password = value; }
}
}
Register Model
public class Register
{
private string email;
[Required]
public string Email
{
get { return email; }
set { email = value; }
}
private string password;
[Required]
public string Password
{
get { return password; }
set { password = value; }
}
private string name;
[Required]
public string Name
{
get { return name; }
set { name = value; }
}
}
View of Login and Register both is created using "Create" Option.
Both contains
<input type="submit" value="Create" />
Now, both views are on my other page, home page.
#Html.Action("Index", "Login")
#Html.Action("Index", "Register")
Both display okay, but when i click on any of the "create" button of any of the view, it also gets fire the event in controller for the other one.
My controller code....Logincontroller.
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Login lgobj)
{
System.Threading.Thread.Sleep(2000);
string email = lgobj.Email;
string password = lgobj.Password;
return View();
}
RegisterController:
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Register model)
{
return View();
}
Can anyone please specify the reason, or what is missing in my code?
If not clear, please let me know, i will be describe more.
Try changing your Home View to this:
#using (Html.BeginForm())
{
#Html.Action("Index", "Login")
}
#using (Html.BeginForm())
{
#Html.Action("Index", "Register")
}
What I think is happening is that your submit is calling a POST to the wrong controller, as there is no distinct difference of forms.
Ok so you have a page (a View) that displays two ActionLinks. Once clicked, these two ActionLinks brings you to the LoginController or the RegisterController (depending on the link you’ve clicked). In both cases, you end up inside the Index() ActionResult of the appropriate Controller…so far so good!
Now…once inside the Index() you simply call return View() but I don’t see any code showing that these Views are strongly typed! Try the following:
LoginController:
public ActionResult Index()
{
var model = new Login();
return View(model);
}
RegisterController:
public ActionResult Index()
{
var model = new Register();
return View(model);
}
Assuming you’ve created two strongly typed views (Index.cshtml inside the Login folder and Index.cshtml inside the Register folder) make sure each view has an appropriate form and a submit button.
Little change to what mentioned by #Shark,
We need to mention the action and controller to which indivisual form will post data, If we will not specify both the form will post to the page url.
#using (Html.BeginForm("Index","Login"))
{
#Html.Action("Index", "Login")
}
#using (Html.BeginForm("Index","Register"))
{
#Html.Action("Index", "Register")
}
In this scenario, ( as commented in my first answer)
We need to use a Dynamic view page. (More Information)
Follow following steps:
Create DynamicViewPage type:
public class DynamicViewPage : ViewPage
{
public new dynamic Model { get; private set; }
protected override void SetViewData(ViewDataDictionary viewData)
{
base.SetViewData(viewData);
Model = ViewData.Model;
}
}
Your Controller will look like
public ActionResult Account(string returnUrl)
{
LoginModel loginmodel = null;//Initialize Model;
RegistrationModel registrationModel = null ;//Initialize Model;
.
.
.
.
.
return View("Account", new
{
Login = loginmodel,
Register = registrationModel
});
your View should Inherit from
Inherits="DynamicViewPage"
Now #Model.Login will give you Loginmodel
#Model.Register will give you RegisterModel
It should work as you expected.........
I have the following code in my controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] BackupSet AccountToCreate)
{
if (!ModelState.IsValid)
return View();
_DBE.AddToBackupSet(AccountToCreate);
_DBE.SaveChanges();
return RedirectToAction("Index");
}
I need to have the value of User.Identity.Name set to be the value of one of the fields in the create view when I post it to the database.
I am sure its very simple but really don't know how.
Thanks,
Steve.
Why do you need to store the username in the view? You will surely be initiating the DB transaction from within a controller so if it's the username for the user that is currently logged in use the MembershipProvider as per the last suggestion:
HttpContext.Current.User.Identity.Name
If not perhaps you should consider creating a container/wrapper class that clearly represents your View model - some might consider this overkill for one extra property but I hate "magic strings" in code.
public class MyView
{
public string UserName { get; set; }
public MyObject MyMainObject { get; set;}
public MyView(string username, MyObject myMainObject)
{
this.Username = username;
this.MyMainObject = myMainObject;
}
}
then set your view model type as:
System.Web.Mvc.ViewPage<MyNamespace.MyView>
this then allows you to have strongly typed properties for everything in your view e.g.
<%=Model.Username %>
<%=Model.MyMainObject.Title %>
and in your controller you can parameterize your Action as
public ActionResult(MyMainObject myMainObject, string username)
{
//Do something here
//if not correct
return View(new MyView(username, myMainObject));
}
If instead you wanted to go down this path:
ViewData["Name"] = User.Identity.Name;
or
ViewData.Add("Name", User.Identity.Name);
Consider creating Enums to once again avoid using string literals e.g.
public enum UserEnum
{
Username,
Password
}
then use:
ViewData.Add(UserEnum.Username.ToString(), User.Identity.Name);
one of the fields in view?
how about simply setting
ViewData["Name"] = User.Identity.Name
and then in View use it wherever you want.
Short Answer:
HttpContext.Current.User.Identity.Name
Long Answer:
You should probably make a membership service to provide that value. The default MVC2 project will provide IMembershipService interface which you can expand to provide property: CurrentUserName (or whatever you like)
public string CurrentUserName
{
get
{
var context = HttpContext.Current;
if (null != context)
return context.User.Identity.Name;
var user = Thread.CurrentPrincipal;
return (null == user)
? string.Empty
: user.Identity.Name;
}
}