3

I want to check, that users table records does not have specific email already stored.

If there is, then ModelState.IsValid returns false in controller action.

I understand need of unique constraint and I understand issues with race conditions. Those are not my concern right now.

At this point I just want to make ModelState.IsValid to return false after querying data in right place and making model invalid.

Should I implement such validation:

  1. in DbContext?
  2. in my entity classes (User / Company etc.)?
  3. in SomeCustomValidation class?
  4. directly in controller (since there I can already query the database...)
  5. somewhere else...

And nice bonus would be create solution reusable across all entities :)

How should I do it?

0

2 Answers 2

4

You can custom validation attribute like below:

public class TestEmailAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        var context = (YourDbContext)validationContext.GetService(typeof(YourDbContext));
        if(!context.User.Any(a=>a.Email==value.ToString()))
        {
            return ValidationResult.Success;
        }
        return new ValidationResult("Email exists");
    }
}

Model:

public class User
{
    public int Id { get; set; }
    [TestEmail]
    public string Email { get; set; }
}

View(Test.cshtml):

@model User
<form method="post" asp-action="Test" asp-controller="Home">   
    <div class="form-group">
        <input asp-for="Email" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>

    <input type="submit" value="Post"/>
</form>

Controller:

//GET render the Test.cshtml
public async Task<IActionResult> Test()
{
    return View();
}
[HttpPost]
public async Task<IActionResult> Test(User user)
{
    if(!ModelState.IsValid)
    {
        return View(user);
    }
    return RedirectToAction("Index");
}
Sign up to request clarification or add additional context in comments.

1 Comment

Your example did work, although there are some null checks required to get rid of warnings, also I would like that TestEmailAttribute class would be UniqueAttribute that handles dynamically model and attribute. Since all of that is inside validationContext, I gues I can do that! Thank you for your answer.
0

better way is that you check it before every insert or update by :

if(db.Table.Any(x => x.UniqueCloumn == newValue))
    error = "this record is already exist"
else
{  
    db.Table.Add(newObject);
    db.Savechanges() 
}

also there is some approach for reusable code that I do not recommend : https://www.codeproject.com/Tips/1143215/Validate-a-Unique-Constraint-at-dbContext-Validate

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.