无论用户注销/超时/浏览器关闭,执行某些会话清理逻辑的方法是什么?

时间:2014-04-29 18:13:13

标签: asp.net .net session

我有一个带有C#后端的IIS托管Web应用程序。

当用户登录时,我想为登录用户实例化HttpClient()的实例,以通过REST API与后端进行通信。一旦创建了该客户端,后端将初始化一些用户特定的内存,一旦用户注销就应该清除(即,HttpClient()对象被释放)。

这里做的正确的事情似乎是在登录时实例化HttpClient()对象,然后在用户手动注销或用户会话超时或者用户会话时调用一些代码用户关闭浏览器,该代码将手动处理HttpClient()

这肯定是一个行之有效的问题,因此必须有一个优雅的解决方案。如果出现任何可能的注销情况(手动/超时/浏览器关闭),如何处理此特定于用户的HttpClient()

3 个答案:

答案 0 :(得分:0)

您可以做的是创建一个执行您想要执行的特定于用户的内存函数的类。该类将包含一个实例化HttpClient()对象然后执行特定于用户的操作(函数)的方法。该类还包含另一个清除用户特定内存函数的方法,即它处理HttpClient()对象并执行任何特定于用户的数据的清理。

所以,基本上,你的代码看起来像这样:

public class HttpHelper
{

    public void LoadUserInformation()
    {
       HttpClient httpClientObj = new HttpClient();
       //perform user-specific tasks
       //your logic here

       //Store the httpClientObj object in session
    }

    public void DisposeUserInformation()
    {
       //Fetch the httpClientObj from session
       //perform user-specific tasks
       //your logic here
       httpClient.Dispose();
    }
}

现在,在任一场景中,无论会话超时还是用户注销,您都可以调用DisposeUserInformation()方法,这将处理您的场景,即会话超时或用户注销。

global.asax中有一个Session_End()方法。在会话结束时,将连接global.asax文件以调用此方法。你可以在那里调用DisposeUserInformation()方法。

您也可以在控制器中单击注销按钮时调用此方法。

希望这有帮助!!!

答案 1 :(得分:0)

处理Web用户的离开并非易事,因为HTTP协议是无状态的。如果用户仍在那里,服务器永远无法确定;一个关闭的HTTP连接并不意味着用户必须离开,并且服务器可以认为连接仍然是打开的,尽管用户不再存在。

除非你强烈地使用HttpClient对象,否则你希望保持它存活会节省大量资源,你应该在每个REST请求结束时将其丢弃,并打开一个新的对于下一个请求。

Web请求通常需要很短的时间来处理,并且在请求消失时释放用于它的大多数资源。这使得大多数对象都很短暂,而那些是垃圾收集器最有效处理的对象。在几个请求中保持对象会使它们长寿,这会占用服务器上的内存,并使垃圾收集器更加困难。除非有特定的理由要坚持一个对象,否则你不应该让它比处理请求所花的时间更长。

答案 2 :(得分:0)

我真的不建议在会话中存储任何内容IDisposable。如果在从Web APi下载的过程中,在另一个窗口中用户单击 Logout ,则在您使用HttpClient时将其丢弃。这是一个小的边缘情况,但是会有很多边缘情况在会话中存储IDisposable。此外,如果您需要扩展到多个服务器,那么需要将Session存储在进程以外的其他内容中,这需要对象可序列化(HttpClient不是)。

相反:

[serializable]
public sealed class ApiClient
{
  public ApiClient(uri baseAddress)
  {
    this._BaseAddress = baseAddress;
  }

  public Uri BaseAddress { get; set; }

  public IEnumerable<Person> GetPersons()
  {
    var address = new Uri(this.BaseAddress, "Employees/Persons");

    using (var client = new HttpClient())
    {
      // something like this
      var task = GetStringAsync(address);
      await task;
      var json = task.Result;
    }
  }
}

好的会话包装器:

public static class SessionExtensions
{
public static bool TryGetValue<T>(this HttpSessionStateBase session, out T value)
      where T : class
{
    var name = typeof(T).FullName;

    value = session[name] as T;

    var result = value != null;

    return result;
}

public static void SetValue<T>(this HttpSessionStateBase session, T value)
{
    var name = typeof(T).FullName;

    session[name] = value;
}

public static void RemoveValue<T>(this HttpSessionStateBase session)
{
    var name = typeof(T).FullName;

    session[name] = null;
}

public static bool ValueExists(this HttpSessionStateBase session, Type objectType)
{
    var name = objectType.FullName;

    var result = session[name] != null;

    return result;
}
}

现在您可以为每个客户端创建api:

Session.SetValue(new ApiClient(new Uri("http://localhost:443")));

在其他地方你可以得到人:

ApiClient client;

if (Session.TryGetValue(out client))
{
  client.GetPersons();
}