存储库模式 - 验证对象和返回消息

时间:2017-06-06 08:39:15

标签: c# asp.net model-view-controller repository-pattern

我正在一个网站上工作,只是试图了解一般结构。我在后台有一个数据库,我正在使用“存储库模式”访问。我在 UserRepository 类中有以下代码:

public bool IsValid(User user)
{
  if (_context.Users.Any(c => c.EmailAddress == user.EmailAddress))
  {
    Message = "Email address already in use";
    return false;
  }

  return true;
}

这是在这里实施的

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(User user)
{
  if (ModelState.IsValid)
  {
    var context = new Context("DatabaseContext");
    var userRepo = new UserRepository(context);

    if (userRepo.IsValid(user))
    {
      userRepo.Add(user);
      // return to different view
    }
    else
    {
      // display userRepo.Message on page
      return View(user);
    }
  }

  return View(user);
}

我的问题是我不认为我正确地绕过“消息”位,但我找不到任何在线帮助我(特别是在存储库周围)。我认为我应该将 IsValid 的返回类型更改为结果(就像我在对话框中看到的那样),但同样,我不确定。

非常感谢任何帮助。

感谢。

3 个答案:

答案 0 :(得分:2)

实现此目的的一种方法与您建议的完全一样 - 更改IsValid 的返回类型。

过去我在“业务层”中有类似的验证方法,它返回ValidationResult的集合,其中每个返回的记录都会在模型中解释验证错误,而空集合将被解释为有效的模型。

例如:

public class ValidationResult
{
    public string FieldName { get; set; }
    public string Message { get; set; }
}

public interface IValidator<T>
{
    IEnumerable<ValidationResult> IsValid(T model);
}

//...in your implementation
public IEnumerable<ValidationResult> IsValid(User user)
{
    //Return a new ValidationResult per validation error
    if (_context.Users.Any(c => c.EmailAddress == user.EmailAddress))
    {
        yield return new ValidationResult
        {
            Message = "Email address already in use",
            FieldName = nameof(user.EmailAddress)
        };
    }
}

然后,您的表示层可以将其解释为反馈给用户。

答案 1 :(得分:2)

我同意你提到的问题。返回自定义类将更好地接近IMO。

public ValidationResult IsValid(User user)
{
  ValidationResult validationResult = new ValidationResult(true, "");
  if (_context.Users.Any(c => c.EmailAddress == user.EmailAddress))
  {
    validationResult.Status = false;
    validationResult.Message = "Email address already in use";
    return validationResult;
  }

  return validationResult;
}

这样,StatusMessage会为您提供所需的所有信息。首先检查状态。如果为false,请检查消息以获取确切的详细信息。

答案 2 :(得分:1)

虽然上述用户提供的解决方案很好,但我不认为你这样做是正确的。这种验证电子邮件地址解决方案有一些缺点。

假设如果电子邮件可用(无效,因为这不是有效性),那么您必须返回错误视图。如果所有输入电子邮件地址都可用,那么最终用户将多次获得此错误但整个视图将在每个请求中呈现,这不是一个好的做法。总是尝试在这种情况下使用远程验证。

在您的模型属性(电子邮件)上使用Remoteattribute,并尝试通过JsonResult动态返回可用性消息。我将为您提供此演示示例,您可以随意在代码中实现。

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public JsonResult IsEmailAvailable(string emailAddress)
{
    if (!_context.Users.Any(c => c.EmailAddress == emailAddress))
    {
         return Json(true, JsonRequestBehavior.AllowGet);
    }
    return Json("Email address already taken" , JsonRequestBehavior.AllowGet);
}

为了防止ASP.NET MVC缓存验证方法的结果,需要OutputCacheAttribute属性。

装饰您的模型电子邮件属性,如下所示:

//inside you model.
    [Required]
    [Remote("IsEmailAvailable", "YourControllerName")]
    [RegularExpression(@"Your email address validation regex here", ErrorMessage = "Email address is not valid .")]
    [Editable(true)]
    public string Email{ get; set; }

并在Web.config文件中添加此代码段以允许使用Remote属性:

<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

register操作方法中删除以下代码。

if (userRepo.IsValid(user))
    {
      userRepo.Add(user); //write this only inside code cause you will always get valid email now.
      // return to different view
    }
    else
    {
      // display userRepo.Message on page
      return View(user);
    }

我希望这会奏效。有关更多信息,请阅读本文。 https://msdn.microsoft.com/en-us/library/gg508808(vs.98).aspx