如何在ServiceStack中正确本地化Razor Views

时间:2013-10-30 13:03:43

标签: razor servicestack globalization culture

我目前从Accept-Language-HTTP-Header获取首选文化,并将其存储在 AuthUserSession 中。

在AppHost.Configure:

PreRequestFilters.Add((httpReq, httpResp) =>
{
    var session = httpReq.GetSession();
    if (session is AuthUserSession)
    {
        var auths = ((AuthUserSession)session);
        if (auths.Culture == null)
        {
            //parse languages
            var languages = httpReq.Headers["Accept-Language"];
            //auths.Culture = Helpers.CultureHelper.GetBestAcceptLanguageMatch(languages);
            auths.Culture = "en-US";
            httpReq.SaveSession(session, new TimeSpan(0, 20, 0));
        }
    }
});

我目前在用户首选文化中渲染视图的解决方案是从Razor视图更改当前的Threads UICulture:

@inherits ViewPage<LandingPage.ServiceModel.Operations.AskQuestions>

@{
    var session = GetSession<ServiceStack.ServiceInterface.Auth.AuthUserSession>();
    var prevCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(session.Culture);
    //access a Resource
    ViewBag.Title = Resources.AskTitle;
}
Views Content
@{
    System.Threading.Thread.CurrentThread.CurrentUICulture = prevCulture;
}

这似乎不够优雅和笨拙。什么是更好的方法呢?

*编辑: 我正在寻找两个钩点:一个在View被调用之前,一个在它被渲染之后。这些应该保持对其他请求服务为零的干扰。

1 个答案:

答案 0 :(得分:3)

我今天发现自定义IServiceRunner只提供正确的挂钩(参见https://github.com/ServiceStack/ServiceStack/wiki/Customize-HTTP-Responses)。

如上所述,当页面由服务提供时,它才起作用,因为请求ContentPage时甚至没有触及RequestFilters和ServiceRunner。

可能有意义的是,RequestFilter是另一个挂钩点,在执行View之前调用。但对于ResponseFilter来说,情况也是如此。我试图在ResponseFilter中重置CurrentUICulture的一个小测试使我的页面未本地化。

AppHost

public override void Configure(Funq.Container container)
{
    //plugins
    Plugins.Add(new RazorFormat());
    Plugins.Add(new AuthFeature(() =>
        new AuthUserSession(),
        new IAuthProvider[] {
            new BasicAuthProvider()
        }));

    //request filters
    PreRequestFilters.Add((httpReq, httpResp) =>
    {
        var session = httpReq.GetSession();
        if (session is AuthUserSession)
        {
            var auths = ((AuthUserSession)session);
            if (auths.Culture == null)
            {
                var languages = httpReq.Headers["Accept-Language"];
                auths.Culture = Helpers.CultureHelper.GetBestAcceptLanguageMatch(languages);

                httpReq.SaveSession(session, new TimeSpan(0, 20, 0));
            }
            httpReq.SetItem("Culture", auths.Culture);
        }
    });

    //funq
    var userRep = new InMemoryAuthRepository();
    container.Register<IUserAuthRepository>(userRep);
    container.Register<ICacheClient>(c => new MemoryCacheClient());
}

//use a custom IServiceRunner
public override ServiceStack.ServiceHost.IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
    var runner = base.CreateServiceRunner<TRequest>(actionContext);
    return new CultureAwareServiceRunner<TRequest>(this, actionContext);
}

<强> CultureAwareServiceRunner.cs

public class CultureAwareServiceRunner<T> : ServiceRunner<T>
{

    public CultureAwareServiceRunner(AppHost appHost, ServiceStack.WebHost.Endpoints.ActionContext actionContext) : 
        base(appHost, actionContext)
    { }

    public override void OnBeforeExecute(IRequestContext requestContext, T request)
    {
        var httpReq = requestContext.Get<IHttpRequest>();
        httpReq.SetItem("PreviousCulture", Thread.CurrentThread.CurrentUICulture);
        string culture = httpReq.GetItem("Culture") as string;
        if (culture != null)
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
        base.OnBeforeExecute(requestContext, request);
    }

    public override object OnAfterExecute(IRequestContext requestContext, object response)
    {
        var httpReq = requestContext.Get<IHttpRequest>();
        var prevCulture = httpReq.GetItem("PreviousCultureCulture") as CultureInfo;
        if (prevCulture != null)
            Thread.CurrentThread.CurrentUICulture = prevCulture;
        return base.OnAfterExecute(requestContext, response);
    }
}