I'm trying to implement a simple login for admin in a MVC3 project. I'm new to ASP.NET and to MVC3. I have googled and asked questions! have seen a lot of really nice ways of implementing this but they were all on a very abstract level and quite frankly maybe a bit to high for me at the time being. I have the credentials in my db so basically I just want to query that one and redirect the user if login matches those and if not show login form again. So this is what I got. My model:
public class FormModel
{
public bool isAdmin { get; set; }
[Required(ErrorMessage = "Please enter your Username")]
//[Remote("ValidateUserName", "Login", ErrorMessage = "UserName already taken!")]
[StringLength(6, MinimumLength = 3)]
[Display(Name = "Username:")]
[RegularExpression(#"(\S)+", ErrorMessage = "White space is not allowed")]
public string UserName { get; set; }
[Required(ErrorMessage = "Please enter your Password")]
[DataType(DataType.Password)]
[Display(Name = "Password:")]
public string Password { get; set; }
}
public User IsAdmin(string username, string password)
{
return (from user in db.Users
where user.username == username && user.password == password <--- alternative here is to just match username and pass against the data I have in my db columns(testdata 'admin', 'password')
&& user.IsAdmin == true
select user).SingleOrDefault();
}
And in my controller basically this right now:
public ActionResult Index()
{
//some code here maybe a conditional
return View();
}
And finally my view:
#model Web.VoucherCannon.Models.FormModel
#using (Html.BeginForm("HandleForm", "Login", FormMethod.Post, new {id = "myForm"})) {
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<button class="button">Log In</button>
}
So now. How do I use the returned result of the query in my controller so that I can login? I'm sure I will refactor this later on and make it with a dbcontext layer and so on, but just for now I will be happy to make this work. Grateful for help!
You should have 2 controller actions: one for rendering the login (accessible on GET) form and one for handling the submission (accessible on POST) and performing the actual authentication.
// This will render the Login view (the one you have shown)
public ActionResult Login()
{
var model = new FormModel();
return View(model);
}
// This one is responsible for handling the submission and credential verification
[HttpPost]
public ActionResult Login(FormModel model)
{
if (!ModelState.IsValid)
{
// The user submit the form but validation
// (as defined on the model using DataAnnotation attributes) failed
// => redisplay the view so that the user can fix his errors
return View(model);
}
// notice that you don't need to pass parameters to the IsAdmin method
// as it already contains the username and password as properties
if (!model.IsAdmin())
{
// The IsAdmin method didn't verify the credentials => add a model error
// and redisplay the login view
ModelState.AddModelError("username", "dude you are not an admin");
return View(model);
}
// OK, at this stage everything is fine => we can grant access
// by issuing an authentication cookie
FormsAuthentication.SetAuthCookie(model.UserName, false);
// finally we redirect to some home page for admins
return RedirectToAction("Index", "Admin");
}
Related
I have already tried many solutions available on web as per my understanding in context to this question but being new in MVC I am still unable to find a solution. Kindly help.
I have a view which is the home page of the website named as "Index.cshtml" and is situated under the following path:
WebsiteName/Areas/Website/Views/CypressHome/Index.cshtml
Secondly, I have a created a user trial form as partial view named as "_PartialHomeFormFreeTrial.cshtml" which is situated under the following path:
WebsiteName/Areas/Website/Shared/_PartialHomeFormFreeTrial.cshtml.
This form I have used inside my "Index.cshtml" as below:
<!--freetrialform-->
#Html.Partial("_PartialHomeFormFreeTrial")
<!--//freetrialform-->
Now, my partial page is posting data comprising of following elements:
#using (Html.BeginForm("Create", "Customer", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.EditorFor(model => model.CustomerName, new { htmlAttributes = new { #class = "input__field input__field--kuro" } })
#Html.ValidationMessageFor(model => model.CustomerName, "", new { #class = "text-danger" })
............
other fields such as email, phone, date, etc..
<input type="submit" id="" value="SEND REQUEST" />
</div>
}
Now, I have created a controller named "CustomerController" which has the following code to save the data of the form as used as partial view in the main view "Index.cshtml":
public class CustomerController : Controller
{
private WebsiteContext db = new WebsiteContext();
// GET: Website/Customer
public ActionResult Index()
{
return View();
}
// GET: Website/Customer/Create
public ActionResult Create()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View("Index");
}
// POST: Website/Customer/Create
[HttpPost]
public ActionResult Create([Bind(Include = "CustomerID,CustomerName,CustomerEmail,CustomerPhone,DateOfRegistration,StatusPlanID")] Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.Add(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status", customer.StatusPlanID);
return View(customer);
}
}
I have tried many changes in my controller, return in the views and
many other things but I am getting the same error always. Neither the
validations are working nor the validated data is getting saved.
The error is as below:
Server Error in '/' Application.
The view 'Create' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Areas/Website/Views/Customer/Create.aspx
~/Areas/Website/Views/Customer/Create.ascx
~/Areas/Website/Views/Shared/Create.aspx
~/Areas/Website/Views/Shared/Create.ascx
~/Views/Customer/Create.aspx
~/Views/Customer/Create.ascx
~/Views/Shared/Create.aspx
~/Views/Shared/Create.ascx
~/Areas/Website/Views/Customer/Create.cshtml
~/Areas/Website/Views/Customer/Create.vbhtml
~/Areas/Website/Views/Shared/Create.cshtml
~/Areas/Website/Views/Shared/Create.vbhtml
~/Views/Customer/Create.cshtml
~/Views/Customer/Create.vbhtml
~/Views/Shared/Create.cshtml
~/Views/Shared/Create.vbhtml
And the url is changing as below:
1. On running the system initially: http://localhost:53872/
2. On clicking on submit: http://localhost:53872/Areas/Website/Customer/Create along with the
error as stated above.
For more information my WebsiteAreaRegistration.cs file contains the below code:
public class WebsiteAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Website";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Website_home",
"",
new { controller = "CypressHome", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Website_default",
"Areas/Website/{controller}/{action}/{id}",
new { controller = "CypressHome", action = "Index", id = UrlParameter.Optional }
);
}
}
Though I have understood the problem but unable to figure out. Kindly help.
In your code last return statement is return View(customer). That's means after POST data it return a View (using HTTP GET method) as same name as Action that's Create. But your description you have a Create Action but you have no view page.
So please create a Create.cshtml with a Model corresponding customer Object.
Or change the return statement.
Based on your comment you can follow this Change.
1.Remove
public ActionResult Create()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View("Index");
}
2.then change
public ActionResult Index()
{
ViewBag.StatusPlanID = new SelectList(db.StatusPlans, "StatusPlanID", "Status");
return View(new Customer());
}
3.in Index.cshtml
#Model Customer
#Html.Partial("_PartialHomeFormFreeTrial",Model)
4.Then
return View("Index",customer);
So what I want to do is take a string from a textarea and pass it to an action method overload (string paramJSON).
Action method:
public ActionResult SendMail(string templateName, string receiver, string paramJSON)
{
var paramDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(paramJSON);
new SendMailClient().Send(templateName, receiver, paramDictionary);
if(Request.IsAjaxRequest())
{
return RedirectToAction("SendPartial", "TestMail");
}
return View();
}
Textarea:
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
Your html helper
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
generates a textarea with name="TestParametrar". When you submit a form, it sends back the values of each controls name and value attributes in this case TestParametrar: 'The text you entered' You method needs to include a parameter with the same name, for example
public ActionResult SendMail(string TestParametrar, ....)
and the value of the parameter will be the text entered in the form control.
However, since you view is based on a model, then it is better to just post back to the model and all properties will be bound
public ActionResult SendMail(YourModel model)
which has the added benefit of validating your properties. For example, if property TestParametrar has the [Required] attribute, then if the user does not enter a value, ModelSTate will be invalid and the view can be returned for correction.
#using (Html.BeginForm("SendMail2"))
{
#Html.TextAreaFor(a => a.TestParametrar, new { id = "paramTxt" })
<input type="submit" value="Send Message" />
}
And:
public ActionResult SendMail2(string TestParametrar)
{
return SendMail("myTemplate", "hello#world.com", TestParametrar);
}
I have the following partial view with an Html.FormBegin helper method;
#if (Session["UserSpecific"]!=null) //(Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
#Html.AntiForgeryToken()
#* #Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })*#
<input type="button" class="menu-button nav navbar-nav navbar-right" data-target=".customer-list" data-toggle="collapse" />
<div class="customer-list-container">
<div class="customer-list collapse">
<ul>
#{
string[] array = { "Steel Company", "Recycling Company", "Other Company", "Random Name Here" };
}
#foreach (string name in array)
{
<li>#Html.ActionLink(name, "", "", routeValues: null, htmlAttributes: new { #class = "customer-link" })</li><hr/>
}
<li><input type="submit" /></li>
</ul>
<div class="col-xs-6">#Html.ActionLink("Settings", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })</div><div class="col-xs-6"><!--<input type="submit" value="Log Off"/>-><!--Log off</div><div class="clearfix">--></div>
</div>
</div>
}
}
The problem is, whenever I click on the Submit button, instead of logging out, it runs through the LogIn method again, and modifies the URL to read:
Account/Login?ReturnUrl=%2FAccount%2FLogOff
I don't get why it is running through the LogIn method again, since the Html.BeginForm method specifies that it will use the LogOff method in the Account controller.
The Login method that gets called:
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The LogOff method that should be called:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
//AuthenticationManager.SignOut();
Session.Remove("UserSpecific");
Session["UserSpecific"] = null;
return RedirectToAction("Index", "Home");
}
It looks like the Index action method on your HomeController is not marked with the [AllowAnonymous] attribute, which means when the browser attempts to access it after being logged out it gets redirected to the login page again because you're trying to access a page that is accessible only to authenticated users.
Try adding [AllowAnonymous]:
public class HomeController : Controller {
[AllowAnonymous] // <-- add this
public ActionResult Index() {
return View();
}
// other stuff
}
I just realised something interesting, I was facing the same problem with my MVC area calling the index method in the account controller instead of calling the logoff method.
I realised the problem was with a defective routing done in the admin area of the application.
Try testing that to see if you're able to correct it.
I have two inputs of type file, one in a partial view, and another in main page
In partial view
<input type="file" name="image" id="image" onchange="readURL(this)"/>
In main page
<input type="file" name="userProfilePic" id="userProfilePic" style="display:none" />
What I want is that when a user changes image/file on the visible file upload, the image/file should be updated on main/other input too. Here's my code.
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#imagePreview').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
// window['profilePic'] = input.files[0];
$('#userProfilePic').get(0).files[0] = input.files[0];
return false;
}
The Error
The error is quite weird, when I open my console, and check for files, it shows up sometime, and a moment later it don't.
In my console window
$('#userProfilePic').get(0).files[0]
File (file object details)
....
(after a second)
$('#userProfilePic').get(0).files[0]
undefined
And it isn't happening the first time only. Say sometimes, it shows the values for 5-6 times, then 7th time it won't...
$('#userProfilePic').get(0).files[0]
File (file object details)
....
(after a second)
$('#userProfilePic').get(0).files[0]
File (file object details)
....
(after a second)
$('#userProfilePic').get(0).files[0]
File (file object details)
....
(after a second)
$('#userProfilePic').get(0).files[0]
undefined
That's all the code I have, there is no other code. Now, as you can see in the code, I also set window[profilePic] to the file object. But if I check that in console window, it always shows no matter what? How is this happening?
The problem
I need to submit the form, but when I do, the image (the input file) is being sent as null, but sometimes as a valid file. As I explained earlier, when I check the value in console, it shows for first time, or some random number of times, then all of a sudden it is gone, while the variable that I set on window (window[profilePic]) always have that file object.
In case someone is wondering, the original/visible file input where user actually selects the file always has the value.
You cant do this for security reasons , all files uploaded via input type="file" have to be done manually by the user.
However as long as the user will upload an image anyway , you should do all the process you want in your server side script.
for further info , please refer to this post here :
How to set a value to a file input in HTML?
Why you try to use two inputfile for the same file?
if you try to make a form in a PartialView with a inputfile and extra data? I answered a very similar question here:
File upload in MVC when used in bootstrap modal returns null
1) make a model for used in the form with all elements for the form,
2) declare the model in the first line in the partial view
3) pass as parameter the model to the post function.
4) you use a Partial view, well is possible use this view in differents pages, you need specify the control to treatement the form.
An Example in code:
Model:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class PartialFormModel
{
[Required]
[StringLength(200)]
public string FileName { get; set; }
[StringLength(200)]
public string Title { get; set; }
[StringLength(1000)]
public string Description { get; set; }
public int? Order { get; set; }
[NotMapped]
public HttpPostedFileBase ImageFile { get; set; }
}
PartialVIEW:
#model YOURSPACENAME.Models.PartialFormModel
#using (Html.BeginForm("YourActionName", "YourControllerName", FormMethod.Post, new { #class = "form-horizontal", #role = "form", #enctype="multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.LabelFor(model => model.FileName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FileName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FileName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ImageFile, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.ImageFile, new { #class = "form-control", type = "file" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
CONTROLLER
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult YourActionName(PartialFormModel obj)
{
if (ModelState.IsValid)
{
//your options
}
return PartialView("_EditSlider");
}
Considering that:
For security reasons you can't set value of input type="file"
programmatically.
Changing the type of an <input> throws a security error in some
browsers (old IE and Firefox versions).
I don't know actually what you want. But I exhort you to create a new input element, set its type to the one you want, say file, and set its properties according to your need. like this:
<script>
function createInputType(_type, _value, _name, _id, _class) {
var newObject = document.createElement('input');
newObject.type = _type;
newObject.value = _value;
newObject.name = _name;
newObject.id = _id;
newObject.className = _class;
return newObject;
}
</script>
Ok so im trying to input data from View to a SQL table i got no errorss but data does not show in the table
I using VisualStudio project is ASP.NET MVC 4 Web Application so it has already created models
views connectionstring controllers and it has a Site.Master so i just make new View from which i will pass data to my controller and then push it to SQL table which i have already created within "Table" folder which is created by default from the project in this "Table" folder i have tables which are needed for registration stuff already created by its own so i just added a new table to this "Table" folder called ProductTable
So ProductTable has 2 values (int)ID which is Primary Keyed and (string)Name
Ok so in "Model" folder i added new Class "ProductTable" with code inside
[Table("ProductTable")]
public class ProductTable
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
}
i have created another class there "ProductTableContext " with code inside
public class ProductTableContext : DbContext
{
public DbSet<ProductTable> Products { get; set; }
}
and in my HomeController i have
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your .";
return View();
}
public ActionResult Table()
{
return View(new ProductTable());
}
[HttpPost]
public ActionResult Table(ProductTable product)
{
if (!ModelState.IsValid)
{
return View(product);
}
using (var contex = new ProductTableContext())
{
contex.Products.Add(product);
contex.SaveChanges();
}
return View();
}
}
so Index , About and Contact are Views created by the project itself.
and View
#model Father.Models.ProductTable
#{
ViewBag.Title = "Table";
}
<h2>Table</h2>
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.Name)
#Html.EditorFor(x => x.Name)
#Html.ValidationMessageFor(x => x.Name)
</div>
<button type="submit">Create event</button>
}
So the problem is that everything works fine i have no errors but when i close the website and i press debug > stop debugging then i click ShowTableData on ProductTable in ServerExplorer all values are Nulls so its like ihave never added this Data to the table can anyone tell me whats wrong? Thank you!
Add this attribute to your ID property
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]. This will tell EF to have the database generate the Identity when you save the object.