我是网络开发人员的新手。我正在使用asp.net/C#来建立一个网站。我目前有一个名为DataLayer
的类,我用它来执行我的所有数据库功能,还存储一些查询信息。我最初把这个类看成是静态的,因为这就是我希望它表现的方式,但后来意识到这对多个用户来说都是坏事。
我必须从这个类中创建一个实例才能使用它,但我需要在该用户的几个网页中维护相同的实例。关于如何采用这种方法的任何想法或想法?如何将此对象从一个页面传递到另一个页面?存储在会话变量中,以某种方式作为全局对象?我想这更像是一个讨论,因为有多个解决方案,我想听听更有经验的人的建议^^ pts所有有用的建议:D
答案 0 :(得分:2)
我在最近的项目中开始了这条道路。我在身份验证Cookie中使用自定义UserData
属性来存储有关用户的特殊信息。它工作得很好,很快,并且做了我需要的一切。不幸的是因为“PageSpeed”告诉我我的cookie太大了(2.2K),我选择使用DB调用和一些缓存甜蜜的缓存代替自定义UserData。
我已经附加了我使用的类(大部分是从另一个StackOverflow用户借来的)来在UserData字段中存储其他信息。
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);
}
}
}
然而正如@Greg Sansom在他的一篇评论中所说,保持你的应用程序无状态是未来可扩展性的一个非常好的奖励。如果您可以通过进行数据库调用和缓存数据(这是我选择做的)来做到,我认为您会对速度和结果感到满意。
然而,我使用ASP.NET MVC并尽可能避免任何类型的状态。
答案 1 :(得分:1)
你是对的 - 避免使用静态类是一个好主意。
以每个用户为基础实现保持对象的唯一框架实现方式是将其存储为会话变量。
那就是说,我应该指出以下最佳实践建议:
使用会话变量会损害应用程序的可伸缩性,就像保留一次性对象一样。
数据库可以处理的数据库连接数量有限制,因此如果您的站点使用率很高,如果您在请求之间保持这些连接打开,您将开始看到失败。
此外,会话变量在用户离开网站后占用内存一定时间。这是会话变量不可避免的副作用,并且意味着如果您在特定时间段内拥有大量用户,那么您的应用程序将使用比实际需要更多的RAM。您可以配置会话以使用数据库存储而不是内存,但这只会创建一组不同的问题(可能您仍需要保留数据库连接!)。
使用会话的另一个问题是,如果运行应用程序的服务器超过两个,则需要在数据库中维护会话状态,这将影响应用程序的性能。