Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a session start equivalent in .Net Core MVC 2.1?

In MVC 5 you could assign a value to session in global.asx when the session started. Is there a way you can do this in .Net Core MVC? I have session configured but in the middleware it seems to get called on every request.

like image 924
doogdeb Avatar asked Sep 27 '18 09:09

doogdeb


People also ask

Is session available in MVC?

By default, Asp.Net MVC support session state. Session is used to store data values across requests. Whether you store some data values with in the session or not Asp.Net MVC must manage the session state for all the controllers in your application that is time consuming.

What can I use instead of session in ASP.NET MVC?

Use 'Local Storage 'or 'Session Storage'. 2.) Append data with the querystring. Local storage is client side alternative to session.

Are sessions enabled by default in ASP.NET Core?

By default, Session State is disabled in ASP.Net Core applications i.e. ASP.Net Core MVC and ASP.Net Core Razor Pages. This article will cover the steps to enable Session Sate in ASP.Net Core applications. Session can be enabled using the Configure method.


2 Answers

nercan's solution will work, but I think I found a solution that requires less code and may have other advantages.

First, wrap DistributedSessionStore like this:

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Session;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

public interface IStartSession
{
    void StartSession(ISession session);
}

public class DistributedSessionStoreWithStart : ISessionStore
{
    DistributedSessionStore innerStore;
    IStartSession startSession;
    public DistributedSessionStoreWithStart(IDistributedCache cache, 
        ILoggerFactory loggerFactory, IStartSession startSession)
    {
        innerStore = new DistributedSessionStore(cache, loggerFactory);
        this.startSession = startSession;
    }

    public ISession Create(string sessionKey, TimeSpan idleTimeout, 
        TimeSpan ioTimeout, Func<bool> tryEstablishSession, 
        bool isNewSessionKey)
    {
        ISession session = innerStore.Create(sessionKey, idleTimeout, ioTimeout,
             tryEstablishSession, isNewSessionKey);
        if (isNewSessionKey)
        {
            startSession.StartSession(session);
        }
        return session;
    }
}

Then register this new class in Startup.cs:

class InitSession : IStartSession
{
    public void StartSession(ISession session)
    {
        session.SetString("Hello", "World");
    }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSingleton<IStartSession, InitSession>();
        services.AddSingleton<ISessionStore, DistributedSessionStoreWithStart>();
        services.AddSession();
        ...
    }

Full code is here: https://github.com/SurferJeffAtGoogle/scratch/tree/master/StartSession/MVC

like image 193
Jeffrey Rennie Avatar answered Nov 15 '22 08:11

Jeffrey Rennie


I use it in a live project. It works correctly. if you want to keep it when the application stops. You should use DistributedCache. For example, I'm using DistributedRedisCache.

Add to startup this code;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromMinutes(60);
            options.Cookie.HttpOnly = true;
        });
        // for redis distributed cache

        //services.AddDistributedRedisCache(options =>
        //    {
        //   options.InstanceName = $"{Configuration["DistributedRedisCacheInstance"]}";
        //   options.Configuration = $"{Configuration["DistributedRedisCacheHost"]}";
        //  });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IHttpContextAccessor acc)
    {
        app.UseSession();
    }

And add new session extension;

using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System.Text;

namespace SampleApp
{
    public static class SessionExtensions
    {
        public static void SetObjectAsJson<T>(this ISession session, string key, T value)
        {
            session.Set(key, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
        }

        public static T GetObjectFromJson<T>(this ISession session, string key)
        {
            session.TryGetValue(key, out byte[] dataByte);
            string data = dataByte != null ? Encoding.UTF8.GetString(dataByte) : null;

            return data == null ? default(T) : JsonConvert.DeserializeObject<T>(data);
        }
    }
}

And use get or set same this;

var sessionItem = httpContext.Session.GetObjectFromJson<string>("sessionItem");
//or
ContextProviderExtension.HttpContextAccessor.HttpContext.Session.SetObjectAsJson("sessionItem", sessionItem);

you need this extension;

using Microsoft.AspNetCore.Http;
using System;
    
namespace SampleApp
{
    public static class ContextProviderExtension
    {
        static IHttpContextAccessor httpContextAccessor = null;
        public static IHttpContextAccessor HttpContextAccessor
        {
            get { return httpContextAccessor; }
            set
            {
                if (httpContextAccessor != null)
                {
                    throw new Exception("");
                }
                httpContextAccessor = value;
            }
        }
    }
}

I suppose it will work.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;


namespace SampleApp
{
    public class SessionMiddleware
    {
        private readonly RequestDelegate _next;

        public SessionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            var sessionItem = httpContext.Session.GetObjectFromJson<string>("test");
            if (sessionItem == null)
                httpContext.Session.SetObjectAsJson<string>("test", httpContext.Session.Id);//httpContext.Session.Id or set a value
            await _next.Invoke(httpContext);
        }
    }

    public static class SessionMiddlewareExtensions
    {
        public static IApplicationBuilder UseSessionMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<SessionMiddleware>();
        }
    }
}

and add startup.cs Configure method after app.UseSession();

app.UseSessionMiddleware();
like image 31
nercan Avatar answered Nov 15 '22 07:11

nercan