Question

I am currently getting the prefered Culture from the Accept-Language-HTTP-Header and storing it in the AuthUserSession.

In 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));
        }
    }
});

My current solution to Render a View in the users prefered Culture is to change the current Threads UICulture from the Razor view:

@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;
}

This seems unelegant and clumsy. What would be a better way to do this?

*edit: I am looking for two hook points: one just before the View gets called, and one right after it got rendered. These should keep the interference with other Requests that get served to zero.

Was it helpful?

Solution

I discovered today that a custom IServiceRunner supplies just the right hooks (see https://github.com/ServiceStack/ServiceStack/wiki/Customize-HTTP-Responses).

As the one above it only works, when the page is served by a Service, because the RequestFilters and the ServiceRunner are not even touched when a ContentPage is requested.

It might be of interest, that the RequestFilter is another hook point, that is called before the Execution of the View. But the same seems true for the ResponseFilter. A small test in which I tried to reset the CurrentUICulture in the ResponseFilter rendered my page unlocalized.

In 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);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top