Search code examples
asp.net-corerazor-pages

PageRouteModelConvention for adding Culture to URL triggers second get request on Client when redirect is sent from server


In a basic CRUD app using NET8, I noticed that TempData, which provides the message "Person added successfully", was showing briefly on a page and then being cleared.

Inspecting the Network traffic on the client revealed two get requests https://host/person/edit/1 followed by https://host/fr/person/edit/1. I confirmed in the database that two requests were being sent for the record.

The OnPost handler for the Person/Create page redirects sets the TempData["Message"] then redirects the user to the edit page for subsequent changes to Person:

return RedirectToPage("./Edit", new { Person.Id });

The app uses the following PageRouteModelConvention to prepend the user's selected culture (culture selector in a dropdown on the page)

public class CultureTemplateRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (int i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];

            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = -1,
                    Template = AttributeRouteModel.CombineTemplates("{culture?}", selector.AttributeRouteModel.Template),
                }
            });
        }
    }
}

It's added via convention in the services

services.AddRazorPages(options =>
{
    options.Conventions.Add( new CultureTemplateRouteModelConvention() );
})
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
        {
            var assemblyName = new AssemblyName(typeof(SharedResource).GetTypeInfo().Assembly.FullName);
            return factory.Create(nameof(SharedResource), assemblyName.Name);
        };
    })
    .AddViewComponentsAsServices()
    .AddRazorRuntimeCompilation();

then configured in the Pipeline

var localizationOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization(localizationOptions);

I expect the solution is to include the Culture in the redirect to the client but I don't know how to configure that in the pipeline. I'd rather not do it in the handler.


Solution

  • Retrieving the culture from the client request and including it in the RedirectToPage prevents the additional request from the client.

    public async Task<IActionResult> OnPostAsync(CreatePersonCommand person)
    {
        var result = await mediator.Send(person);
        HandleResponse(result);
        if (Success)
        {
            var rqf = Request.HttpContext.Features.Get<IRequestCultureFeature>();
            var culture = rqf.RequestCulture.Culture.Name;
            return RedirectToPage("./Edit", new { culture = culture, Id = result.Person.Id });
        }
        return Page();
    }