How to use a session outside the controller

I have a Signalr Hub called NotificationHub that handles sending a new notification to connected clients. The NotificationHub class uses the NotificationManager class to retrieve notification data. Now I want to be able to use the session to store the last call to the new notification, but when using HttpContext.Current.Session ["lastRun"] in the NotificationManager, I get a NullReferenceException. To clarify, here are some of the codes for both classes:

NotificationHub

[HubName("notification")]
    public class NotificationHub : Hub
    {
        private NotificationManager _manager;
        private ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public NotificationManager Manager
        {
            get { return _manager; }
            set { _manager = value; }
        }

        public NotificationHub()
        {
            _manager = NotificationManager.GetInstance(PushLatestNotifications);
        }

        public void PushLatestNotifications(ActivityStream stream)
        {
            logger.Info($"Adding {stream.TotalItems} notifications ");
            Clients.Caller.addLatestNotifications(stream);
        }
//.....
}

NotificationManager

 public class NotificationManager
        {
            private static NotificationManager _manager;
            private DateTime _lastRun;
            private DbUpdateNotifier _updateNotifier;
            private readonly INotificationService _notificationService;
            private readonly Action<ActivityStream> _dispatcher;
            private long _userId;
            private IUnitOfWork unitOfWork;
            public NotificationService NotificationService => (NotificationService)_notificationService;
            public DbUpdateNotifier UpdateNotifier
            {
                get { return _updateNotifier; }
                set { _updateNotifier = value; }
            }

            public static NotificationManager GetInstance(Action<ActivityStream> dispatcher)
            {
                return _manager ?? new NotificationManager(dispatcher);
            }



            private NotificationManager(Action<ActivityStream> dispatcher)
            {
                _userId = HttpContext.Current.User.Identity.CurrentUserId();
                _updateNotifier = new DbUpdateNotifier(_userId);
                _updateNotifier.NewNotification += NewNotificationHandler;
                unitOfWork = new UnitOfWork();
                _notificationService = new NotificationService(_userId, unitOfWork);
                _dispatcher = dispatcher;

            }



         private void NewNotificationHandler(object sender, SqlNotificationEventArgs evt)
                {

                  //Want to store lastRun variable in a session here
                    var notificationList = _notificationService.GetLatestNotifications();
                    _dispatcher(BuilActivityStream(notificationList));
                }
           //....
}

I want to save the lastRun value for the session so that I can receive the next arrival of a new notification. How can i achieve this?

Edit:

, , , - , (-) . , lastRun, lastRun DateTime.Now. : , () , . , , .

+4
4

, DI, @Babak.

- .

Autofac, IoC .

  • (NotificationUpdateService NotificationUpdateDataProvider).

NotificationUpdateService - , . NotificationUpdateDataProvider - . .

public interface INotificationUpdateDataProvider
{
    string UserId { get;  }
    DateTime LastUpdate { get; set; }
}

public interface INotificationUpdateService
{
    DateTime GetLastUpdate();

    void SetLastUpdate(DateTime timesptamp);
}
  1. . - , HttpContext. userId - .

- Dictionary - UserId DateTime .

public class NotificationUpdateDataProvider : INotificationUpdateDataProvider
{
    private readonly Dictionary<string, DateTime> _lastUpdateCollection;
    private readonly string _userId;
    private Cache _cache;

    public NotificationUpdateDataProvider()
    {
        _cache = HttpRuntime.Cache;
        //Qaru - get the User from the HubCallerContext object
        //http://stackoverflow.com/questions/12130590/signalr-getting-username
        _userId = Context.User.Identity.GetUserId();
        _lastUpdateCollection =(Dictionary<string,DateTime>) _cache["LastUpdateCollection"];

        //If null - create it and stuff it in cache
        if (_lastUpdateCollection == null)
        {
            _lastUpdateCollection = new Dictionary<string, DateTime>();
            _cache["LastUpdateCollection"] = _lastUpdateCollection;
        }
    }

    public DateTime LastUpdate
    {
        get { return _lastUpdateCollection[_userId]; }

        set
        {
            //add to existing or insert new
            if (_lastUpdateCollection.ContainsKey(_userId))
            {
                _lastUpdateCollection[_userId] = value;
            }
            else
            {
                _lastUpdateCollection.Add(_userId, value);
            }    

        }
    }

    public string UserId => _userId;
}



public class NotificationUpdateService : INotificationUpdateService
{
    private readonly INotificationUpdateDataProvider _provider;

    public NotificationUpdateService(INotificationUpdateDataProvider provider)
    {
        _provider = provider;
    }

    public DateTime GetLastUpdate()
    {
        return _provider.LastUpdate;
    }

    public void SetLastUpdate(DateTime timestamp)
    {
        _provider.LastUpdate = timestamp;
    }
}
  1. Autofac:

    public static void RegisterComponents()
    {
        var builder = new ContainerBuilder();
    
        //First register the NotificationDataProvider
        builder.RegisterType<NotificationUpdateDataProvider>()
            .As<INotificationUpdateDataProvider>();
    
        //Register the update service
        builder.RegisterType<NotificationUpdateService>()
            .As<INotificationUpdateService>();
    
        var container = builder.Build();
    
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    
    }
    
  2. Global.asax

        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        //I am partial Autofac - but unity, Ninject, etc - the concept is the same
        AutofacConfig.RegisterComponents();
    
  3. , , Autofac .

    public class NotificationManager
    {
            private static NotificationManager _manager;
            private DateTime _lastRun;
            private DbUpdateNotifier _updateNotifier;
            private readonly INotificationService _notificationService;
            private readonly Action<ActivityStream> _dispatcher;
            private long _userId;
            private IUnitOfWork unitOfWork;
            public NotificationService NotificationService => (NotificationService)_notificationService;
            private readonly INotificationUpdateService _updateService;                                         
            public DbUpdateNotifier UpdateNotifier
            {
                get { return _updateNotifier; }
                set { _updateNotifier = value; }
            }
    
            public static NotificationManager GetInstance(Action<ActivityStream> dispatcher)
            {
                return _manager ?? new NotificationManager(dispatcher);
            }
    
    
            //You'll need to make the constructor accessible for autofac to resolve your dependency
            public NotificationManager(Action<ActivityStream> dispatcher,  INotificationUpdateService updateService)
            {
                _userId = HttpContext.Current.User.Identity.CurrentUserId();
                _updateNotifier = new DbUpdateNotifier(_userId);
                _updateNotifier.NewNotification += NewNotificationHandler;
                unitOfWork = new UnitOfWork();
                _notificationService = new NotificationService(_userId, unitOfWork);
                _dispatcher = dispatcher;
                _updateService = updateService;
            }
    
    
    
            private void NewNotificationHandler(object sender, SqlNotificationEventArgs evt)
            {
    
                //Want to store lastRun variable in a session here
    
                //just put the datetime in through the service
                _updateService.SetLastUpdate(DateTime.Now);
    
                var notificationList = _notificationService.GetLatestNotifications();
                _dispatcher(BuilActivityStream(notificationList));
            }
    
    
    }
    
  4. , :

            //This is not the preferred way  - but it does the job
            public NotificationManager(Action<ActivityStream> dispatcher)
            {
                _userId = HttpContext.Current.User.Identity.CurrentUserId();
                _updateNotifier = new DbUpdateNotifier(_userId);
                _updateNotifier.NewNotification += NewNotificationHandler;
                unitOfWork = new UnitOfWork();
                _notificationService = new NotificationService(_userId, unitOfWork);
                _dispatcher = dispatcher;
                _updateService = DependencyResolver.Current.GetService<INotificationUpdateService>(); //versus having autofac resolve in the constructor
            }
    
  5. - :

       private void NewNotificationHandler(object sender, SqlNotificationEventArgs evt)
            {
    
                //Want to store lastRun variable in a session here
    
                //just put the datetime in through the service
                _updateService.SetLastUpdate(DateTime.Now);
    
                var notificationList = _notificationService.GetLatestNotifications();
                _dispatcher(BuilActivityStream(notificationList));
            }
    

- , . , .

+3

@Ryios, HttpContext.Current.Session. , HttpContext.Current null, HTTP; , . .

HttpContext.Current.Session - System.Web.SessionState.HttpSessionState, NotificationManager, HttpSessionState, HttpContext.Current.Session .

, NotificationManager.GetInstance

    public NotificationHub()
    {
        _manager = NotificationManager.GetInstance(PushLatestNotifications, HttpContext.Current.Session);
    }
0

Per :

Session SignalR (. SignalR ). , .

, SessionState ASP.NET , . ( ( , ), EnableSessionstate , , ), . . , SignalR . : HTTPContext.Current.Session.

, , .

0
source

You can follow the solution below, it works well for me -

HUB code for notification -

public class NotificationsHub : Hub
{
    public void NotifyAllClients(string s_Not, DateTime d_LastRun)
    {
       IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationsHub>();
       context.Clients.All.displayNotification(s_Not, d_LastRun);
    }
}

You can provide the variables in the HUB notification using below (for example, you can change according to your needs) -

NotificationsHub nHub = new NotificationsHub();
nHub.NotifyAllClients("Test Notification", Now.Date);

Now, if you want to save the last runtime in a session variable, you can do it with Javascript -

<script type="text/javascript">            
        $(function () {
            var notify = $.connection.notificationsHub;

            notify.client.displayNotification = function (s_Not, d_LastRun) {
                "<%=System.Web.HttpContext.Current.Session("lastRun")="' + d_LastRun + '"%>";                    
            };

            $.connection.hub.start();

        });

    </script> 

Hope this helps.

0
source

All Articles