สำหรับ ASPNET MVC เราทำสิ่งต่อไปนี้:
- ตามค่าเริ่มต้นให้ตั้งค่า
SessionStateBehavior.ReadOnly
การดำเนินการของคอนโทรลเลอร์ทั้งหมดโดยลบล้างDefaultControllerFactory
- ในการดำเนินการของตัวควบคุมที่จำเป็นต้องมีการเขียนไปยังสถานะเซสชันทำเครื่องหมายด้วยแอตทริบิวต์เพื่อตั้งค่า
SessionStateBehavior.Required
สร้าง ControllerFactory GetControllerSessionBehavior
ที่กำหนดเองและแทนที่
protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
{
var DefaultSessionStateBehaviour = SessionStateBehaviour.ReadOnly;
if (controllerType == null)
return DefaultSessionStateBehaviour;
var isRequireSessionWrite =
controllerType.GetCustomAttributes<AcquireSessionLock>(inherit: true).FirstOrDefault() != null;
if (isRequireSessionWrite)
return SessionStateBehavior.Required;
var actionName = requestContext.RouteData.Values["action"].ToString();
MethodInfo actionMethodInfo;
try
{
actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
catch (AmbiguousMatchException)
{
var httpRequestTypeAttr = GetHttpRequestTypeAttr(requestContext.HttpContext.Request.HttpMethod);
actionMethodInfo =
controllerType.GetMethods().FirstOrDefault(
mi => mi.Name.Equals(actionName, StringComparison.CurrentCultureIgnoreCase) && mi.GetCustomAttributes(httpRequestTypeAttr, false).Length > 0);
}
if (actionMethodInfo == null)
return DefaultSessionStateBehaviour;
isRequireSessionWrite = actionMethodInfo.GetCustomAttributes<AcquireSessionLock>(inherit: false).FirstOrDefault() != null;
return isRequireSessionWrite ? SessionStateBehavior.Required : DefaultSessionStateBehaviour;
}
private static Type GetHttpRequestTypeAttr(string httpMethod)
{
switch (httpMethod)
{
case "GET":
return typeof(HttpGetAttribute);
case "POST":
return typeof(HttpPostAttribute);
case "PUT":
return typeof(HttpPutAttribute);
case "DELETE":
return typeof(HttpDeleteAttribute);
case "HEAD":
return typeof(HttpHeadAttribute);
case "PATCH":
return typeof(HttpPatchAttribute);
case "OPTIONS":
return typeof(HttpOptionsAttribute);
}
throw new NotSupportedException("unable to determine http method");
}
AcquireSessionLockAttribute
[AttributeUsage(AttributeTargets.Method)]
public sealed class AcquireSessionLock : Attribute
{ }
เชื่อมต่อโรงงานควบคุมที่สร้างขึ้นมา global.asax.cs
ControllerBuilder.Current.SetControllerFactory(typeof(DefaultReadOnlySessionStateControllerFactory));
ตอนนี้เราสามารถมีทั้งread-only
และภาครัฐในครั้งเดียวread-write
Controller
public class TestController : Controller
{
[AcquireSessionLock]
public ActionResult WriteSession()
{
var timeNow = DateTimeOffset.UtcNow.ToString();
Session["key"] = timeNow;
return Json(timeNow, JsonRequestBehavior.AllowGet);
}
public ActionResult ReadSession()
{
var timeNow = Session["key"];
return Json(timeNow ?? "empty", JsonRequestBehavior.AllowGet);
}
}
หมายเหตุ: สถานะเซสชัน ASPNET ยังคงสามารถเขียนได้แม้ในโหมดอ่านอย่างเดียวและจะไม่ทิ้งข้อยกเว้นในรูปแบบใด ๆ (มันไม่ล็อคเพื่อรับประกันความมั่นคง) ดังนั้นเราจึงต้องระมัดระวังในการทำเครื่องหมาย AcquireSessionLock
ในการกระทำของตัวควบคุมที่ต้องเขียนสถานะเซสชัน