9

Azure Web サイトでホストしている基本的な ASP.NET MVC 4 サイトがあります。認証はフォーム認証であり、既定のテンプレートからカスタマイズされていません。公開するたびに、自分のサイトに再度アクセスすると、非常に長いタイムアウト (おそらく数分) でハングし、最終的にエラー メッセージが表示されます。ブラウザでサイトの Cookie を削除して再読み込みすることで回復できます。

当初、問題は認証が必要なページにアクセスしようとしただけでしたが、これを shared に追加しました_Layout.cshtml:

@if (User.IsInRole("Admin"))
{
    <li>@Html.ActionLink("Admin", "Index", "Admin")</li>
}

これは、新しい公開後にページにまったくアクセスできないことを意味するため、ログアウト リンクをクリックすることさえできません。これは、以前は問題を解決するための別の方法でした。

何か間違った設定をしましたか? 自分で使用できる回避策がありますが、更新を公開した後、これはサイトのユーザーにとって良い経験にはなりません。

編集: ELMAH ログから、IsInRole を呼び出すと、フォーム認証が SQL Express データベースを作成しようとしているようです。フォーム認証はすべて 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)
4

3 に答える 3

9

さまざまなブログ投稿からさまざまな提案を試した後、解決策を見つけました。ホームコントローラーに属性を追加InitialiseSimpleMembershipすると、問題が解決します。

[InitializeSimpleMembership]
public class HomeController : Controller

この変更を行った後、いくつかの成功したパブリッシュを問題なく管理しました。その理由は、InitializeSimpleMembershipAttribute呼び出しUser.IsInRoleが行われる前に、コンストラクター内の次のコード行を実行する必要があるためだと思います。

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

InitializeSimpleMembershipで走るのが一番いいと思いますApplication_Start

于 2012-10-20T19:21:21.750 に答える
4

tutorialアプリケーションを Windows Azure にデプロイするときに、SQL データベースをセットアップするために従うことができる手順は次のとおりです。インターネット テンプレートを使用して新しい ASP.NET MVC 4 アプリケーションを作成するときに、デフォルトでローカルの SQL Express データベースを指す web.config に正しい接続文字列を設定する必要があります。

SQL Azure 接続文字列は次のようになります。

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=tcp:#server#.database.windows.net,1433;Initial Catalog=#DBName#;User ID=UserName#@#server#;Password=#password#;MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
于 2012-10-20T16:13:16.630 に答える
1

この質問には答えましたが、同じ問題について自分の経験をすぐに共有できるのではないかと思いました。私の場合はマークの場合とは少し異なります。

そのため、InitializeSimpleMembershipすべてのコントローラーに属性がありました(実際には、すべてのコントローラーが継承するベースコントローラーに属性がありました)が、それでも同じ問題が発生していました。現在、ベースコントローラーではInitialize、アプリケーションのコンテキスト情報を設定するためにメソッドもオーバーライドしていました。このコンテキスト設定の一部は、現在のユーザーが特定のロールに属しているかどうかを確認することです。したがって、アクションメソッドが呼び出される前に、IsUserInRoleこのメソッド内からメソッドが呼び出されていました。Initialize

ここで、InitializeSimpleMembershipクラスを見ると、初期化が実際にOnActionExecutingメソッドで行われている(つまりInitializeSimpleMembership、から継承している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);
}

私の場合、このメンバーシップの初期化は遅すぎました...つまりIsUserInRole、ベースコントローラーのオーバーライドされたInitializeメソッドでを呼び出す前に、シンプルメンバーシップを初期化する必要があります。

私にとっての解決策は比較的単純でした。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誰かがコントローラーのオーバーライドされたメソッドで同様のことをしている場合に備えて、私の経験を説明したかっただけです。

于 2013-02-10T08:17:26.387 に答える