i want to perform a database action on login click.
So i am using stored procedure for getting the data, but here i am facing some issues regarding model exception.
public ActionResult Login(UserInfo model, string returnUrl)
{
if (ModelState.IsValid)
{
List<UserInfo> loginDetails = dbContext.Database.SqlQuery<UserInfo>
("exec spGetloginUserInfo #username,#password", new SqlParameter("#username", model.username), new SqlParameter("#password", model.password)).ToList();
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
My Model
public class UserInfo
{
public string usertype { get; set; }
public string username { get; set; }
public string password { get; set; }
public bool active { get; set; }
public DateTime lastmodifieddate { get; set; }
public string modifiedby { get; set; }
public bool RememberMe { get; set; }
}
The exception thrown is
An exception of type
'System.Data.Entity.ModelConfiguration.ModelValidationException'
occurred in EntityFramework.dll but was not handled in user code
Please let me know where i am doing wrong and also whether my approach is right?
And also is there any other way for database interaction other that stored procedure approach.
ModelState.AddModelError throws an error but your client/javascript/views did not catch that error.
Here is a link on how to implement similar error handling in views.
ASP.NET MVC 2 Model Errors with Custom Exceptions
Also, make sure the your model UserInfo has valid data for each properties
Login(UserInfo model, string returnUrl) <<-- the model of type UserInfo
Related
I have a simple model for my asp.net core controller:
[HttpPost]
public async Task<DefaultResponse> AddCourse([FromBody]CourseDto dto)
{
var response = await _courseService.AddCourse(dto);
return response;
}
My model is :
public class CourseDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Genre { get; set; }
public string Duration { get; set; }
public string Level { get; set; }
public string AgeRange { get; set; }
public string Notes { get; set; }
public bool Active { get; set; }
public string OrganisationCode { get; set; }
}
I'm trying to set value of "OrganisationCode" using a custom mode binder or action filter, but had no success.
I would be thnakful if you advise whats the right way to updat ethe model before executing the action.
Thanks.
I will show you here a very simple custom model binder I have just written (and tested in .Net Core 2.0):
My model binder:
public class CustomModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var value = valueProviderResult.FirstValue; // get the value as string
var model = value.Split(",");
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
My model (and notice, only one property has my custom model binder annotation):
public class CreatePostViewModel
{
[Display(Name = nameof(ContentText))]
[MinLength(10, ErrorMessage = ValidationErrors.MinLength)]
public string ContentText { get; set; }
[BindProperty(BinderType = typeof(CustomModelBinder))]
public IEnumerable<string> Categories { get; set; } // <<<<<< THIS IS WHAT YOU ARE INTERESTER IN
#region View Data
public string PageTitle { get; set; }
public string TitlePlaceHolder { get; set; }
#endregion
}
What it does is: it receives some text like "aaa,bbb,ccc", and converts it into array, and return it to the ViewModel.
I hope that helps.
DISCLAIMER: I am not an expert in model binders writing, I have learnt that 15 minutes ago, and I found your question (with no helpful answer), so I tried to help. This is a very basic model binder, some improvements are surely required. I learned how to write it from the official documentation page.
The [FromBody] attribute you are using on the action parameter. means that you direct the default behavior of Model Binding to use the formatters instead. That is why your custom Model Binder does not work.
And [FromBody] is reading the content (request body). So you won't get the request body from your Action Filter, as the request body is a non-rewindable stream, so it suppose to be read only once (I'm assuming that you are trying to read the request body from Action Filter).
My suggestion is to use your custom model binder and remove the FromBody Attribute.
I have created a ViewModel which contains other models
namespace CreatingLayout.Models
{
public class ViewModel
{
public tbl_Roles Roles { get; set; }
public tbl_Category Category { get; set; }
public tbl_Course Course { get; set; }
public tbl_User User { get; set; }
}
}
And this sub Model has some Required Field field like tbl_User class has following required fields:
public partial class tbl_User
{
[Required(ErrorMessage = "Please enter {0}")]
public string UserName { get; set; }
[Required(ErrorMessage = "Please enter {0}")]
public string Password{ get; set; }
//And many more with Required Field
}
Now my problem is, in my View i am not passing data for all this required fields but only for few. So once i click to submit button, i am calling my Controller Action Method and i am checking for ModelState errors
public ActionResult AdminInsertion(ViewModel objViewModel)
{
if (ModelState.IsValid)
{
//IF No Errors do something
}
return View();
}
So everytime my Modelstate.Isvalid is returning false due to Validation Error which i gave in those 4 classes i.e., tbl_Roles, tbl_Category, tbl_Course and tbl_User. So what i want is to Clear all those error for which i am not passing Data, something like
//Here i want to go to individual classes ex: item should contains all tbl_Roles column fields
foreach(var item in ModelState.Keys)
{
//Now i want to Get Key items of each individual class which is causing Error
foreach(string Key in item)
{
//Here i am going to clear all those error for which i am not passing data
ModelState[Key].Error.Clear();
}
}
But my problem is, i am not able to access fields of tbl_Roles, tbl_Category, tbl_Course and tbl_User. ,How can clear only selected field errors here?
Sorry for newbie questions, i'm brand new to MVC and OOP
I have the following model for my USER db table
namespace MyApp.Models
{
public class User
{
public int user_id { get; set; }
public string username { get; set; }
public string password { get; set; }
public string salt { get; set; }
public string email { get; set; }
public sbyte status { get; set; }
public System.DateTime creation_date { get; set; }
public sbyte type { get; set; }
public virtual Doctor Doctor { get; set; }
public virtual Owner Owner { get; set; }
public virtual UserToken UserToken { get; set; }
public virtual Veterinarian Veterinarian { get; set; }
}
}
Actually in order to recall a particular USER based on the mail or the id i use a specific class called CustomDbFunctions
namespace MyApp.Models.DAL
{
public static class CustomDbFunctions
{
public static User GetUserEntityFromEmail(string email, DbContext db)
{
return db.Users.FirstOrDefault(u => u.email == (string)email);
}
}
}
in that way i use in my code
User user = CustomDbFunctions.GetUserEntityFromEmail(email, db)
and this it 100% OK with me, but i don't know if this kind of approach is correct or not, or if there's a better way like
//select the single user by calling only the class USER
User mySelectedUser = new User(email)
Thank you very much.
Well for understanding how to access your data in your MVC4 application you could read this tutorial from the Asp.Net MVC main page. Read the whole tutorial about MVC4 and you'll get a solid idea on how to work with it.
But I also recommend this tutorial on a good Entityframework design pattern, it's called Repository Pattern, I just a nice way to get all your code ordered (like all other patterns). Let me know.
I develop a web application. It has a three-tier architecture (data access layer, a business logic layer and the presentation layer). A data access layer is implemented with a NHibernate ORM (S#arp Architecture). I have the following table:
public partial class Role {
public Role()
{
this.Users = new Iesi.Collections.Generic.HashedSet<User>();
}
public virtual long Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual Iesi.Collections.Generic.ISet<User> Users
{
get;
set;
}
}
public partial class User {
public User()
{
this.Drivers = new Iesi.Collections.Generic.HashedSet<Driver>();
this.UserPhotos = new Iesi.Collections.Generic.HashedSet<UserPhoto>();
this.Roles = new Iesi.Collections.Generic.HashedSet<Role>();
}
public virtual long Id
{
get;
set;
}
public virtual string Login
{
get;
set;
}
public virtual string Email
{
get;
set;
}
public virtual string Salt
{
get;
set;
}
public virtual string Hash
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual Iesi.Collections.Generic.ISet<Driver> Drivers
{
get;
set;
}
public virtual University University
{
get;
set;
}
public virtual Iesi.Collections.Generic.ISet<UserPhoto> UserPhotos
{
get;
set;
}
public virtual Iesi.Collections.Generic.ISet<Role> Roles
{
get;
set;
}
}
public partial class Driver {
public Driver()
{
this.Trips = new Iesi.Collections.Generic.HashedSet<Trip>();
}
public virtual long Id
{
get;
set;
}
public virtual Car Car
{
get;
set;
}
public virtual User User
{
get;
set;
}
public virtual Iesi.Collections.Generic.ISet<Trip> Trips
{
get;
set;
}
}
There is a User in the system. Table Driver inherits the user table. Each user in the system may have several roles.
I want to implement a few things.
1) User registration. Is it a correct way to implement this features?
[Authorize]
public class AccountController : Controller
{
private readonly IUserTasks userTasks;
public AccountController(IUserTasks userTasks)
{
this.userTasks = userTasks;
}
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
return View();
}
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
public ActionResult Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var userToCreate = this.userTasks.Create(model);
return View(customerToCreate);
}
return View(model);
}
}
2) User authentication. Is it a correct way to implement this features?
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = userTasks.Find(model.UserName, model.Password);
if (user != null)
{
///......
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
return View(model);
}
3) User authorization. User authorization. I want to write some attribute, for example,
[Authorize(Roles = "Admin")]
public string Get(int id)
{
return "value";
}
I do not know how to do it.
In many examples a new library Microsoft.AspNet.Identity is used. Should I use it? There is a implementation NHibernate.AspNet.Identity. However, I do not understand what benefit I get from this.
Also I do not know how to implement user authentication.
I'll be glad if you tell me a vector for further research.
You have 2 choices. Either:
you use OWIN as explained in Setting up Forms Authentication for multiple Web Apps in MVC 5 based on OWIN
you use traditional form-based authentication. See here: MVC 5 External authentication with authentication mode=Forms
As for authorization, Microsoft provides something called claims-based authorization which lets you define user and resource claims and define authorization constraints based on them. Have a look here: Using Claim-Based Authorization
Alternatively, you could look into XACML, the eXtensible Access Control Markup Language. That will require additional libraries outside the .NET framework though. XACML gives you policy-based, fine-grained authorization.
HTH
I'm fairly sure I have followed all the steps, but seem to have missed something. Using simplemembership in MVC4 app. Add Email to UserProfile table and in the Register and UserProfile models, added it to the Register method, but still getting the error. Here is some code:
Models:
public class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
public class RegisterModel
{
[Display(Name = "Email Address")]
[StringLength(20)]
// [Required]
public string Email { get; set; }
[Display(Name = "Date of Birth")]
// [Required]
public DateTime DOB { get; set; }
[Required]
[System.Web.Mvc.Remote("VerifyUserExists", "Account", ErrorMessage="That Username is already taken.")]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
Controller:
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email });
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
I am not trying to use the email address as the login, just want to grab it during the registration step so I can send an auto confirm email.
I have tried with the UserProfile table included in the EF model, and with it out, no difference. I have confirmed the table in the DB has a Email column.
If you're using the default connection, open the database by clicking View -> Server Explorer then expand the DefaultConnection. Under Tables you will see the UserProfile table. Add your columns to the table first and update the database, then add your extra fields to the class.
I'm guessing that the Email property (in your UserProfile class) was somthing you added after you already executed the application for the first time , so if the table already exist befor you changed your model and added the Email property, It might be the cause for the exception.
as you mentioned yourself in one of your comments:
If I remove the section , new{ Email etc ' from the Register method in the controller, it pass fine
To fix that, I think you need to do somthing like that in your DbContext deriven class.(assuming you use code first approach):
public class myDbContext: DbContext
{
public myDbContext()
: base("DefaultConnection")
{
Database.SetInitializer<myDbContext>(new DropCreateDatabaseIfModelChanges<myDbContext>());
}
public DbSet<UserProfile> UserProfiles { get; set; }
}
The default setting is CreateDatabaseIfNotExists ,so if your UserProfile table was already exist, it didn't create it again and didn't find your new Email property (It was in your model but not in the database table);