Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Razor Pages: Set cookie from _Layout.cshtml

In _Layout.cshtml I have menu to change language of the application, like:

<nav id="nav-lang">
                    <ul>
                        <li>
<a href="?culture=en-EN">EN</a>
                        </li>
                        <li>
                            <a href="?culture=pl-PL">PL</a>
                        </li>
                    </ul>
                
            </nav>

What it does is reloading the page and sets new culture - works well. The thing is, that if the user changes culture and then go to other page within my app, default culture is loaded. I checked my options and the best choice seems to be setting a cookie "UserCulture" to e.g. "c=pl-PL|uic=pl-PL". The thing is I don't really know how to do it from in razor pages. I think that I should have a with asp-page-handler set to some method (e.g. "SetCulture") and have setting cookie in that method, but this causes some problems:

  • where to put "SetCulture" if the form would be in _Layout.cshtml? _Layout.cshtml doesn't have code behind file
  • how to submit the form from anchor? If I put input type="submit" it ruins the look of the menu completely.. I know I could do it from js but I try to avoid js where it's not absolutely required, especially for such basic stuff..

I might be missing something very basic here, I'm quite new to Razor Pages still. From the hindsight I should have probably sticked to MVC but Razor Pages was said to be easier..

like image 562
robs23 Avatar asked Dec 08 '25 06:12

robs23


2 Answers

Thanks, Brad. The solution you proposed works well. In the meantime I've got also other suggestion elsewhere and I'll post it too for anyone searching the answer in future.

In _Layout.cshtml:

<nav id="nav-lang">
    <ul>
        <li><a asp-page="/Index" asp-page-handler="SetCulture" asp-route-culture="en-EN">EN</a></li>
        <li><a asp-page="/Index" asp-page-handler="SetCulture" asp-route-culture="pl-PL">PL</a></li>
    </ul>
</nav>

In code-behind of Index (or any other page having code-behind):

public async Task<IActionResult> OnGetSetCultureAsync(string culture)
        {
            HttpContext.Response.Cookies.Append("Culture", "c=" + culture + "|uic=" + culture);
            var returnUrl = Request.Headers["Referer"].ToString();
            if (returnUrl.Contains("?culture="))
            {
                var url = returnUrl.Substring(0, returnUrl.IndexOf("?culture=")); 
                return Redirect(url + "?culture=" + culture);
            }
            else
            {
                return Redirect(returnUrl + "?culture=" + culture);
            }

        }

And of course, for both solutions to work, there must be info in Startup.cs >> Configure:

var supportedCultures = new[]
            {
                new CultureInfo("en-US"),
                new CultureInfo("pl-PL")
            };

            var lo = new RequestLocalizationOptions // Localization Options
            {
                DefaultRequestCulture = new RequestCulture("en-US"),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures
            };

            var cp = lo.RequestCultureProviders.OfType<CookieRequestCultureProvider>().First(); // Culture provider
            cp.CookieName = "Culture";
like image 90
robs23 Avatar answered Dec 09 '25 20:12

robs23


I haven't tested this out but what about setting the cookie using JavaScript and then reloading the page. The server side razor page code should check the code instead of a query parameter.

Something like the following on the _Layout page. Modify the menu to call a JS function instead of a link with a query parameter. In the JS set the cookie and reload the page.

<nav id="nav-lang">
    <ul>
        <li class="nav-item" onClick="setCulture('en-EN')">EN</li>
        <li class="nav-item" onClick="setCulture('pl-PL')">PL</li>
    </ul>
</nav>
...
<script>
    function setCulture(culture) {
        document.cookie = "culture="+culture;
        location.reload();
    }
</script>
like image 31
Brad Patton Avatar answered Dec 09 '25 18:12

Brad Patton