I am an MVC C# newbie.
I have a project which is using the built-in simple membership features of .net. I have that all working fine. I do however want to prevent a user from choosing certain usernames when registering which are NOT in the database already, such as swear words (of which I have been using plenty today).
I want to test against this list both in an ajax call and on submit. What is the proper way of going about this? I already have the system checking for usernames in use from the DB with no problem.
I have added a list called ReservedWords to the RegisterModel, but I just do not know where or how even to populate it so that it is available to the 2 controllers (async and post).
The Model looks like this:
public class RegisterModel
{
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public List<ReservedWord> ReservedWords { get; set; }
}
Am I supposed to populate it in the model file or in the controller? In either case can you please provide a sample?
The controller code is here for both the async and post backs:
// POST: /Account/doesUserNameExist async
[AllowAnonymous]
[HttpPost]
public JsonResult doesUserNameExist(string UserName)
{
var user = Membership.GetUser(UserName);
return Json(user == null);
}
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
Roles.AddUserToRole(model.UserName, Request.Form["RoleName"]);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Thanks in advance!!!!!
Update
So I followed the advice to create a custom validation attribute and it works great on submit. Thanks! Is there a way to get it to work with the client side validation? I have a similar custom validation attribute which compares two fields and makes sure they’re not equal. I followed that code but no luck. Here is the code now:
public class BlackListWordAttribute : ValidationAttribute, IClientValidatable
{
private const string defaultErrorMessage = "{0} cannot use forbidden word.";
private readonly List<string> blackListedWords = new List<string>();
public BlackListWordAttribute()
: base(defaultErrorMessage)
{
//populate from database or text file with cache dependency on either
blackListedWords.Add("bananas");
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
if (blackListedWords.Any(x => x.ToLower() == value.ToString().ToLower()))
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
//This is the name of the method added to the jQuery validator method (must be lower case)
ValidationType = "blacklistword"
};
}
}
Thanks again!
I would at using custom validation. If you change your mode to
Then the custom validation attribute could look something like:
You can store the blacklist either in the database or a file or xml or whatever.
Then you can add client side validation as well. To help with that look at using something like this Filthy List which you can access via a web service.
EDIT/UPDATE No 2:
As requested by the question asker. The best way to make the code available to both “async and post backs” is to create a string extension method. For instance,
The above class to be put either a referenced project or extensions folder with web project.
Then you can just call
For example:
in either scenarios