如何在 ServiceStack 中正确本地化 Razor 视图
Posted
技术标签:
【中文标题】如何在 ServiceStack 中正确本地化 Razor 视图【英文标题】:How can I properly localize Razor Views in ServiceStack 【发布时间】:2013-10-30 13:03:43 【问题描述】:我目前正在从 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 视图中更改当前的线程 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;
这看起来既不雅又笨拙。有什么更好的方法来做到这一点?
*编辑: 我正在寻找两个挂钩点:一个在视图被调用之前,一个在它被渲染之后。这些应该保持对其他请求的干扰为零。
【问题讨论】:
【参考方案1】:我今天发现自定义 IServiceRunner 提供了正确的钩子(请参阅 https://github.com/ServiceStack/ServiceStack/wiki/Customize-HTTP-Responses)。
正如上面的那样,它只在页面由服务提供时才有效,因为在请求 ContentPage 时甚至不会触及 RequestFilters 和 ServiceRunner。
可能有趣的是,RequestFilter 是另一个挂钩点,它在视图的执行之前被调用。但对于 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);
【讨论】:
检查 github.com/ServiceStack/ServiceStack/wiki/Order-of-Operations 会更早地获得该信息。以上是关于如何在 ServiceStack 中正确本地化 Razor 视图的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL Server 和 ServiceStack.OrmLite 中使用架构名称
为啥 UserAuthExtensions.PopulateFromMap(session, jwtPayload) 不能在 ServiceStack.Auth 中正确反序列化带有转义的 json 值