how can i show custom exception next to textbox? - asp.net-mvc-3

I have register form. I want to check new username that is in db or not and if there is in DB , exception show next to it's textbox "UserName already exist...", what should I do?
this my method with exception that I have used it in Register action.:
public void InsertNewUser(MemberRegisterModel mm)
{
EShopThemeDBEntities context = new EShopThemeDBEntities(idbconnection.ConnStr);
using (context)
{
var listUsers = (from o in context.Users
select o.Username).ToList();
var a = listUsers.Count();
foreach (var item in listUsers)
{
if (mm.Username == item.ToString())
{
throw new Exception("UserName already exist...");
}
User mmr = new User();
mmr.FName = mm.FName;
mmr.LName = mm.LName;
mmr.Username = mm.Username;
mmr.Password = mm.Password;
mmr.Email = mm.Email;
mmr.Phone = mm.Phone;
mmr.Mobile = mm.Mobile;
mmr.CreateDate = DateTime.Now;
mmr.RoleId = 2;
context.AddToUsers(mmr);
context.SaveChanges();
}
}

You can set the Model error and return the model object back to view.
if(mm.Username == item.ToString())
{
ModelState.AddModelError("UserName","Username already taken";)
return View(model);
}
Also You do not need to get a list of usrs from database and do a loop to check whether the user entered user name exist or not. You can use the FirstOrDefault method to atleast one is there.
using (context)
{
var user=(from o in context.Users
where o.UserName==mm.UserName).FirstOrDefault();
if(user!=null)
{
ModelState.AddModelError("UserName","Username already taken";)
return View(model);
}
else
{
//Save new user info
}
}
Make sure you have the validation fields in your view, adjacent to the text box
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
But, Ideally, I would also do it asynchronosly with ajax to provide a rich user experience to the user. For that what you have to do is to look for the blur event of the text box and get the value of the textbox, make an ajax call to an action method which checks the availability of user name and return appropriate result.
<script type="text/javascript">
$(function(){
$("#UserName").blur(){
var userName=$(this).val();
$.getJSON("#Url.Action("Check","User")/"+userName,function(response){
if(response.status=="Available")
{
//It is available to register. May be show a green signal in UI
}
else
{
//not available. Show the message to user
$("#someMsgDIv").html("User name not available");
}
});
});
});
</script>
Now we should have an action method called Check in UserController to handle the ajax request
public ActionResult Check(string id)
{
bool isAvailable=false;
string userName=id;
//Check the user name is availabe here
if(isAvailable)
return Json(new { status="Available"},
JsonRequestBehaviour.AllowGet);
else
return Json(new { status="Not Available"},
JsonRequestBehaviour.AllowGet);
}
Note: Never do the client side approach only. Always do the server side checking no matter whether you have client side checking or not.

Shyju's answer is a thorough answer. However, based on your comments about handling the exception, here's a sample:
public void InsertNewUser(MemberRegisterModel mm)
{
// Some code...
if (userExists)
{
throw new ArgumentException("User name not available");
}
}
in your action method:
public ActionResult AddUser(MemberRegisterModel newUser)
{
try
{
var userManager = new MembersSrv();
userManager.InsertNewUser(newUser);
}
catch (ArgumentException ex)
{
if (ex.Message == "User name not available")
{
ModelState.AddModelError("UserName","Username already taken";)
return View(model);
}
}
}
Please note that the better way is to define a class which derives from Exception class (e.g. DuplicateUserNameException) and throw/catch that exception in your code. This sample code has been simplified.

Related

Validate Model in Pipeline Instead of Controller [duplicate]

I was wondering how I can achieve model validation with ASP.NET Web API. I have my model like so:
public class Enquiry
{
[Key]
public int EnquiryId { get; set; }
[Required]
public DateTime EnquiryDate { get; set; }
[Required]
public string CustomerAccountNumber { get; set; }
[Required]
public string ContactName { get; set; }
}
I then have a Post action in my API Controller:
public void Post(Enquiry enquiry)
{
enquiry.EnquiryDate = DateTime.Now;
context.DaybookEnquiries.Add(enquiry);
context.SaveChanges();
}
How do I add if(ModelState.IsValid) and then handle the error message to pass down to the user?
For separation of concern, I would suggest you use action filter for model validation, so you don't need to care much how to do validation in your api controller:
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace System.Web.Http.Filters
{
public class ValidationActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
}
}
}
Maybe not what you were looking for, but perhaps nice for someone to know:
If you are using .net Web Api 2 you could just do the following:
if (!ModelState.IsValid)
return BadRequest();
Depending on the model errors, you get this result:
{
Message: "The request is invalid."
ModelState: {
model.PropertyA: [
"The PropertyA field is required."
],
model.PropertyB: [
"The PropertyB field is required."
]
}
}
Like this, for example:
public HttpResponseMessage Post(Person person)
{
if (ModelState.IsValid)
{
PersonDB.Add(person);
return Request.CreateResponse(HttpStatusCode.Created, person);
}
else
{
// the code below should probably be refactored into a GetModelErrors
// method on your BaseApiController or something like that
var errors = new List<string>();
foreach (var state in ModelState)
{
foreach (var error in state.Value.Errors)
{
errors.Add(error.ErrorMessage);
}
}
return Request.CreateResponse(HttpStatusCode.Forbidden, errors);
}
}
This will return a response like this (assuming JSON, but same basic principle for XML):
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
(some headers removed here)
["A value is required.","The field First is required.","Some custom errorm essage."]
You can of course construct your error object/list any way you like, for example adding field names, field id's etc.
Even if it's a "one way" Ajax call like a POST of a new entity, you should still return something to the caller - something that indicates whether or not the request was successful. Imagine a site where your user will add some info about themselves via an AJAX POST request. What if the information they have tried to entered isn't valid - how will they know if their Save action was successful or not?
The best way to do this is using Good Old HTTP Status Codes like 200 OK and so on. That way your JavaScript can properly handle failures using the correct callbacks (error, success etc).
Here's a nice tutorial on a more advanced version of this method, using an ActionFilter and jQuery: http://asp.net/web-api/videos/getting-started/custom-validation
Or, if you are looking for simple collection of errors for your apps.. here is my implementation of this:
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
var errors = new List<string>();
foreach (var state in modelState)
{
foreach (var error in state.Value.Errors)
{
errors.Add(error.ErrorMessage);
}
}
var response = new { errors = errors };
actionContext.Response = actionContext.Request
.CreateResponse(HttpStatusCode.BadRequest, response, JsonMediaTypeFormatter.DefaultMediaType);
}
}
Error Message Response will look like:
{
"errors": [
"Please enter a valid phone number (7+ more digits)",
"Please enter a valid e-mail address"
]
}
You can use attributes from the System.ComponentModel.DataAnnotations namespace to set validation rules. Refer Model Validation - By Mike Wasson for details.
Also refer video ASP.NET Web API, Part 5: Custom Validation - Jon Galloway
Other References
Take a Walk on the Client Side with WebAPI and WebForms
How ASP.NET Web API binds HTTP messages to domain models, and how to work with media formats in Web API.
Dominick Baier - Securing ASP.NET Web APIs
Hooking AngularJS validation to ASP.NET Web API Validation
Displaying ModelState Errors with AngularJS in ASP.NET MVC
How to render errors to client? AngularJS/WebApi ModelState
Dependency-Injected Validation in Web API
Add below code in startup.cs file
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = (context) =>
{
var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => new ErrorModel()
{
ErrorCode = ((int)HttpStatusCode.BadRequest).ToString(CultureInfo.CurrentCulture),
ErrorMessage = p.ErrorMessage,
ServerErrorMessage = string.Empty
})).ToList();
var result = new BaseResponse
{
Error = errors,
ResponseCode = (int)HttpStatusCode.BadRequest,
ResponseMessage = ResponseMessageConstants.VALIDATIONFAIL,
};
return new BadRequestObjectResult(result);
};
});
C#
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
...
[ValidateModel]
public HttpResponseMessage Post([FromBody]AnyModel model)
{
Javascript
$.ajax({
type: "POST",
url: "/api/xxxxx",
async: 'false',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
error: function (xhr, status, err) {
if (xhr.status == 400) {
DisplayModelStateErrors(xhr.responseJSON.ModelState);
}
},
....
function DisplayModelStateErrors(modelState) {
var message = "";
var propStrings = Object.keys(modelState);
$.each(propStrings, function (i, propString) {
var propErrors = modelState[propString];
$.each(propErrors, function (j, propError) {
message += propError;
});
message += "\n";
});
alert(message);
};
Here you can check to show the model state error one by one
public HttpResponseMessage CertificateUpload(employeeModel emp)
{
if (!ModelState.IsValid)
{
string errordetails = "";
var errors = new List<string>();
foreach (var state in ModelState)
{
foreach (var error in state.Value.Errors)
{
string p = error.ErrorMessage;
errordetails = errordetails + error.ErrorMessage;
}
}
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("error", errordetails);
return Request.CreateResponse(HttpStatusCode.BadRequest, dict);
}
else
{
//do something
}
}
}
I had an issue implementing the accepted solution pattern where my ModelStateFilter would always return false (and subsequently a 400) for actionContext.ModelState.IsValid for certain model objects:
public class ModelStateFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest};
}
}
}
I only accept JSON, so I implemented a custom model binder class:
public class AddressModelBinder : System.Web.Http.ModelBinding.IModelBinder
{
public bool BindModel(HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext)
{
var posted = actionContext.Request.Content.ReadAsStringAsync().Result;
AddressDTO address = JsonConvert.DeserializeObject<AddressDTO>(posted);
if (address != null)
{
// moar val here
bindingContext.Model = address;
return true;
}
return false;
}
}
Which I register directly after my model via
config.BindParameter(typeof(AddressDTO), new AddressModelBinder());
You can also throw exceptions as documented here:
http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
Note, to do what that article suggests, remember to include System.Net.Http
Put this in the startup.cs file
services.AddMvc().ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = (context) =>
{
var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p =>p.ErrorMessage)).ToList();
var result = new Response
{
Succeeded = false,
ResponseMessage = string.Join(", ",errors)
};
return new BadRequestObjectResult(result);
};
});

WebAPI - Return Response from Initialize (override) method

I have the same code on each API method:
if (user.AspNetRoles.Where(p => p.Name == Models.Roles.SmartphonePhotographer).Count() == 0)
{
return Request.CreateResponse((HttpStatusCode)453, new { Message = "User does not have Smartphone Photographer role" });
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "User does not have Smartphone Photographer role");
}
if (!user.EmailConfirmed)
{
return Request.CreateResponse((HttpStatusCode)454, new { Message = "User is not confirmed" });
}
and want to return Response directly from override Initialize method. Can I do it?
(Of course, I have moved it to ActionFilter if had not set user variable in Controller)
protected override void Initialize(HttpControllerContext controllerContext)
{
int id = controllerContext.RequestContext.Principal.Identity.GetUserId<int>();
user = controllerContext.Request.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(id);
base.Initialize(controllerContext);
}
Override Initialize method is a void method so you can't return response result,
You should write on the response but in the Initialize method the response still not completed yet.
see this link
You can reroute to your method which return your response like the below
protected override void Initialize(HttpControllerContext controllerContext)
{
var newControllerContext = controllerContext
//edit RouteData to refer to your controller/action
newControllerContext.RouteData.Values["action"] = "YourAction"
base.Initialize(newControllerContext);
}

setting HttpContext.Current.User

I am developing an asp.net mvc 3.0 application which has a simple authentication process. User fills a form which is sent to server by ajax call and gets response, but the problem here is that using the following method :
FormsAuthentication.SetAuthCookie(person.LoginName,false);
is not enough to fill 'HttpContext.Current.User' and it needs the below method to be run :
FormsAuthentication.RedirectFromLoginPage("...");
Problem here is that as i mentioned, the loggin form uses an ajax form, and get responses with json, so redirecting is not possible.
How could I fill 'HttpContext.Current.User' ?
Thanks.
Update :
Here is register method :
[HttpPost]
public ActionResult Register(Person person)
{
var q = da.Persons.Where(x => x.LoginName == person.LoginName.ToLower()).FirstOrDefault();
if (q != null)
{
ModelState.AddModelError("", "Username is repettive, try other one");
return Json(new object[] { false, this.RenderPartialViewToString("RegisterControl", person) });
}
else
{
if (person.LoginName.ToLower() == "admin")
{
person.IsAdmin = true;
person.IsActive = true;
}
da.Persons.Add(person);
da.SaveChanges();
FormsAuthentication.SetAuthCookie(person.LoginName,false);
return Json(new object[] { true, "You have registered successfully!" });
}
}
FormsAuthentication doesn't support immediate setting of user's identity, but you should be able to fake it by something like this:
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(person.LoginName),
new string[] { /* fill roles if any */ } );
Here is the version I ended up using, which is based on the answer by #AdamTuliper-MSFT. It is only meant to be used right after logging in, but before redirect, to allow other code to access HttpContext.User.
Don't do anything if already authenticated
Doesn't modify the cookie, since this should only be used for the lifetime of this request
Shorten some things, and a little safer with userdata (should never be null, but...)
Call this after you call SetAuthCookie(), like below:
// in login function
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
AuthenticateThisRequest();
private void AuthenticateThisRequest()
{
//NOTE: if the user is already logged in (e.g. under a different user account)
// then this will NOT reset the identity information. Be aware of this if
// you allow already-logged in users to "re-login" as different accounts
// without first logging out.
if (HttpContext.User.Identity.IsAuthenticated) return;
var name = FormsAuthentication.FormsCookieName;
var cookie = Response.Cookies[name];
if (cookie != null)
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null && !ticket.Expired)
{
string[] roles = (ticket.UserData as string ?? "").Split(',');
HttpContext.User = new GenericPrincipal(new FormsIdentity(ticket), roles);
}
}
}
Edit: Remove call to Request.Cookies, as #AdamTuplier-MSFT mentioned.
You need to manually set it. Rather than reinventing the wheel, note the section here on updating the current principal for the request - thats your option here.
How to set Request.IsAuthenticated to true when not using FormsAuthentication.RedirectFromLoginPage?
public void RenewCurrentUser()
{
System.Web.HttpCookie authCookie =
System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = null;
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
FormsAuthenticationTicket newAuthTicket = authTicket;
if (FormsAuthentication.SlidingExpiration)
{
newAuthTicket = FormsAuthentication.RenewTicketIfOld(authTicket);
}
string userData = newAuthTicket.UserData;
string[] roles = userData.Split(',');
System.Web.HttpContext.Current.User =
new System.Security.Principal.GenericPrincipal(new FormsIdentity(newAuthTicket), roles);
}
}
}

how to use two submitt in one jsp and call two actions

i am working with spring mvc framework. i have two submit buttons on a page. that are forwarding request to two different controller. how can i use two action on single jsp page .
please suggest.
my controller are as
1.
#RequestMapping(value = "/user/reset", method = RequestMethod.POST)
public String editUser(#ModelAttribute("users") User user,
BindingResult result) {
Integer uid=user.getId();
User resetUser = usersService.findUser(uid);
resetUser.setActive(0);
ResetPasswordLog resetPasswordLog=new ResetPasswordLog();
usersService.addUsers(resetUser);
resetPasswordLogService.setTempHash(uid);
String TEMPHASH= resetPasswordLog.getTempHash();
System.out.println("www.lacas.com/reset?uid="+uid+"&th="+TEMPHASH);
return "redirect:/secure/user/" + uid;
}
2.
#RequestMapping(value = "/user/edit", method = RequestMethod.POST)
public String addUser(#ModelAttribute("users") UserForm userForm,
BindingResult result) {
Map<String, String> map = new LinkedHashMap<String, String>();
User user = usersService.findUser(userForm.getId());
Integer userId = userForm.getId();
User newUser = usersService.findUser(userForm.getEmail());
user.setName(userForm.getName());
if (newUser == null) {
user.setEmail(userForm.getEmail());
user.getRoles().clear();
Integer[] roleIds = userForm.getRoleIds();
for (Integer roleId : roleIds) {
if (roleId != 0) {
Role role = roleService.findRole(roleId);
user.getRoles().add(role);
}
}
usersService.addUsers(user);
return "redirect:/secure/users/index";
} else {
edit_exist_user = true;
return "redirect:/secure/user/" + userId;
}
}
You can by using JavaScript, and changing form's action attribute dynamically. If this is your form:
<form id="myform" action="#" onsubmit="return pickDestination();">
<input type="submit" name="sbmitbtn" value="edit" onclick="document.pressed=this.value"/>
<input type="submit" name="sbmitbtn" value="reset" onclick="document.pressed=this.value"/>
</form>
Then your pickDestination JS function would look like:
function pickDestination()
{
var a = "/user/" + document.pressed;
document.getElementById("myform").action = a;
return true;
}
I'm going to preface this by saying that I'm not very familiar with spring applications, however in many other java based MVC systems I've accomplished this by simply giving my submit buttons a name and parsing off this in the action class by checking the request.
For example find which submit button was used by it's parameter name, call the appropriate methods. The following is an example of a struts based solution I use on occasion. If you can access the servlet request object in your spring controller, you could do something similar.
#Override
public String execute() throws Exception {
try {
// Check the request for a someone clicking the logout submit button
if (found("logout")) {
user.logout(); //invoke the logout method
session.remove("user");
return SUCCESS;
}
// Check the request for a someone clicking the login submit button
if (found("login")) {
user.login();
session.put("user", user);
return "login";
}
// Catch any login exceptions
} catch (Exception e) {
user = null;
addActionError(e.getMessage());
return INPUT;
}
return SUCCESS;
}
// The following method checks for a request paramater based on the key (String)
// provided. If the key is not found or the value for the parameters is empty, it
// returns false;
private boolean found(String param) {
Object temp = request.getParameter(param);
if (temp != null) {
if (temp.toString().isEmpty()) {
return false;
}
return true;
} else {
return false;
}
}

Is there some way to clean up this controller code?

Most of the code I see online on MVC3 has very little code in the controller, but I can't seem to figure out how to make this code more streamlined.
Maybe if you take a look at it you can suggest improvements. If you need to see my UserModel class, let me know.
Here's the code for the Account controller.
namespace WebUI.Controllers
{
public class AccountController : Controller
{
public ActionResult Register()
{
UserModel model = new UserModel();
EFCityRepository cityRepo = new EFCityRepository();
model.Cities = new List<SelectListItem>();
foreach (var city in cityRepo.FindAllCities()) {
model.Cities.Add(new SelectListItem { Text = city.Name, Value = city.CityId.ToString(), Selected = true });
}
EFGenderRepository genderRepo = new EFGenderRepository();
model.Genders = new List<SelectListItem>();
foreach (var gender in genderRepo.FindAllGenders()) {
model.Genders.Add(new SelectListItem { Text = gender.Name, Value = gender.GenderId.ToString(), Selected = true });
}
return View(model);
}
[HttpPost]
public ActionResult Register(UserModel model)
{
EFCityRepository cityRepo = new EFCityRepository();
model.Cities = new List<SelectListItem>();
foreach (var city in cityRepo.FindAllCities())
{
model.Cities.Add(new SelectListItem { Text = city.Name, Value = city.CityId.ToString(), Selected = true });
}
EFGenderRepository genderRepo = new EFGenderRepository();
model.Genders = new List<SelectListItem>();
foreach (var gender in genderRepo.FindAllGenders())
{
model.Genders.Add(new SelectListItem { Text = gender.Name, Value = gender.GenderId.ToString(), Selected = true });
}
if (ModelState.IsValid)
{
Domain.User user = new Domain.User();
user.UserRoleId = 1;
user.Nickname = model.Nickname;
user.Name = model.Name;
user.Lastname = model.Lastname;
user.GenderId = model.GenderId;
user.Address = model.Address;
user.Email = model.Email;
user.Telephone = model.Telephone;
user.MobilePhone = model.MobilePhone;
user.Carnet = model.Carnet;
user.DateOfBirth = model.DateOfBirth;
user.DateOfRegistry = DateTime.Now;
user.LastDateLogin = DateTime.Now;
user.IsActive = false;
user.LanceCreditBalance = 5;
user.LancesSpent = 0;
user.Login = model.Login;
user.Password = model.Password;
user.EmailVerificationCode = "TempTokenString";
user.CityId = model.CityId;
EFUserRepository repo = new EFUserRepository();
var result = repo.CreateUser(user);
if (result == UserCreationResults.Ok)
{
FormsAuthentication.SetAuthCookie(model.Nickname, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
switch (result)
{
case UserCreationResults.UsernameExists:
ModelState.AddModelError("", "El nombre de usuario ya esta siendo utilizado.");
break;
case UserCreationResults.EmailAlreadyExists:
ModelState.AddModelError("", "Ese correo ya esta en uso.");
break;
case UserCreationResults.NicknameAlreadyExists:
ModelState.AddModelError("", "El nickname ya esta siendo utilizado.");
break;
case UserCreationResults.UnknownError:
ModelState.AddModelError("", "Algo durante el registro. Por favor intente de nuevo.");
break;
default:
break;
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
}
I'm using Entity Framework as my ORM, it generates a User class automatically for me. However, I made a User*Model* class so I could add data annotations for the views to use. Maybe this is the wrong idea?
I have many suggestions. For startes, read up about Dependancy Injection and Inversion of Control (DI and IoC). They will make all that boilerplate object instantiation a thing of the past.
Next, convert those for-each list builders into Linq expressions. Much more succinct and more likely faster as well.
Then, in your post handler, again do the same things there. In addition, get to know AutoMapper, which will automatically map your view to domain classes and make your life much easier.
If you did those things, your code would be reduced by 2x, maybe even 3.
EDIT:
An example linq query, because I really don't know the definition of your objects... would look something like this:
model.Cities = cityRepo.FindAllCities().Select(city => new SelectListItem() {
Text = city.Name, Value = city.CityId.ToString()}).ToList();
Notice how you don't have to new up a new List, since that's returned by the ToList() method. It is also using projection to select the items into a new SelectListItem.
Basically, you could write your method like this, using Dependancy Injection, Linq, and AutoMapper (it looks longer because i had to break lines multiple times to fit the small viewing are of SO):
namespace WebUI.Controllers
{
public class AccountController : Controller
{
private IGenderRepository _genderRepo;
private ICityrRepository _cityRepo;
private IUserRepository _userRepo;
public AccountController(IGenderRepository gr, ICityRepository cr,
IUserRepository ur)
{
_genderRepo = gr;
_cityRepo = cr;
_userRepo = ur;
}
public ActionResult Register()
{
UserModel model = new UserModel();
// Selected property is ignored by MVC on SelectListItems
model.Cities = _cityRepo.FindAllCities().Select(city =>
new SelectListItem() { Text = city.Name,
Value = city.CityId.ToString()}).ToList();
model.Genders = _genderRepo.FindAllGenders().Select(gender =>
new SelectListItem() { Text = gender.Name,
Value = gender.GenderId.ToString()}).ToList();
return View(model);
}
[HttpPost]
public ActionResult Register(UserModel model)
{
model.Cities = _cityRepo.FindAllCities().Select(city =>
new SelectListItem() { Text = city.Name,
Value = city.CityId.ToString()}).ToList();
model.Genders = _genderRepo.FindAllGenders().Select(gender =>
new SelectListItem() { Text = gender.Name,
Value = gender.GenderId.ToString()}).ToList();
if (ModelState.IsValid)
{
Domain.User user = Mapper.Map<Domain.User, Model>(model)
var result = _userRepo.CreateUser(user);
if (result == UserCreationResults.Ok) {
FormsAuthentication.SetAuthCookie(model.Nickname, false);
return RedirectToAction("Index", "Home");
} else {
ModelState.AddModelError("", GetErrorString(result));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
}
your Idea is good. Because it is not a good practice to have entity classes as the view models in MVC layer because it will create a tight coupling between your presentation and persistence logic.
To cleanup yuor code you can use AutoMapper ( http://automapper.codeplex.com/ ) to map your entity classes to view model easy without writing too many codes. http://jasona.wordpress.com/2010/02/05/getting-started-with-automapper/ here is a good article for you.

Resources