3

MVC3 添加了一个使用[SessionState(SessionStateBehavior.Disabled)]属性制作无会话控制器的好机会。这很好但不灵活,因为您不能为每个控制器方法设置会话状态,也不能按条件启用它。

是否可以仅为经过身份验证的用户或通过其他一些自定义条件启用会话状态?即 PHP 有一个很棒的特性。 if (!isset($_SESSION)) session_start(); 能找到类似的东西就好了

4

2 回答 2

4

您可以覆盖默认控制器工厂,更具体地说是GetControllerSessionBehavior方法:

public class MyControllerFactory : DefaultControllerFactory
{
    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return SessionStateBehavior.Default;
        }

        if (requestContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // enable session if there's an authenticated user
            return SessionStateBehavior.Required;
        }

        return SessionStateBehavior.Disabled;
    }
}

Application_Start用自定义控制器工厂替换默认控制器工厂:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
于 2012-05-28T08:43:39.280 回答
2

如何禁用每个控制器方法的会话状态。即使对于这样的流程,它也能正常工作:

  1. 启用会话的请求方法
  2. 禁用会话的请求方法
  3. 启用会话的请求方法 - 保留值(我不明白为什么,但确实如此)

      /// <summary>
      /// Enable session if there's an authenticated user or method in controller is marked with <see cref="SessionAttribute" /> or controller class is marked within <see cref="SessionAttribute" /> or <see cref="SessionStateAttribute" />
      /// </summary>
      public class AuthSessionControllerFactory : DefaultControllerFactory
      {
    
        protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
        {
          if ( controllerType == null ) return SessionStateBehavior.Default;
    
          return requestContext.HttpContext.User.Identity.IsAuthenticated
            ? SessionStateBehavior.Required
            : GetDefaultSessionBehavior( requestContext, controllerType );
        }
    
     private static readonly ConcurrentDictionary<string, SessionStateBehavior> _sessionStateCache = new ConcurrentDictionary<string, SessionStateBehavior>();
     protected SessionStateBehavior GetDefaultSessionBehavior(RequestContext requestContext, Type controllerType)
     {
      if ( !requestContext.RouteData.Values.Keys.Contains( "action" ) ) return SessionStateBehavior.Required;
      var act = requestContext.RouteData.Values["action"].ToString();
    
      return _sessionStateCache.GetOrAdd( controllerType + act,
        (type => {
          var typeCopy = controllerType;
    
          //get current action
          var methods = typeCopy.GetMethods().Where( m => m.Name == act ).ToArray();
          foreach (var method in methods) {
    
            //look for SessionAttribute on the method
            var attr = Attribute.GetCustomAttribute( method, typeof( SessionAttribute ), false );
            if ( attr != null ) return (( SessionAttribute )attr).Behavior;
    
    
            //support default SessionState behavior
            var controllerattr = typeCopy.GetCustomAttributes( typeof( SessionStateAttribute ), true )
              .OfType<SessionStateAttribute>().FirstOrDefault();
            if ( controllerattr == null ) 
            {
              var controllerattrCustom = typeCopy.GetCustomAttributes( typeof( SessionAttribute ), true )
                .OfType<SessionAttribute>().FirstOrDefault();
              if ( controllerattrCustom != null ) return controllerattrCustom.Behavior;
            } else
              return controllerattr.Behavior;
          }
          return SessionStateBehavior.Disabled;
    
        }) );
    }
    

    }

Application_Start()在 Global.asax的方法中注册它

ControllerBuilder.Current.SetControllerFactory( new AuthUserSessionControllerFactory() );  

这是一个 SessionAttribute 类 - 它看起来像 MS 的 SessionStateAttribute - 唯一的区别是方法允许使用这个

[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true )]
  public sealed class SessionAttribute : Attribute
  {

    public SessionAttribute(SessionStateBehavior behavior)
    {
      Behavior = behavior;
    }

    public SessionStateBehavior Behavior { get; private set; }
  }
于 2012-05-28T11:42:58.190 回答