ASP.NET:在会话中存储类属性和使用会话处理程序 - 这是一个好的设计吗?

时间:2010-07-27 21:56:09

标签: c# asp.net oop

我有一个名为EditMapUtilities的类。

以下是我想要保留的一些类属性:

public class EditMapUtlities
{
    public static Boolean isInitialEditMapPageLoad
    {
        get { return SessionHandler.isInitialEditMapPageLoad; }
        set { SessionHandler.isInitialEditMapPageLoad = value; }
    }

// REST OF CLASS NOT GERMAIN TO DISCUSSION AND OMITTED
}

这是我的SessionHandler类,遵循这篇文章的模式 Static Session Class and Multiple Users

using System.Web.SessionState;


public static class SessionHandler
{
    private static HttpSessionState currentSession
    {
        get
        {
            if (HttpContext.Current.Session == null)
                throw new Exception("Session is not available in the current context.");
            else
                return HttpContext.Current.Session;
        }
    }

    //A boolean type session variable
    private static string _isInitialEditMapPageLoad = "EditMapInitialPageLoad";
    public static bool isInitialEditMapPageLoad
    {
        get 
        {
            if (currentSession[_isInitialEditMapPageLoad] == null)
                return true;
            else
                return (Boolean)currentSession[_isInitialEditMapPageLoad];    
        }
        set
        {
            currentSession[_isInitialEditMapPageLoad] = value;
        }
    }
}

我还在学习OOAD。我想保留相关属性的相关属性。我还想将所有Session存储的变量保存在一个地方,以便于维护并封装会话密钥和调用。

我觉得我的设计太融洽了。如何使它更松散耦合?我的editMapUtilities类是否与SessionHandler类紧密耦合?你会怎样做得更好?

2 个答案:

答案 0 :(得分:5)

你的直觉非常好,因为你的班级确实非常紧密地相互耦合。我将引用Bob Martin的Principles of Object Oriented Design

Single Responsibility Principle之后,您希望确保在其中一个类更改时不必更新这两个类。现在两个班级对彼此都知之甚少。

我们可以从EditMapUtilites开始,并重构对会话处理程序的访问,以更准确地传达意图。主要是,应用程序状态作用于用户。此外,我们可以通过使用实现相同目标的方法来更改访问这些值的方式,使其更少耦合。

public class EditMapUtlities
{
    //Omitting the wireup details for now
    private SessionHandler ApplicationState {get; set;}

    public static Boolean isInitialEditMapPageLoad
    {
        get { return ApplicationState.GetValue<Boolean>("EditMapInitialPageLoad"); }
        set { ApplicationState.SetValue("EditMapInitialPageLoad", value); }
    }

// REST OF CLASS NOT GERMAIN TO DISCUSSION AND OMITTED
}

SessionHandler类现在包含两个新方法:

public static T GetValue<T>(String key)
{
    return currentSession[key] ?? default(T);
}

public static void SetValue(String key, Object val)
{
    currentSession[key] = val;
}

好的,所以现在一个类稍微冗长一点,但是你的会话类更简单,更灵活。添加其他值很简单,但您可能会问自己为什么不直接使用直接会话?

我们以这种方式重组课程的原因是让我们更接近他们之间的干净休息。通过财产访问我们的SessionHandler课程,我们现在可以进一步重构我们,并使用Dependency Inversion Principle

为什么我们不抽象在接口后面存储Application State变量,而不是依赖于SessionHandler的具体实现。一个看起来像这样:

public interface IApplicationState
{
    public T GetValue<T>(String key);
    public SetValue(String key, Object val);
}

现在我们可以简单地更改EditMapUtlities内部的属性以使用接口,并使用良好的手动依赖注入将其传递给构造函数。

public class EditMapUtlities
{
    //Omitting the wireup details for now
    private IApplicationState ApplicationState {get; set;}

    public EditMapUtilities(IApplicationState appState)
    {
        if(appState == null) throw new ArgumentNullException("appState");

        ApplicationState = appState;
    }

    public static Boolean isInitialEditMapPageLoad
    {
        get { return ApplicationState.GetValue<Boolean>("EditMapInitialPageLoad"); }
        set { ApplicationState.SetValue("EditMapInitialPageLoad", value); }
    }

// REST OF CLASS NOT GERMAIN TO DISCUSSION AND OMITTED
}

您可以轻松地重构SessionHandler类来实现接口而不是静态的:

public SessionHandler: IApplicationState { //Implementation }

或者如果你需要保持与其他代码区域的向后兼容性,你可以创建一个包装类,并让SessionHandler保持静态:

public SessionHandlerWrapper: IApplicationState
{
    //Call SessionHandler from within this class
}

现在确实你必须手动创建IApplicationState的具体实例并将其传递给EditMapUtilities,但现在这两个类都不依赖于另一个。实际上,如果您希望以后将其存储在数据库中,则只需编写一个实现IApplicationState的新类。只有调用代码才能更改为使用新的数据库类而不是基于会话的数据库。

现在,您可以享受新的loosley耦合架构以及为添加新功能而必须进行的最小化更改。

答案 1 :(得分:0)

这没有错。不要担心耦合这么多 - 类必须像砖块一样协同工作。当他们的砖块紧密结合时,人们不担心。 Session和ASP.Net像砖头一样齐头并进。换句话说,要编写Web应用程序,必须向HTTP添加有状态。

我想说在这种情况下你可能不需要使用会话。如果客户端可以更改并为更敏感的数据(实体ID,基于角色的变量)保留会话,我倾向于将ViewState用于我不关心的值