2

在我最后一个关于微调的问题的所有答案被证明比我预期的更有用之后,我想我也会问另一个关于 MembershipProviders 的类似问题。

好的,首先要澄清一下:我知道什么是会员、角色和个人资料提供者,如何实现我自己的,如何配置它们,以及关于它们的大部分内容。
实现角色和配置文件提供者非常简单,因为它们大多数时候只需要简单的 CRUD。(对于 RoleProvider 的大约一半方法来说,一行 LINQ 就足够了。)

但是,会员资格提供者是一个不同的野兽。你们中的许多人可能意识到它违反了 SR(单一责任)原则,因为它必须做与用户管理相关的所有事情。虽然这为自定义留下了很大的空间,但它也有其缺点。Internet 上没有关于它们的确切预期行为是什么的信息,例如它们应该何时抛出异常或简单地返回 null 等等。

我使用这个示例实现作为参考,但它也包含一些矛盾。

  • 例如,它使用自己的 ValidateUser 方法检查 ChangePassword 方法中的凭据。但 ValidateUser 还将用户的 LastLoginDate 更新为当前日期。那么,框架是否希望我也将它设置在我自己的提供程序中,或者它只是示例中的一个错误?
  • 另一种是:ChangePassword 方法每次验证新密码时都会抛出异常,但 CreateUser 不会抛出异常,它只是返回 false。
  • 最后但并非最不重要的一点是:它计算用户的无效密码尝试并在超过阈值时锁定它们。虽然这很好,但它需要手动操作来解锁用户。如果我的提供商在一定时间后自动解锁用户是否有问题?

  • (编辑)我差点忘了:示例中的 CreateUser 方法从方法参数中插入了 ID。我实际上认为这是不好的做法,因为我使用带有自动 incement 的 inters 作为 ID,所以从某个方法参数插入它们不是一种选择。我应该忽略该参数,还是要求其值为 null 并在不是时抛出异常?

总而言之,ASP.NET 是否对 MembershipProvider 的行为有任何假设?
是否有任何文档描述了我应该何时抛出异常或只返回 null?

我还试图找到一组通用单元测试,它们可以为预期的行为提供一些指导,但没有运气,我找到了很多关于“单元测试很好”和“如何对 MembershipProvider 进行单元测试”的文章,但没有一个会有任何实际测试的地方。

提前感谢大家!

4

1 回答 1

4

您可以咨询 MSDN 以获得指导。例如,RoleProvider.RemoveUsersFromRoles提供以下指导:

RemoveUsersFromRoles 由 Roles 类的 RemoveUserFromRole 、 RemoveUsersFromRole 、 RemoveUserFromRoles 和 RemoveUsersFromRoles 方法调用,以从数据源的指定角色中删除指定用户。仅修改配置的 ApplicationName 的角色。

如果没有为配置的 applicationName 找到任何指定的角色名称,我们建议您的提供程序抛出 ProviderException。

如果任何指定的用户名未与配置的 applicationName 的任何指定角色名相关联,我们建议您的提供程序抛出 ProviderException。

如果任何指定的用户名为 null 或为空字符串,我们建议您的提供程序抛出异常。

如果任何指定的角色名称为 null 或为空字符串,我们建议您的提供程序抛出异常。

如果您的数据源支持事务,我们建议您将每个删除操作都包含在事务中,并且在任何删除操作失败时回滚事务并引发异常。

RoleProvider.GetRolesForUser说:

GetRolesForUser 由 Roles 类的 GetRolesForUser 方法调用,以从数据源中检索与指定用户关联的角色名称。仅检索配置的 ApplicationName 的角色。

如果配置的 applicationName 的指定用户不存在任何角色,我们建议您的提供程序返回一个不包含任何元素的字符串数组。

如果指定的用户名为 null 或为空字符串,我们建议您的提供程序抛出异常。

但是,在实践中,每个提供者中只有少数方法和行为是必需的和预期的。其余的是对您希望实现的功能的支持。

经过几年处理默认提供程序堆栈后,我开始了解一些让您对链接到的示例感到犹豫的事情,这是一个非常简单的实现,例如在 ChangePassword 方法中走捷径。

如果您使用反射器并检查 SqlMembershipProvider,您会注意到一些显着差异......

例如:

  • ValidateUser 更新登录日期,因为,用户正在登录,它通过调用 .CheckPassword 和 true 为 UpdateLastLoginTime 来做到这一点。更改密码调用相同的方法,但提供错误。

  • CreateUser 方法接受 ProviderUserKey,因为 SPROC 也将接受 UserId 参数。这是为了允许在成员表和用户表之间重新创建和同步。作为 API 的使用者,您通常不会使用此功能,但提供程序堆栈会在内部使用。

  • 关于锁定..这取决于你。这就是实现自定义提供程序的全部内容:获得您想要的行为。正如我所说,系统要求很少。

因此,这将我们带到您问题的最后一部分(两段都提到了同样的问题):预期行为和单元测试......

由于提供者的行为在很大程度上是任意的,并且预期的行为很少,因此一组已建立的通用测试将包含很少的方法。您需要编写适用于您的实现行为的测试。

最后一点,我建议您查找下载Asp.Net 提供程序工具包示例。它为您提供完整的 Sql 提供程序堆栈的工作源代码,并将让您深入了解“真实”提供程序是如何实现的。

事后思考

此刻,我正在实现一个完整的 SQLite 提供程序堆栈,它与默认的 Sql 堆栈 100% 兼容。测试套件验证我的堆栈和 asp.net 之间的行为奇偶性。如果您通过我的个人资料访问我的博客并与我联系,我会在测试完成时通知您,您可以将它们用作基准,了解默认堆栈的确切预期。

于 2010-04-30T17:14:15.310 回答