views:

479

answers:

3

Hi,

I have a asp.net mvc web site where I make use of the Dependency Injections features of the "Micorosoft.Practices.Unity" and "Microsoft.Practices.ObjectBuilder2". This all works great by injected my objects into my controllers constructors.

The problem is that I am having difficulty in clearing this session when a user leaves the browser or wants to log off. All the values remain persisted in the objects. How can I destory the container which is created in the global.asax on either Session_End() or by a user click and taken care by a controller action.

Below is some sample code.

Global.asax - Performed from Session_start:

protected static void RegisterDependencies()
{
    IUnityContainer container = new UnityContainer();

    container.RegisterType<DataStore, DataStore>(new SessionLifetimeManager<DataStore>());
    container.RegisterType<IMotorRepository, MotorRepository>(new SessionLifetimeManager<IMotorRepository>());
    container.RegisterType<ICoverRepository, CoverRepository>(new SessionLifetimeManager<ICoverRepository>());
    container.RegisterType<IDriverRepository, DriverRepository>(new SessionLifetimeManager<IDriverRepository>());
    container.RegisterType<IVehicleRepository, VehicleRepository>(new SessionLifetimeManager<IVehicleRepository>());
    container.RegisterType<ICodeValueRepository, CodeValueRepository>(new SessionLifetimeManager<ICodeValueRepository>());

    ControllerBuilder.Current.SetControllerFactory(
        new UnityControllerFactory(container)
    );
}

SessionLifeTimeManager:

public class SessionLifetimeManager<T> : LifetimeManager, IDisposable
{
    public override object GetValue()
    {
        return HttpContext.Current.Session[typeof(T).AssemblyQualifiedName];
    }
    public override void RemoveValue()
    {
        HttpContext.Current.Session.Remove(typeof(T).AssemblyQualifiedName);
    }
    public override void SetValue(object newValue)
    {
        HttpContext.Current.Session[typeof(T).AssemblyQualifiedName] = newValue;
    }
    public void Dispose()
    {
        RemoveValue();
    }
}
A: 

Session_End is not fired until something like 30 minutes after the user leaves. I too have met the woes of session in ASP.NET.

If you call Session.Abandon you can force the firing of Session_end. But that doesn't fix your problem if the user leaves your site or closes their browser.

You could maybe use a javascript event and do a webservice call to end their session when they leave a page. This is similar logic to attempting to prevent users from leaving before saving work.

The problem with this? It will expire session EVERY page transition.

window.onbeforeunload = endSession;

function endSession() {
    //end session here through some kind of call back to the server
}

I have done a single page before, however, where some functions would cause a popup to deter the user from leaving, while others (like posting back) would not fire the event. What I ended up having to do is set a var on page load and then modify that var when certain controls or links are interacted with.

var endUserSession = true;

window.onbeforeunload = endSession;

function endSession() {
    if(endUserSession) {
        //end session here through some kind of call back to the server
    }
}

While this is a very invasive implementation and requires a lot of work and integration to implement site wide, it can work, although it will be time consuming to get your postback to not trigger the end session.

In my personal experience, it's best to just let session deal with itself and not worry about when it is or is not expiring. Too many weeks of my time have been spent trying to solve issues around session. IIS should handle it for you, and you can go into the worker process and change how frequently the WP is restarted (and session cleared).

If the problem here is related to available system resources: ie the site is just taking up a lot of memory and dumping session is not an option, you could implement the Sql Server State Server and then recycle the worker process all you want.

How to implement sql state server

Josh
A: 

这样定义LifetimeManager ,在配置文件web.config中如何实现根据配置使用不同的LifetimeManager?

A: 

The problem with this approach, which the first commenter alluded to is that you're both creating a container associated to the session AND setting the lifetimes of the objects associated to that container to session.

Really, you don't need to do both. Either register associate the container with the session OR set the lifetime of the object to session.

I prefer setting the lifetime of the object to session because it keeps my container creation cleaner. Simply move your container creation to the application level. When a user (i.e. a unique session) asks for an object of a type that's registered with the container and the lifetime of that object is session, it will look for that object in that user's session. If not found, it'll add it to the session. If found it will return it from the session. If another user comes along and requests an object of the same type, the same pattern will occur because the backing store of the object is unique for each user.

JayRu