将MVC 4应用程序发布到azure后的身份validation问题

我有一个基本的ASP.NET MVC 4站点,我在Azure网站上托管。 身份validation是表单身份validation,尚未从默认模板进行自定义。 每次我发布时,当我重新访问我的网站时,它只会挂起很长的超时(也许几分钟),最后会向我显示一条错误消息。 我可以通过在浏览器中删除网站的cookie并重新加载来恢复。

最初问题只是尝试访问需要身份validation的页面,但后来我将其添加到我的共享_Layout.cshtml

 @if (User.IsInRole("Admin")) { 
  • @Html.ActionLink("Admin", "Index", "Admin")
  • }

    现在意味着在新发布之后根本没有页面可访问,因此我甚至无法单击注销链接,这是我以前能够解决问题的另一种方式。

    我有错误的配置吗? 虽然我有自己可以使用的解决方法,但在发布更新后,这对于网站用户来说不是一个好的体验。

    编辑:从ELMAH日志,似乎表单身份validation尝试在我调用IsInRole时创建SQL Express数据库。 我不明白为什么会这样做,因为我的表单身份validation都设置为使用我的SQL Azure数据库。

     System.Web.HttpException (0x80004005): Unable to connect to SQL Server database. ---> System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean withFailover) at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject, Boolean withFailover) at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout) at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance) at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance) at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup) at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) at System.Data.SqlClient.SqlConnection.Open() at System.Web.Management.SqlServices.GetSqlConnection(String server, String user, String password, Boolean trusted, String connectionString) ClientConnectionId:00000000-0000-0000-0000-000000000000 at System.Web.Management.SqlServices.GetSqlConnection(String server, String user, String password, Boolean trusted, String connectionString) at System.Web.Management.SqlServices.SetupApplicationServices(String server, String user, String password, Boolean trusted, String connectionString, String database, String dbFileName, SqlFeatures features, Boolean install) at System.Web.Management.SqlServices.Install(String database, String dbFileName, String connectionString) at System.Web.DataAccess.SqlConnectionHelper.CreateMdfFile(String fullFileName, String dataDir, String connectionString) at System.Web.DataAccess.SqlConnectionHelper.EnsureSqlExpressDBFile(String connectionString) at System.Web.DataAccess.SqlConnectionHelper.GetConnection(String connectionString, Boolean revertImpersonation) at System.Web.Security.SqlRoleProvider.GetRolesForUser(String username) at WebMatrix.WebData.SimpleRoleProvider.GetRolesForUser(String username) at System.Web.Security.RolePrincipal.IsInRole(String role) 

    在尝试了各种博客文章中的数十种不同建议之后,我找到了一个解决方案。 将InitialiseSimpleMembership属性添加到我的家庭控制器可以解决问题。

     [InitializeSimpleMembership] public class HomeController : Controller 

    进行此更改后,我成功地管理了几个成功的发布。 我怀疑原因是在对User.IsInRole进行任何调用之前, InitializeSimpleMembershipAttribute构造函数中的以下代码行需要运行:

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

    我想最好的办法是在Application_Start运行InitializeSimpleMembership

    这是在Windows Azure上部署应用程序时可以按照设置SQL数据库的tutorial 。 您必须在web.config中设置正确的连接字符串,当使用Internet模板创建新的ASP.NET MVC 4应用程序时,该字符串默认指向本地SQL Express数据库。

    您的SQL Azure连接字符串将如下所示:

        

    虽然这个问题已得到解答,但我想我可能会很快分享我对同一问题的经验。 我的情况与马克的情况略有不同。

    所以,我在所有控制器上都有InitializeSimpleMembership属性(实际上我在我的所有控制器inheritance的基础控制器上都有它),但是我仍然遇到同样的问题。 现在,在我的基本控制器中,我还重写了Initialize方法,以便为我们的应用程序设置一些上下文信息。 此上下文设置的一部分是检查当前用户是否处于特定角色,因此在调用任何操作方法之前,都会从此Initialize方法中调用IsUserInRole方法。

    现在,如果查看InitializeSimpleMembership类,则会注意到初始化实际上是在OnActionExecuting方法中完成的(即InitializeSimpleMembershipinheritance自ActionFilterAttribute ):

     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); } 

    在我的情况下,这个成员资格初始化发生得太晚了……也就是说,我需要初始化Simple Membership才能在我的基本控制器覆盖的Initialize方法中调用IsUserInRole

    对我来说解决方案相对简单:我完全删除了InitializeSimpleMembership属性并将其逻辑直接放入我的基本控制器中,以便我可以从我的Initialize方法调用它,如下所示:

     public class BaseController : Controller { private static SimpleMembershipInitializer _initializer; private static object _initializerLock = new object(); private static bool _isInitialized; private class SimpleMembershipInitializer { public SimpleMembershipInitializer() { try { WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "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); } } } ... protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); SetupControllerContext(); // my function that calls 'IsUserInRole' } } 

    现在我想象一个人应该重构这个并把它放在Application_Start()方法中,正如Mark建议的那样,但你明白了:)。 我只是想解释一下我的经验,以防万一有人在他们的控制器覆盖的Initialize方法中做了类似的事情。