首页 > 解决方案 > .NET Core 3.1 复杂会话包装器不起作用

问题描述

我正在尝试在 .NET Core 3.1 中创建一个复杂的会话包装器。我遇到了一个问题,我的变量没有被设置。这是我设置会话包装类的方式。

public class SessionWrapper : ISessionWrapper
{
    private static IHttpContextAccessor context;
    public SessionWrapper(IHttpContextAccessor _context)
    {
        context = _context;
    }
    public static Course Course
    {
        get
        {

            var key = context.HttpContext.Session.GetString("course");
            if (key == null)
            {
                return default;
            }
            else
            {
                return JsonConvert.DeserializeObject<Course>(key);
            }
        }
        set
        {
            if(value != null)
            {
                context.HttpContext.Session.SetString("course", JsonConvert.SerializeObject(value));
            }
        }
    }
}

我将我的服务配置为使用会话和会话包装器。

 services.AddDistributedMemoryCache();
 services.AddSession();

 services.AddHttpContextAccessor();
 services.AddScoped<ISessionWrapper, SessionWrapper>();

我将管道配置为使用会话

app.UseSession(); 

在我的控制器中,我正在初始化课程并设置会话包装器。然后,我将课程 ID 设置为 4。它没有抱怨,但没有设置课程 ID。它始终为空。我一直在寻找它并且感到沮丧。我在这里想念什么?

  Course myCourse = new Course();
  SessionWrapper.Course = myCourse;
  SessionWrapper.Course.Id = "4"

标签: asp.net-core.net-coresession-variablessession-state

解决方案


我觉得你的包装器本身并不是最好的方法。一个具有自我意识的 Course 子类具有“知道如何”将自己存储在 Session 中,对我来说似乎更合乎逻辑。这样,您就可以将控制器从管理持久性的责任中解放出来。

public abstract class Course
{
   public abstract int Id { get; set; }
}

public class SessionCourse : Course
{
    private int _id;
    public override int Id 
    { 
        get => _id; 
        set { _id = value; UpdateSession(); }
    }

    // The GetCourse method is a factory for creating the SessionCourse objects 
    // and providing it with a ISession object so they can store themselves.

    public static Course GetCourse(IServiceProvider services)
    {
        ISession session = services.GetRequiredService<IHttpContextAccessor>()?.HttpContext.Session;
        SessionCourse course = session?.GetJson<SessionCourse>("Course") ?? new SessionCourse();
        course.Session = session;
        return course;
    }

    [JsonIgnore]
    private ISession Session { get; set; }

    private void UpdateSession() {
        Session.SetJson("Course", this);
    }
}

现在的诀窍是使用 SessionCourse 对象来满足对 Course 对象的请求,该对象将自身存储在会话中。您可以通过为课程对象添加一个带有 lambda 表达式的范围服务来做到这一点。结果是对课程服务的请求将返回 SessionCourse 对象。

services.AddScoped<Course>(sp => SessionCourse.GetCourse(sp));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

所以创建这种服务的好处是它允许你简化使用 Course 对象的控制器。

public class CourseController : Controller 
{
    private Course course;

    public CartController(Course courseService) 
    {
        course = courseService;
    }

    public void SetCourseId()
    {
        course.Id = "4";
    }

SessionExtension.cs 定义了将对象添加到会话的扩展方法。

public static class SessionExtensions {

    public static void SetJson(this ISession session, string key, object value) {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T GetJson<T>(this ISession session, string key) {
        var sessionData = session.GetString(key);
        return sessionData == null ? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
    }
}

推荐阅读