C#+代码合同 - 抛出异常

时间:2010-12-24 22:30:15

标签: c# exception exception-handling code-contracts

更新 - 由于我方缺乏解释,我改写了帖子。

您如何看待使用代码约定在无效输入上抛出异常? (我正在根据我的服务合同进行编码,该合同要求UserName不为空或包含空格)

MembershipServiceContracts.cs - 位于子文件夹中的服务层

[ContractClassFor(typeof (IMemberShipService))]
internal abstract class MemberShipServiceContracts : IMemberShipService
{
    #region IMemberShipService Members

    public MembershipCreateStatus CreateUser(string userName, string password, string email)
    {
        Contract.Requires(!String.IsNullOrWhiteSpace(userName), "Test");
        Contract.Requires(!String.IsNullOrWhiteSpace(password));
        Contract.Requires(!String.IsNullOrWhiteSpace(email));

        return default(MembershipCreateStatus);
    }

    #endregion

}

MembershipService.cs - 位于我的服务层

[ContractClass(typeof (MemberShipServiceContracts))]
public interface IMemberShipService
{
    MembershipCreateStatus CreateUser(string userName, string password, string email);
}

public class MemberShipService : IMemberShipService
{
    private readonly MembershipProvider _provider;

    public MemberShipService()
        : this(null)
    { }

    public MemberShipService(MembershipProvider provider)
    {
        _provider = provider ?? Membership.Provider;
    }

    #region IMemberShipService Members

    public MembershipCreateStatus CreateUser(string userName, string password, string email)
    {
        MembershipCreateStatus status;
        _provider.CreateUser(userName, password, email, null, null, true, null, out status);

        return status;
    }

    #endregion
}

AccountController.cs - 位于UI层

现在这是有趣的部分......

我应该使用:

    [Authorize(Roles = "Developer")]
    [HttpPost]
    public ActionResult Create(CreateUserViewModel model)
    {
        if (!String.IsNullOrEmpty(model.UserName))
        {
            throw new ArgumentException("UserName May not be null or contain only white spaces.", model.UserName);
        }

        if (!String.IsNullOrEmpty(model.Password))
        {
            throw new ArgumentException("Password May not be null or contain only white spaces", model.Password);
        }

        if (!String.IsNullOrEmpty(model.Email))
        {
            throw new ArgumentException("Email May not be null or contain only white spaces", model.Email);
        }

        if (!ModelState.IsValid)
        {
            return Json("Model validation failed");
        }

        MembershipCreateStatus newUser = _memberShipService.CreateUser(model.UserName, model.Password,
                model.Email);

        return Json(newUser != MembershipCreateStatus.Success ? "Failed" : "Success");
    }

或:

[Authorize(Roles = "Developer")]
[HttpPost]
public ActionResult Create(CreateUserViewModel model)
{
    Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(model.UserName),
            "UserName May not be null or contain only white spaces.");

    Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(model.Password),
            "Password May not be null or contain only white spaces");

    Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(model.Email),
            "Email May not be null or contain only white spaces");

    if (!ModelState.IsValid)
    {
        return Json("Model validation failed");
    }

    MembershipCreateStatus newUser = _memberShipService.CreateUser(model.UserName, model.Password,
            model.Email);

    return Json(newUser != MembershipCreateStatus.Success ? "Failed" : "Success");
}

如果未满足CreateUser()方法的代码合同,则抛出异常?

提前致谢。

3 个答案:

答案 0 :(得分:7)

代码合同中的失败表明您的代码存在应该修复的严重错误。它不会取代用户输入的验证。相反,您将首先验证您的用户输入,然后在确定有效时尝试处理数据(否则提示用户重新输入)。如果您不满足目标合同与您的有效数据,那么将抛出一个无法捕获的异常,因为您显然有一个错误。

我希望它会成为一颗银弹,但很快意识到我仍然需要我的验证。在那之后,我逐渐变得非常喜欢代码合同将取代我所有常用的守卫代码的方式。

想想你会得到一个NullReferenceException(对我来说太多了!)。代码合同可以消除这种痛苦。

R上。

P.S。另外,不要使用契约来验证安全敏感数据,因为代码契约可以在运行时关闭......

答案 1 :(得分:4)

我不敢说:这取决于您希望如何使用代码合同。

您最好查看user manual部分“使用指南”。这是一个小摘录:

  

最简单地使用合同工具   如果你决定不需要的话   执行参数验证   发布版本中的运行时(用法1)。   在这种情况下,您使用合同   开发过程中的工具,但不是   装运的位。记住,你可以   发运合同参考组件   以及你的释放位18   客户端可以获得运行时检查   你的参数验证   通过call-site需要调试构建   检查。第二个最简单的方法   如果你需要参数验证   您的发布版本将打开   所有版本中的合同检查(用法   2)。因此你利用了   生成运行时的工具   你的条件和   为你执行合同继承。   你可以选择生产specic   参数的例外情况   验证,或具有默认值   ContractException。

我建议你在做出任何重大决定之前阅读整篇文章。

答案 2 :(得分:0)

这两种方法都很好。

用于检查前置条件的3种方式是

  1. Contract.Requires - &gt;进入该方法后,特定条件必须为真。

  2. Contract.Requires - &gt;与上述相同但如果条件不满足则抛出异常 需求始终是编译的,因此使用此方法需要对工具进行严格依赖。在使用此方法之前,您应该决定是否需要它。

  3. 您的第一种方法 - &gt;这种前提条件的好处是始终可以执行运行时检查。

  4. 在第一种方法中,您可能希望添加Contract.EndContractBlock();

    我自己正在探索此功能,但我认为您可以在服务层中抛出异常并且没问题。

    HTH