24

SimpleMembership可以与EF 模型优先一起使用吗?当我尝试它时,我在调用时收到“无法找到请求的 .NET Framework 数据提供程序”WebSecurity.InitializeDatabaseConnection.

WebSecurity.InitializeDatabaseConnection换句话说:当连接字符串使用System.Data.EntityClient提供者时(就像使用模型优先范式时一样),我无法调用 to work。

要重现此问题,请创建一个 MVC 4 应用程序,并将代码优先的UserProfile 实体类(您可以使用 MVC 4 模板免费获得)替换为您在实体设计器中创建的模型优先的用户类:

  1. 在VS 2012中创建一个 MVC 4 应用程序并添加一个新的空白实体数据模型。
  2. 添加一个名为User模型的新实体,其字段为Id, UserName, and FullName. 因此,此时,User数据实体被映射到一个Users表,并通过一个使用System.Data.EntityClient提供程序的时髦连接字符串进行访问。
  3. 验证EF是否可以访问User实体。一种简单的方法是根据 User 表及其关联的 DbContext 搭建一个 Users 控制器。
  4. 编辑该AccountModels.cs文件以删除UserProfile该类及其关联的UsersContext类。用对新 User 类及其关联类的引用替换对(现在缺少的)UserProfile和类的引用。UsersContextDbContext
  5. 将对 InitializeDatabaseConnection 的调用从 InitializeSimpleMembershipAttribute 过滤器类移至 Global.asax.cs 中的 Application_Start 方法。当您使用它时,修改参数以使用您的新用户实体的连接字符串、表名和 UserId 列名。
  6. 删除(不再使用的)InitializeSimpleMembershipAttribute 类和对它的引用。

当您运行repro时,它会在调用InitializeDatabaseConnection.

鲍勃

4

5 回答 5

24

SimpleMembership 可以先使用模型。这是解决方案。

1.InitializeSimpleMembershipAttribute.cs来自 MVC 4 Internet Application 模板应该是这样的

namespace WebAndAPILayer.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
    {
        private static SimpleMembershipInitializer _initializer;
        private static object _initializerLock = new object();
        private static bool _isInitialized;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Ensure ASP.NET Simple Membership is initialized only once per app start
            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
        }

        private class SimpleMembershipInitializer
        {
            public SimpleMembershipInitializer()
            {
                try
                {
                    WebSecurity.InitializeDatabaseConnection("ConnStringForWebSecurity", "UserProfile", "Id", "UserName", autoCreateTables: true);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException("Something is wrong", ex);
                }
            }
        }
    }
}

2.Delete CodeFirst Classes fromAcountModel.cs

AccountCotroler.cs3.修复以使用您的模型优先的 DbContext(方法ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)

4.定义您的"ConnStringForWebSecurity"连接字符串,它与用于模型优先数据库访问的时髦 conn 字符串不同,请注意我们使用 provider System.Data.SqlClientnotSystem.Data.EntityClient

 <connectionStrings>
         <add name="ModelFirstEntityFramework" connectionString="metadata=res://*/Context.csdl|res://*/Context.ssdl|res://*/Context.msl;provider=System.Data.SqlClient;provider
 connection string=&quot;data source=.\SQLEXPRESS;Initial
 Catalog=aspnet-MVC4;Integrated
 Security=SSPI;multipleactiveresultsets=True;App=EntityFramework&quot;"
 providerName="System.Data.EntityClient" />
         <add name="ConnStringForWebSecurity" connectionString="data source=.\SQLEXPRESS;Initial Catalog=aspnet-MVC4;Integrated
 Security=SSPI" providerName="System.Data.SqlClient" />
       </connectionStrings>
于 2012-10-23T19:33:55.213 回答
12

这是 MVC 4 中的一个错误。这篇博文中有一个解决方法

作为一个动作过滤器,InitializeSimpleMembershipAttribute挂钩OnActionExecuting来执行延迟初始化工作,但这在生命周期中可能为时已晚。OnAuthorization如果需要执行基于角色的访问检查(在 期间),Authorize 属性将需要提供者提前准备好。换句话说,如果对站点的第一个请求遇到如下控制器操作:

[Authorize(Roles="Sales")]

..那么你会有一个例外,因为过滤器检查用户的角色,但提供者没有初始化。

我的建议是从项目中删除 ISMA,并在应用程序启动事件期间初始化 WebSecurity。

于 2012-09-25T13:48:46.880 回答
10

1 - 您需要启用迁移,最好使用 EntityFramework 5

2 - 移动你的

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 

到 YourMvcApp/Migrations/Configuration.cs 类中的 Seed 方法

    protected override void Seed(UsersContext context)
    {
        WebSecurity.InitializeDatabaseConnection(
            "DefaultConnection",
            "UserProfile",
            "UserId",
            "UserName", autoCreateTables: true);

        if (!Roles.RoleExists("Administrator"))
            Roles.CreateRole("Administrator");

        if (!WebSecurity.UserExists("lelong37"))
            WebSecurity.CreateUserAndAccount(
                "lelong37",
                "password",
                new {Mobile = "+19725000000", IsSmsVerified = false});

        if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
            Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
    }

现在 EF5 将负责创建您的 UserProfile 表,这样做之后您将调用 WebSecurity.InitializeDatabaseConnection 以仅向已创建的 UserProfile 表注册 SimpleMembershipProvider (在您的情况下,您可以将“UserProfile”参数值替换为您的自定义表name),还告诉 SimpleMembershipProvider 哪一列是 UserId 和 UserName。我还展示了一个示例,说明如何在 Seed 方法中添加用户、角色并将两者与自定义 UserProfile 属性/字段(例如用户的手机(号码))相关联。

3 - 现在,当您从包管理器控制台运行 update-database 时,EF5 将为您的表提供所有自定义属性

有关其他参考资料,请参阅本文的源代码: http ://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom -用户属性/

于 2012-09-28T17:50:02.367 回答
1

这个问题是由于WebSecurity.InitializeDatabaseConnection不能使用连接字符串和System.Data.EntityClient提供者名称引起的。

提供双连接字符串听起来不太好,因此您可以先在部分类的构造函数中生成 EF 模型的连接字符串。

代码如下所示

public partial class MyDataContext 
{
    private static string GenerateConnectionString(string connectionString)
    {
        var cs = System.Configuration.ConfigurationManager
                     .ConnectionStrings[connectionString];

        SqlConnectionStringBuilder sb = 
             new SqlConnectionStringBuilder(cs.ConnectionString);
        EntityConnectionStringBuilder builder = 
             new EntityConnectionStringBuilder();
        builder.Provider = cs.ProviderName;
        builder.ProviderConnectionString = sb.ConnectionString;
        builder.Metadata = "res://*/MyDataContext.csdl|" +
              "res://*/MyDataContext.ssdl|res://*/MyDataContext.msl";
        return builder.ToString();
    }

    public MyDataContext(string connectionName) : 
          base(GenerateConnectionString(connectionName)) { }
}

通过这个技巧,您可以在 Web 配置中使用单个连接字符串,但一个问题是您不能在数据上下文中使用默认构造函数,而是在实例化数据上下文时应在任何地方播种连接字符串名称。但是当您使用依赖注入模式时,这不是一个大问题。

于 2013-01-13T23:30:20.633 回答
0

我无法使用 EF 和 WebMatrix webSecurity 类,所以要避免这个问题并继续:

首先将我的 Ef 模型更改为先编码。

更改连接字符串以使用 providerName="System.Data.SqlClient"(删除所有元数据信息)或使用 EF 连接

在我的情况下,模型、数据和 web 是不同的项目,所以对我来说,从 web.project 上的 web.config 中删除这些信息不是问题。

现在 websecuroty.initializeddatabase 不使用 EF 连接字符串运行。

我希望这有帮助

于 2012-09-30T21:02:37.587 回答