2

既知の利点 (Web ファーム、IIS のリサイクル) のために、Session を処理するために StateServer を使用します。

ただし、このフォールトトレラントを作成する方法を理解しようとしています。セッションに保存するものは重要ではなく、単にパフォーマンスのために使用されます。そのため、StateServer が利用できない場合は、ディスクからリロードできます。

ただし、StateServer がオンラインかどうかを検出する方法はないようです。したがって、StateServer がダウンしていても、次のコードはすべて正常に実行されます。

try
{
    //It is not NULL as it has been configured
    if (HttpContext.Current.Session != null)
        Session["Test"] = "value";
}
// No exception is thrown
catch (Exception)
{
    throw new Exception();
}

これで、例外がスローされないことは理にかなっています。書き込みごとにステータスをチェックする必要がある場合、セッション処理のパフォーマンスはあまり高くありません。したがって、応答が書き込まれるときにすべてのセッション変数が書き込まれると思います。

セッションを書き込もうとすると 500 エラーで失敗し、とにかくこのエラーをインターセプトして処理する方法がわからないという問題があります。

セッション状態サーバーにセッション状態要求を行うことができません。ASP.NET State サービスが開始されていること、およびクライアントとサーバーのポートが同じであることを確認してください。

私が望んでいるのは、書き込みがサイレントに失敗する (またはエラーをログに記録する) だけで、クライアントが影響を受けないことです。今書いているように、この単一障害点が原因でサイト全体がダウンします。

任意のアイデア - 明らかな何かが欠けていますか?

4

2 に答える 2

1

まあ、それは難しいかもしれません。Asp.net はセッションを厳密に使用するため、セッション ストレージが失敗すると、セッション モジュールの初期化中にも asp.net が失敗します。既存のものをラップする独自のセッション状態プロバイダーを作成できます。失敗した場合は空のセッション項目を返しますが、セッションの動作が予測できないため、使いにくい場合があります。

SQLサーバーにレプリケーションがある場合に備えて、フェイルオーバーを備えた組み込みのSQLセッション状態プロバイダーを調べることができます。

更新1

デフォルトのセッション プロバイダーのラッパーの例を次に示します。

public class SessionProviderWrapper : SessionStateStoreProviderBase
{
    private readonly SessionStateStoreProviderBase _provider;

    private static Func<SessionStateStoreProviderBase> _createProvider;

    static SessionProvider()
    {
        _createProvider = InitializerProvider();
    }

    private static Func<SessionStateStoreProviderBase> InitializerProvider()
    {
        if (_createProvider != null)
            return _createProvider;

        var sessionType = "stateserver"; // you can switch to another session provider

        Type type;
        switch (sessionType)
        {
            case "inproc":
                type = Type.GetType("System.Web.SessionState.InProcSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                break;

            case "sql":
                type = Type.GetType("System.Web.SessionState.SqlSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                break;

            case "stateserver":
                type = Type.GetType("System.Web.SessionState.OutOfProcSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                break;

            default:
                throw new ConfigurationErrorsException("Unknow session type: " + sessionType);
        }

        if (type == null)
        {
            throw new InvalidOperationException("Failed to find session provider for " + sessionType);
        }

        _createProvider = GenerateConstructorCall(type);

        return _createProvider;
    }

    private static Func<SessionStateStoreProviderBase> GenerateConstructorCall(Type type)
    {
        // we are searching for public constructor
        var constructor = type.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 0);
        if (constructor == null)
        {
            // otherwise for internal. SQL session provider has internal constructor, but we don't care
            constructor = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Length == 0);
        }

        var node = Expression.New(constructor);
        var lambda = Expression.Lambda<Func<SessionStateStoreProviderBase>>(node, null);
        var func = lambda.Compile();
        return func;
    }

    public SessionProvider()
    {
        var createProvider = InitializerProvider();

        _provider = createProvider();
    }

    public override void Initialize(string name, NameValueCollection config)
    {
        _provider.Initialize(name, config);
    }

    public override string Name
    {
        get { return _provider.Name; }
    }

    public override string Description
    {
        get { return _provider.Description; }
    }

    public override void Dispose()
    {
        _provider.Dispose();
    }

    public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
    {
        return _provider.SetItemExpireCallback(expireCallback);
    }

    public override void InitializeRequest(HttpContext context)
    {
        _provider.InitializeRequest(context);
    }

    public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId,
                                         out SessionStateActions actions)
    {
        try
        {
            return _provider.GetItem(context, id, out locked, out lockAge, out lockId, out actions);
        }
        catch (Exception ex)
        {
            locked = false;
            lockAge = TimeSpan.Zero;
            lockId = null;
            actions = SessionStateActions.None;
            // log ex
            return new SessionStateStoreData(new SessionStateItemCollection(), new HttpStaticObjectsCollection(), 10);
        }
    }

    public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId,
                                                  out SessionStateActions actions)
    {
        return _provider.GetItemExclusive(context, id, out locked, out lockAge, out lockId, out actions);
    }

    public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
    {
        _provider.ReleaseItemExclusive(context, id, lockId);
    }

    public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
    {
        _provider.SetAndReleaseItemExclusive(context, id, item, lockId, newItem);
    }

    public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
    {
        _provider.RemoveItem(context, id, lockId, item);
    }

    public override void ResetItemTimeout(HttpContext context, string id)
    {
        _provider.ResetItemTimeout(context, id);
    }

    public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
    {
        return _provider.CreateNewStoreData(context, timeout);
    }

    public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
    {
        _provider.CreateUninitializedItem(context, id, timeout);
    }

    public override void EndRequest(HttpContext context)
    {
        _provider.EndRequest(context);
    }
}

基本的には GetItem メソッドのように各メソッドで try\catch を行うことができ、エラーの場合は空のセッション オブジェクトを返すことができます。try\catch で失敗した場合でも、アプリケーションは生きています。ただし、要求ごとに Get\Release でいくつかの例外がスローされ、catch セクションで処理されるため、パフォーマンスが低下します。とにかく、これらの例外はパフォーマンスを少し低下させます

于 2013-12-24T19:27:49.787 に答える
0

私にとって有効な解決策として tgolisch の回答を受け入れたいと思います。

  • Global.asax では、Application_Error イベントで欠落している StateServer エラーを探します。
  • 見つかった場合は、 Server.ClearError() を使用してエラーをログに記録します
  • また、これを使用してエラーをログに記録し、場合によってはアラートを送信します

皆さんありがとう!

于 2013-12-24T19:51:29.777 に答える