开发者

How to manage back end data layer class instance throughout site

开发者 https://www.devze.com 2023-02-06 02:16 出处:网络
I\'m new to web dev. and I\'m using asp.net/C# to build a website. I currently have a class called DataLayer that I\'m using to perform all of my database functions, and also store some queried inform

I'm new to web dev. and I'm using asp.net/C# to build a website. I currently have a class called DataLayer that I'm using to perform all of my database functions, and also store some queried informatio开发者_如何学Pythonn. I initially had this class as static, because that's how I wanted it to behave, but then realized that will be all kinds of bad for multiple users.

I have to make an instance out of this class in order to use it, but I need to maintain the same instance throughout several webpages for that user. Any thoughts or ideas on how to go about this approach? How to pass this object from page to page? Store in session variable, as a global object somehow? I guess this more of a discussion since there are multiple solutions, I want to hear suggestions from more experienced people^^ pts for all helpful suggestions :D


I started down this path in my recent project. I was using the custom UserData attribute in the Authentication Cookie to store special info about the user. It worked really well, was fast, and did everything I needed. Unfortunately because "PageSpeed" told me my cookie was too big (2.2K), I opted to go with DB calls and a bit of caching sweet ass caching in lieu of the custom UserData.

I've attached the class I use (most of it was borrowed from another StackOverflow User) to store additional info in the UserData field.

using System.Web.Security;
using System.Web;
namespace Utilities.Helpers
{
    /// <summary>
    /// A helper class that aids us in dealing with the Auth Cookie.
    /// </summary>
    /// <remarks></remarks>
    public sealed class AuthenticationHelper
    {
        /// <summary>
        /// Prevents a default instance of the <see cref="AuthenticationHelper" /> class from being created.
        /// </summary>
        /// <remarks></remarks>
        private AuthenticationHelper()
        {
        }
        /// <summary>
        /// Generate an Authentication Cookie that also contains "UserData".
        /// The UserData is a serialized "AuthUserData" Object containing "ID"
        /// "RegionID" "Username" and "Slug"
        /// </summary>
        /// <param name="userName">this is the "claimedidentifier" of the user's OpenId</param>
        /// <param name="userData">be mindful of the cookie size or you will be chasing ghosts</param>
        /// <param name="persistent"></param>
        public static HttpCookie CreateAuthCookie(string userName, AuthUserData userData, bool persistent)
        {

            DateTime issued = DateTime.UtcNow;
            // formsAuth does not expose timeout!? have to get around the spoiled
            // parts and keep moving..
            HttpCookie fooCookie = FormsAuthentication.GetAuthCookie("foo", true);
            int formsTimeout = Convert.ToInt32((fooCookie.Expires - DateTime.UtcNow).TotalMinutes);

            DateTime expiration = DateTime.UtcNow.AddMinutes(formsTimeout);
            string cookiePath = FormsAuthentication.FormsCookiePath;

            string SerializedUser = SerializeUser(userData);

            object ticket = new FormsAuthenticationTicket(0, userName, issued, expiration, true, SerializedUser, cookiePath);
            return CreateAuthCookie(ticket, expiration, persistent);
        }

        /// <summary>
        /// Creates the auth cookie.
        /// </summary>
        /// <param name="ticket">The ticket.</param>
        /// <param name="expiration">The expiration.</param>
        /// <param name="persistent">if set to <c>true</c> [persistent].</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static HttpCookie CreateAuthCookie(FormsAuthenticationTicket ticket, DateTime expiration, bool persistent)
        {
            string creamyFilling = FormsAuthentication.Encrypt(ticket);
            object cookie = new HttpCookie(FormsAuthentication.FormsCookieName, creamyFilling) {
                Domain = FormsAuthentication.CookieDomain,
                Path = FormsAuthentication.FormsCookiePath
            };
            if (persistent) {
                cookie.Expires = expiration;
            }

            return cookie;
        }


        /// <summary>
        /// Retrieves the auth user.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public static AuthUserData RetrieveAuthUser()
        {
            string cookieName = FormsAuthentication.FormsCookieName;
            HttpCookie authCookie = HttpContext.Current.Request.Cookies(cookieName);
            FormsAuthenticationTicket authTicket = default(FormsAuthenticationTicket);
            string userdata = string.Empty;
            AuthUserData aum = new AuthUserData();  //AuthUserData is a custom serializable Poco that holds all the required user data for my cookie (userID, email address, whatever.

            if ((authCookie != null)) {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                userdata = authTicket.UserData;
            }


            if ((!object.ReferenceEquals(userdata, string.Empty))) {
                aum = DeserializeUser(userdata);
                if (string.IsNullOrEmpty(aum.Username)) {
                    aum.Username = "User" + aum.ID;
                }
            } else {
                aum.ID = null;
                aum.Region = null;
                aum.Username = string.Empty;
                aum.Reputation = 0;
            }

            return aum;
        }


        /// <summary>
        /// Serializes the user.
        /// </summary>
        /// <param name="aum">The AuthUserData.</param>
        /// <returns></returns>
        /// <remarks>The AuthUserData is a custom serializable poco that holds the data</remarks>
        private static string SerializeUser(AuthUserData aud)
        {
            Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            IO.MemoryStream mem = new IO.MemoryStream();
            bf.Serialize(mem, aud);
            return Convert.ToBase64String(mem.ToArray());
        }

        /// <summary>
        /// Deserializes the user.
        /// </summary>
        /// <param name="serializedaum">The serialized AuthUserData.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static AuthUserData DeserializeUser(string serializedaud)
        {
            Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            IO.MemoryStream mem = new IO.MemoryStream(Convert.FromBase64String(serializedaud));
            return (AuthUserData)bf.Deserialize(mem);
        }
    }
}

However as @Greg Sansom said in one of his comments, keeping your app stateless is a really good bonus to future scalability. If you can make due with making a database call, and caching the data (this is what I chose to do), I think you'll be happy with the speed and results.

I am however using ASP.NET MVC and avoiding any kind of State as much as humanly possible.


You are right - avoiding using a static class is a good idea.

The only framework implemented way to hold onto the object on a per-user user basis is to store it as a session variable.

That said, I should point out the following best practice recommendations:

  1. Don't use session variables.
  2. Don't keep database connections open (I assume this is what you are planning).

Using session variables damages the scalability of your application, as does holding onto disposable objects.

There is a limit to the number of database connections your database can handle, so if your site ever experiences high usage, you'll start to see failures if you are holding those connections open between requests.

Also, session variables occupy memory for a certain timespan after the user has finished left the website. This is an unavoidable side-effect of session variables, and means that if you have had a lot of users within a certain time period, your application will be using quit a lot more RAM than it really needs to. You can configure sessions to use database storage instead of memory, but this will just create a different set of issues (and presumably you still need to hold onto a database connection!).

Another problem with using sessions is that if you have more than two servers running the application, you need to maintain session state in the database, which will affect the performance of your app.

0

精彩评论

暂无评论...
验证码 换一张
取 消