Настройка пользовательской культуры в веб-приложении ServiceStack + MVC
Мне нужно установить специфичную для пользователя культуру для каждого веб-запроса, отправленного в мое веб-приложение, написанное с ServiceStack 3
а также MVC 4
,
Культура каждого пользователя хранится в его профиле в базе данных, которую я извлекаю в свою собственную реализацию IAuthSession
используя собственный поставщик аутентификации, полученный из CredentialsAuthProvider
, Так что мне плевать на браузер AcceptLanguage
заголовок и вместо этого хотите установить культуру текущего потока в свойство Culture сеанса аутентификации сразу после ServiceStack
разрешает это из кеша. Это должно произойти для обоих 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's 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
По предложению Скотта я создал обычай 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);
}
}
Поскольку я изменяю культуру только после аутентификации пользователя, имеет смысл (в любом случае, на мой взгляд) делать это в том же месте, где мы проверяем аутентификацию.
Затем я украсил все мои службы SS и контроллеры MVC этим атрибутом вместо оригинального [Authenticate]
,
Теперь, когда служба SS называется атрибутом Execute
метод выполняется, и культура устанавливается правильно. Тем не мение, Execute
никогда не выполняется, когда вызывается действие контроллера MVC, что действительно вызывает недоумение, потому что тогда как MVC+SS узнает, как перенаправить неаутентифицированные запросы на страницу входа в систему.
Есть какие-нибудь мысли?
2 ответа
Я бы сделал это с помощью RequestFilter
вместо того, чтобы переопределять SessionAs<T>
, В вашем AppHost
Configure
метод:
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);
});
}
Я закончил тем, что создал собственный фильтр действий 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, так и на стороне СС, так что я счастлив!