Asp.net mvc 为什么在MVC4应用程序中初始化SimpleMembershipAttribute

Asp.net mvc 为什么在MVC4应用程序中初始化SimpleMembershipAttribute,asp.net-mvc,asp.net-mvc-4,simplemembership,Asp.net Mvc,Asp.net Mvc 4,Simplemembership,我认为我对SimpleMembershipProvider的理解几乎是60%,其他人正在了解它的内部工作原理 仅在AccountController(默认模板)中使用[InitializeSimpleMembership]过滤器时,您会很快发现一些问题。我认为无论您在哪里使用Memberhsip API或WebMatrix.WebSecurity,都需要确保首先调用此筛选器 稍后,如果在我的\u Layout.cshtml中使用User.IsInRole。您需要将筛选器应用于所有控制器,然后开始

我认为我对SimpleMembershipProvider的理解几乎是60%,其他人正在了解它的内部工作原理

仅在AccountController(默认模板)中使用
[InitializeSimpleMembership]
过滤器时,您会很快发现一些问题。我认为无论您在哪里使用Memberhsip API或
WebMatrix.WebSecurity
,都需要确保首先调用此筛选器

稍后,如果在我的
\u Layout.cshtml
中使用
User.IsInRole
。您需要将筛选器应用于所有控制器,然后开始在全局中注册它

然而,我刚刚意识到有一个
LazyInitializer.EnsureInitialized
,它使得每次应用程序启动只执行一次初始化

那么为什么
SimpleMembershipInitializer
(在过滤器中)不直接在应用程序启动中呢?
是否有任何理由使用过滤器?

我相信模板使用了一个属性进行数据库初始化,这样,如果初始化失败,站点的未经验证部分仍然可以工作


出于最实际的目的,最好在App_Start中完成此操作。

我花了一天的时间试图找出我的角色.getrolefourser失败的原因。这是因为懒散的初始化器没有被调用


就像马特说的,只要把它放在App_Start中,确保没有问题。

如果要将
初始化SimpleMembershipAttribute
合并到
全局.asax.cs
应用程序_Start
中,那么
SimpleMembershipProvider
将在不调用任何
AccountController
路由的情况下进行初始化

…它可能看起来像这样:

//下面的用法是“UsersContext”所必需的-它将与您的项目名称空间相关
使用mvcapapplication1.模型;
使用制度;
使用System.Data.Entity;
使用System.Data.Entity.Infrastructure;
使用系统线程;
使用System.Web.Http;
使用System.Web.Mvc;
使用System.Web.Optimization;
使用System.Web.Routing;
使用WebMatrix.WebData;
命名空间MVCAPApplication1
{
//注:有关启用IIS6或IIS7经典模式的说明,
//拜访http://go.microsoft.com/?LinkId=9394801
公共类MVC应用程序:System.Web.HttpApplication
{
受保护的无效应用程序\u Start()
{
RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
//确保每次应用程序启动仅初始化一次ASP.NET简单成员身份
LazyInitializer.确保重新初始化(参考初始值设定项,参考初始值设定项,参考初始值设定项锁定);
}
私有静态SimpleMembershipInitializer\u initializer;
私有静态对象_initializerLock=新对象();
私有静态布尔值初始化;
私有类SimpleMembershipInitializer
{
公共SimpleMembershipInitializer()
{
Database.SetInitializer(null);
尝试
{
使用(var context=new UsersContext())
{
如果(!context.Database.Exists())
{
//创建没有实体框架迁移模式的SimpleMembership数据库
((IObjectContextAdapter)context.ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection(“DefaultConnection”、“UserProfile”、“UserId”、“UserName”,autoCreateTables:true);
}
捕获(例外情况除外)
{
抛出新的InvalidOperationException(“无法初始化ASP.NET简单成员身份数据库。有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=256588“,ex);
}
}
}
}
}

InitializeSimpleMembership筛选器及其过于复杂的代码的原因是,当开发人员可能决定不使用表单身份验证时,模板生成的代码仍能正常工作。如果始终使用表单身份验证,则可以在Global.asax的Application\u Start方法中初始化SimpleMembership。有。

如果计划确保
InitializeSimpleMembership属性
在全球范围内运行,最好在
应用程序启动\FilterConfig.cs中使用MVC 4方式

public class FilterConfig
{
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
    filters.Add(new HandleErrorAttribute());
    filters.Add(new InitializeMembershipAttribute());
  }
}
保持Global.asax.cs与可能应该像MVC4与以前版本一样封装的代码保持一致。留下一个干净漂亮的房间:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}
我还建议将类型更改为AuthorizeAttribute(实际上就是这样做的),因为AuthorizeAttribute方法是在ActionFilterAttribute方法之前执行的。(如果其他ActionFilter正在检查安全性,并且允许派生的自定义属性,那么这应该会产生较少的问题)


我在这个问题上花了很多时间。但我最后只做了这样的改变:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new InitializeSimpleMembershipAttribute());

    }
}
我随机看到了以下错误

System.Web.HttpException(0x80004005):无法连接到SQL Server数据库。-->System.Data.SqlClient.SqlException(0x80131904):建立到SQL Server的连接时发生与网络相关或特定于实例的错误。找不到服务器或无法访问服务器。验证实例名称是否正确,以及SQL Server是否配置为允许远程连接。(提供程序:SQL网络接口,错误:26-定位指定的服务器/实例时出错)

我注意到,每当我看到错误时,我也会看到:

在ASP
[AttributeUsage(AttributeTargets.Class | 
                AttributeTargets.Method, 
                AllowMultiple = false, 
                Inherited = true)]
public class InitializeMembershipAttribute : AuthorizeAttribute
{
    private static SimpleMembershipInitializer _initializer;
    private static object _initializerLock = new object();
    private static bool _isInitialized;

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

    private class SimpleMembershipInitializer ...
    }
}
public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new InitializeSimpleMembershipAttribute());

    }
}
if (User != null && User.Identity != null && (User.IsInRole("publisher") || User.IsInRole("admin")))
    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()
        {
            Database.SetInitializer<DataContext>(null);
@{
    var maintenanceAccess = false;
    if (User != null && User.Identity != null && (User.IsInRole("publisher") || User.IsInRole("admin")))
   {
       maintenanceAccess = true;
   }
}
filters.Add(new InitializeSimpleMembershipAttribute()); public InitializeSimpleMembershipAttribute() { // Ensure ASP.NET Simple Membership is initialized only once per app start LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); }
[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 InitializeSimpleMembershipAttribute()
    {
        // Ensure ASP.NET Simple Membership is initialized only once per app start
        LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
    }

    //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()
        {
            Database.SetInitializer<UsersContext>(null);

            try
            {
                using (var context = new UsersContext())
                {
                    if (!context.Database.Exists())
                    {
                        // Create the SimpleMembership database without Entity Framework migration schema
                        ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                    }
                }

                WebSecurity.InitializeDatabaseConnection("Database_Connection_String_Name", "Users", "UserId", "UserName", autoCreateTables: true);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
            }
        }
    }
}