ASP.NET MVC Session vs Global vs Cache

2019-03-09 05:20发布

I have an application that was written in vanilla ASP.NET that I would like to port over to ASP.NET MVC.

I, however, am confused about the right place to persist objects. I need to persist for a couple reasons:

  1. I would like all to have a single database connection, wrapped in a "repository" or "manager" style object.
  2. Each user has a user object that needs to be saved on a per-session basis.

Normally, I would say that #1 would be saved as a static item in the Globals.asax that can be hit using Global.Repository or similar.

And I would normally say that #2 should be a property with a session backing store somewhere in the base class of the pages.

Now the reason I am confused is that I have heard that sessions have changed in MVC, and the Global.asax no longer holds the same class. Also, the concept of pages has been removed, so adding a property to the base class of a controller seems... wrong.

What say yall?

4条回答
做自己的国王
2楼-- · 2019-03-09 05:55

Sessions haven't changed at all in MVC. The GlobalApplication class in Global.asax still exists, too. Pages exist, also, that you would want to refer to a repository in a controller rather than a page. Adding a property to a base controller class is fine; I do it all the time.

查看更多
贪生不怕死
3楼-- · 2019-03-09 05:56

Your database would go in a base class for your controllers. This base class should extend Controller, and all your controllers should extend the base class. Here's a little example:

public class BaseController : Controller
{
    private AuthServices _auth;
    private LogHelper _log;
    private Repository _repository;

    /// <summary>
    /// <see cref="AuthServices"/>
    /// </summary>
    protected AuthServices Authorization
    {
        get { return _auth ?? (_auth = new AuthServices()); }
    }

    /// <summary>
    /// <see cref="LogHelper"/>
    /// </summary>
    protected LogHelper Log
    {
        get { return _log ?? (_log = new LogHelper()); }
    }

    /// <summary>
    /// <see cref="Repository"/>
    /// </summary>
    protected Repository Repository
    {
        get { return _repository ?? (_repository = new Repository()); }
    }
}

Notice the lazy instantiation. That allows me to sneak in before running tests and set my private fields with mocks.

As for the session, your User object can still be saved in the session just as in a traditional ASP.NET application. Almost everything is still around (Response, Cache, Session, etc), but some of them have been wrapped with classes from System.Web.Abstractions so that they can be mocked for testing. They all still behave the same way, though you shouldn't use some of them in their traditional role (e.g., don't Response.Redirect, return an ActionResult such as RedirectToRouteResult that performs your redirection).

As for the reasoning behind your questions....

Don't stress on a single db connection. Depending on your implementation it may even be a bad idea, as requests may step on each other. Just open your connex, use it, and dispose/close it when done.

Also, one of the biggest changes that MVC brings is the rejection of the stateful model that traditional ASP.NET attempted to bring to web development. All that framework and viewstate doesn't exist anymore (pay no attention to the man behind the curtain). The less state you hold onto the less complex and more robust your web application is. Try it, you might like it.

查看更多
放我归山
4楼-- · 2019-03-09 05:56

If you use sessions I would recommend having a session class, so that you only need to specify the string name once in code and this will give you IntelliSence also.

 public static class SessionHandler
{   
    // User Values
    private static string _userID = "UserID";
    private static string _userRole = "UserRole";

    public static string UserID
    {
        get
        {
            if (HttpContext.Current.Session[SessionHandler._userID] == null)
            { return string.Empty; }
            else
            { return HttpContext.Current.Session[SessionHandler._userID].ToString(); }
        }
        set
        { HttpContext.Current.Session[SessionHandler._userID] = value; }

    }

    public static string UserRole
    {
        get
        {
            if (HttpContext.Current.Session[SessionHandler._userRole] == null)
            { return string.Empty; }
            else
            { return HttpContext.Current.Session[SessionHandler._userRole].ToString(); }
        }
        set
        { HttpContext.Current.Session[SessionHandler._userRole] = value; }

    }
}
查看更多
何必那么认真
5楼-- · 2019-03-09 05:59

You can create a model binder to encapsulate state.

(See Steve Sanderson's mvc book on his shopping cart implementation)

With the model binder, you have access to the controllerContext - which has the HttpContext.

查看更多
登录 后发表回答