【问题标题】:Setting user-specific culture in a ServiceStack + MVC web application在 ServiceStack + MVC Web 应用程序中设置用户特定的文化
【发布时间】:2014-06-10 17:56:11
【问题描述】:

我需要为发送到使用ServiceStack 3MVC 4 编写的Web 应用程序的每个Web 请求设置用户特定的文化。

每个用户的文化都存储在数据库中的个人资料中,我使用派生自CredentialsAuthProvider 的自定义身份验证提供程序将其检索到我自己的IAuthSession 实现中。所以我不关心浏览器的AcceptLanguage 标头,而是想在ServiceStack 从缓存中解析它之后立即将当前线程的文化设置为auth 会话的文化属性。这对于ServiceStack 服务和MVC 控制器(源自ServiceStackController)都必须发生。

完成上述任务的最佳方法是什么?

更新 1

我已经找到了一种方法来做到这一点,尽管我不相信这是最佳解决方案。

在派生所有服务的基础服务类中,我覆盖了SessionAs<> 属性,如下所示:

protected override TUserSession SessionAs<TUserSession>()
{
    var genericUserSession = base.SessionAs<TUserSession>();

    var userAuthSession = genericUserSession as UserAuthSession;
    if (userAuthSession != null && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
        System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);

    return genericUserSession;
}

UserAuthSession 是我对 ServiceStack 的IAuthSession 的自定义实现。其LanguageCode 属性在登录时设置为存储在数据库中用户配置文件中的用户选择的 ISO 文化代码。

同样,在我的所有控制器派生自的基本控制器类中,我像这样覆盖了AuthSession 属性:

public override IAuthSession AuthSession
{
    get
    {
        var userAuthSession = base.AuthSession as UserAuthSession;
        if (userAuthSession != null && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);
        return userAuthSession;
    }
}

这似乎工作正常,因为这两个属性在调用服务或执行控制器操作时始终如一地使用,因此在执行任何下游逻辑之前设置当前线程的文化。

如果有人能想到更好的方法,请告诉我。

更新 2

根据 Scott 的建议,我创建了一个自定义 AuthenticateAndSetCultureAttribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class AuthenticateAndSetCultureAttribute : AuthenticateAttribute
{
    public AuthenticateAndSetCultureAttribute() : base() { }
    public AuthenticateAndSetCultureAttribute(ApplyTo applyTo) : base(applyTo) { }
    public AuthenticateAndSetCultureAttribute(string provider) : base(provider) { }
    public AuthenticateAndSetCultureAttribute(ApplyTo applyTo, string provider) : base(applyTo, provider) { }

    public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
    {
        base.Execute(req, res, requestDto);

        var session = req.GetSession() as UserAuthSession;
        if (session != null && session.IsAuthenticated && !String.IsNullOrWhiteSpace(session.LanguageCode))
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(session.LanguageCode);
    }
}

因为我只在用户通过身份验证时更改文化,所以(无论如何在我看来)在我们检查身份验证的同一个地方进行更改是有意义的。

然后我用这个属性而不是原来的 [Authenticate] 来装饰我所有的 SS 服务和 MVC 控制器。

现在,当调用 SS 服务时,会执行属性的 Execute 方法,并正确设置文化。但是,当调用 MVC 控制器操作时,Execute 永远不会被执行,这真的很令人费解,因为 MVC+SS 怎么知道将未经身份验证的请求重定向到登录页面。

有什么想法吗?

【问题讨论】:

    标签: asp.net-mvc-4 authentication servicestack servicestack-bsd


    【解决方案1】:

    我会使用RequestFilter 而不是覆盖SessionAs&lt;T&gt; 来做到这一点。在你的AppHostConfigure 方法中:

    public override void Configure(Container container)
    {
        RequestFilters.Add((httpReq, httpResp, requestDto) => {
            var session = httpReq.GetSession() as UserAuthSession;
            if(session == null || !session.IsAuthenticated || String.IsNullOrWhiteSpace(session.LanguageCode))
                return;
    
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(session.LanguageCode);
        });
    }
    

    【讨论】:

    • 感谢您的建议!我更进一步,创建了一个自定义身份验证属性(请参阅上面的第二次更新)。它适用于 SS 服务,但 MVC 控制器仍然存在问题。
    【解决方案2】:

    我最终创建了一个自定义 MVC 操作过滤器,该过滤器根据经过身份验证的用户设置设置请求线程的文化:

    public class SetUserCultureAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
    
            var baseController = filterContext.Controller as BaseController;
            if (baseController == null) return;
    
            var userAuthSession = baseController.UserAuthSession;
            if (userAuthSession != null && userAuthSession.IsAuthenticated && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
                System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);
        }
    }
    

    然后我用这个属性装饰了我的BaseController 类,并用ServiceStack 的常规Authorize 属性保护了我的控制器/操作。

    之前创建的 AuthenticateAndSetCultureAttribute 我最初打算用于控制器和服务,现在仅用于 SS 服务。

    MVC 和 SS 方面的文化设置正确,所以我很高兴!

    【讨论】:

      猜你喜欢
      • 2015-06-12
      • 2010-12-06
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-10
      • 1970-01-01
      相关资源
      最近更新 更多