Explanation: When i use async actions like Ajax.BeginForm, the threads cultureinfo is not set and therefor the library.dictionaryItem returns empty (i think).. First time the page load, the translation is there, but when i submit the form. then it returns with brackets [Username] and [Password] ("as it should if the returned DictionaryItem is Null or empty")
Question:
Is there a simple way to set the cultureinfo on async calls? Or is there a workaround? or do i just have to set the cultureinfo on all my models?
My Model, with my custom DisplayNameAttribute, that uses a library.DictionaryItem.
public class LoginModel
{
[Display("Username")] // Custom DisplayNameAttribute
public string Username { get; set; }
[Display("Password")] // Custom DisplayNameAttribute
public string Password { get; set; }
}
Custom DisplayNameAttribute
public class Display : DisplayNameAttribute
{
private string DictionaryItemKey { get; set; }
public Display(string dictionaryItemKey) : base()
{
DictionaryItemKey = dictionaryItemKey;
}
public override string DisplayName
{
get
{
// Custom service wish return library.GetDictionaryItem(key)
return TranslationService.GetDictionaryItem(DictionaryItemKey);
}
}
}
Custom service
public static class TranslationService
{
public static string GetDictionaryItem(string key)
{
var dictionaryItem = umbraco.library.GetDictionaryItem(key);
if (!string.IsNullOrWhiteSpace(dictionaryItem))
{
return dictionaryItem;
}
else
{
return string.Format("[{0}]", key);
}
}
}
SurfaceController
public class LoginSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
[ChildActionOnly]
[AllowAnonymous]
public ActionResult GetLogin()
{
return PartialView("~/Views/Partials/Models/login.cshtml", ModelHelper.NewLoginModel);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
// Could also be public async Task<ActionResult> PostLogin(LoginModel model) with an await method.
public ActionResult PostLogin(LoginModel model)
{
ModelState.AddModelError("", "Just to return an error");
return PartialView("~/Views/Partials/Models/login.cshtml", model);
}
}
I think you have to set culture with this lines of code:
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureCode);
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(cultureCode);
I was playing around with a RenderControllerFactory and overrideing of the IController, and your linked post got me closer to a solution. Setting the thread cultureInfo is not the problem, but getting the users last used cultureInfo is. (not the default set by the browser).
So i am looking for a way to get the current document/context cultureinfo.
Here is a working scenario using sessions. It's working locally, when i try switching between pages with different language set to them and post the form.
CultureinfoControllerFactory
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using Umbraco.Web.Mvc;
namespace My.WebApplication.Namespace
{
public class CultureinfoControllerFactory : RenderControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
// Custom service to retrieve the current thread cultureinfo (if any)
var cultureinfo = ThreadService.CultureInfo;
// Custom service to get the current session that contains the cultureinfo (if set)
var session = SessionService.GetSession(Constants.Session.CultureInfo);
if (session != null && requestContext.HttpContext.Request.IsAjaxRequest())
{
// Custom service to Set the thread cultureinfo.
ThreadService.CultureInfo = session as CultureInfo;
ThreadService.UiCultureInfo = session as CultureInfo;
}
else if (cultureinfo != null && cultureinfo != session)
{
// Custom service to create or override a session.
SessionService.SetSession(Constants.Session.CultureInfo, cultureinfo);
}
// Returning the base method, since we do not manipulate with it.
return base.CreateController(requestContext, controllerName);
}
}
}
ApplicationEventHandler
using System.Web.Mvc;
using Umbraco.Core;
namespace My.WebApplication.Namespace
{
public class FactoryApplicationEvent : ApplicationEventHandler
{
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ControllerBuilder.Current.SetControllerFactory(typeof(CultureinfoControllerFactory));
}
}
}
The best solution i could come up with, was to add a meta tag with the cultureinfo set in Umbraco. That way we can intercept all ajax calls and add a HttpRequest header to it. Then create a ControllerFactory to get all Http Request sent to any SurfaceControllers, and look for the custom made header and set the thread cultureinfo if the custom header is received.
Step 1:Adding a meta html tag to my layout.cshtml in the head section.
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using Umbraco.Web.Mvc;
namespace My.WebApplication.Namespace
{
public class CultureinfoControllerFactory : RenderControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
// Constants.HttpHeader.SetCultureInfo = "set-cultureinfo";
// Makeing sure nothing is null, and that the header we need exists.
if (requestContext != null
&& requestContext.HttpContext != null
&& requestContext.HttpContext.Request != null
&& requestContext.HttpContext.Request.Headers != null
&& requestContext.HttpContext.Request.Headers[Constants.HttpHeader.SetCultureInfo] != null
&& !string.IsNullOrEmpty(requestContext.HttpContext.Request.Headers[Constants.HttpHeader.SetCultureInfo]))
{
// Createing a cultureInfo from the set-cultureinfo header value.
var cultureInfo = CultureInfo.CreateSpecificCulture(requestContext.HttpContext.Request.Headers[Constants.HttpHeader.SetCultureInfo].ToString());
System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo;
System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
// Returning the base method, since we do not manipulate with the create method.
return base.CreateController(requestContext, controllerName);
}
}
}
Step 4:Adding the controller factory to the builder.
using System.Web.Mvc;
using Umbraco.Core;
namespace My.WebApplication.Namespace
{
public class FactoryApplicationEvent : ApplicationEventHandler
{
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ControllerBuilder.Current.SetControllerFactory(typeof(CultureinfoControllerFactory));
}
}
}
Finally, a general solution to the ajax/culture problem:-) This should be in the Umbraco core. For everyone implementing ajax forms in Umbraco sites, the issue is incredibly frustrating. The problem isn't Umbraco's fault, but it would help a lot of developers if this fix was in there.
async calls make empty dictionary item
Hi everyone.
I need some help here.
using umbraco 7.6.3
Explanation: When i use async actions like Ajax.BeginForm, the threads cultureinfo is not set and therefor the library.dictionaryItem returns empty (i think).. First time the page load, the translation is there, but when i submit the form. then it returns with brackets [Username] and [Password] ("as it should if the returned DictionaryItem is Null or empty")
Question: Is there a simple way to set the cultureinfo on async calls? Or is there a workaround? or do i just have to set the cultureinfo on all my models?
My Model, with my custom DisplayNameAttribute, that uses a library.DictionaryItem.
Custom DisplayNameAttribute
Custom service
SurfaceController
home.cshtml
PartialView login.cshtml
Hi Bo
I think you have to set culture with this lines of code:
Check out this thread also - https://our.umbraco.org/forum/developers/api-questions/53735-GetDictionaryValue-returns-empty-string#comment-186402
Thanks,
Alex
Hi Alex.
Thanks for your answer.
I was playing around with a RenderControllerFactory and overrideing of the IController, and your linked post got me closer to a solution. Setting the thread cultureInfo is not the problem, but getting the users last used cultureInfo is. (not the default set by the browser).
So i am looking for a way to get the current document/context cultureinfo.
Here is a working scenario using sessions. It's working locally, when i try switching between pages with different language set to them and post the form.
CultureinfoControllerFactory
ApplicationEventHandler
I made a solution for ajax calls.
The best solution i could come up with, was to add a meta tag with the cultureinfo set in Umbraco. That way we can intercept all ajax calls and add a HttpRequest header to it. Then create a ControllerFactory to get all Http Request sent to any SurfaceControllers, and look for the custom made header and set the thread cultureinfo if the custom header is received.
Step 1: Adding a meta html tag to my layout.cshtml in the head section.
Step 2: Adding a global ajax interceptor.
Step 3: Creating a controller factory.
Step 4: Adding the controller factory to the builder.
Fantastic, Bo!
Finally, a general solution to the ajax/culture problem:-) This should be in the Umbraco core. For everyone implementing ajax forms in Umbraco sites, the issue is incredibly frustrating. The problem isn't Umbraco's fault, but it would help a lot of developers if this fix was in there.
It would be great if we somehow could find a solution, so we only had to add the global ajax interceptor.
is working on a reply...