Question

I was wondering whether any people could help me please? I'm trying to create a site where the user logs in, it retrieves their chosen language from the database, and it uses that when setting the culture. There are also a number of settings about the user that would be retrieved at the same time as the user's language.

The culture/translations are handled via a base controller below (it's still a test version, but you will get the idea).

public abstract class BaseController : Controller
{

    //public UserRegistrationInformation UserSession;

    //public void GetUserInfo()
    //{
    //    WebUsersEntities db = new WebUsersEntities();
    //    UserSession = db.UserRegistrationInformations.Where(r => r.uri_UserID == WebSecurity.CurrentUserId).FirstOrDefault();
    //}


    protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
    {
        //GetUserInfo();


        string cultureName = null;
        // Change this to read from the user settings rather than a cookie

        /// Attempt to read the culture cookie from Request
        //HttpCookie cultureCookie = Request.Cookies["_culture"];
        //if (cultureCookie != null)
        //    cultureName = cultureCookie.Value;
        //else
            cultureName = Request.UserLanguages[0]; // obtain it from HTTP header AcceptLanguages
            //cultureName = "es-es";

            // Validate culture name
            cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe

            // Modify current thread's cultures
        Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

        return base.BeginExecuteCore(callback, state);
    }


}

This was largely taken from http://afana.me/post/aspnet-mvc-internationalization-part-2.aspx

I've been searching for how to pass the user's settings to the _layout rather than just the view. I found an interesting post here Pass data to layout that are common to all pages that works for me, I've created a base ViewModel, and any other ViewModels are inheriting it.

public abstract class ViewModelBase
{
    public string BrandName { get; set; }
    public UserRegistrationInformation UserSession;

    public void GetUserInfo()
    {
        WebUsersEntities db = new WebUsersEntities();
        UserSession = db.UserRegistrationInformations.Where(r => r.uri_UserID == WebSecurity.CurrentUserId).FirstOrDefault();
    }

}

To test with I've altered the existing change password model and control to:

public class LocalPasswordModel : ViewModelBase
{..........}

and

public ActionResult Manage(ManageMessageId? message)
    {

        //ViewModelAccounts vma = new ViewModelAccounts();
        //vma.GetUserInfo();
        LocalPasswordModel l = new LocalPasswordModel();
        l.GetUserInfo();
        l.BrandName = "blue";

        ViewBag.StatusMessage =
            message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
            : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
            : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
            : "";
        ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
        ViewBag.ReturnUrl = Url.Action("Manage");
        return View(l);
    }

Again this works perfectly, however I only want to retrieve the user's information the once. Currently I can do what I want by calling it in the BeginExecuteCore, and then again in the controller as above. How can I call this the once to be used everywhere? i.e. populate the BaseViewModel.

Thanks for any help or pointers you may be able to give!

Was it helpful?

Solution

Ok. I've finally solved this.

I'm, creating a base model that all of my other view-models are going to inherit from. It can also be called directly in case any view doesn't require its own view-model.

public class ViewModelBase
{
    public UserSettings ProfileSettings;

    // Create a new instance, so we don't need to every time its called.
    public ViewModelBase()
    {
        ProfileSettings = new UserSettings();
    }

}

public class UserSettings // UserSettings is only used here and consumed by ViewModelBase, its the name there that is used throughout the application
{
    public string BrandName { get; set; }
    public UserRegistrationInformation UserSession;    
}

This is being generated in the basecontroller.

public abstract class BaseController : Controller
{
    public ViewModelBase vmb = new ViewModelBase();

    protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
    {
        string cultureName = null;
        int userid = 0;

        if (System.Web.Security.Membership.GetUser() != null)
        {
            //logged in
            userid = (int)System.Web.Security.Membership.GetUser().ProviderUserKey;

            WebUsersEntities db = new WebUsersEntities();
            vmb.ProfileSettings.UserSession = db.UserRegistrationInformations.Where(r => r.uri_UserID == userid).FirstOrDefault();
            vmb.ProfileSettings.BrandName = "test";

            cultureName = "es-es";
        }
        else
        {
            // not logged in                
            cultureName = Request.UserLanguages[0]; // obtain it from HTTP header AcceptLanguages
        }


        // Validate culture name
        cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe

        // Modify current thread's cultures            
        Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

        return base.BeginExecuteCore(callback, state);
    }
}

The other controllers all inherit from this controller. If any screen has a dedicated view-model it can retrieve the information from the model populated in the controller like this:

    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        LoginModel v = new LoginModel();

        v.ProfileSettings = vmb.ProfileSettings;

        ViewBag.ReturnUrl = returnUrl;
        return View(v);
    }

I hope that helps someone in the future.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top