dotnet / dotnet/aspnetcore

Razor Pages: Urls generated by built-in taghelpers do not honor PageRouteModelConvention

Open
#16,960 24 comments 24 reactions 0 assignees View on GitHub
affected-medium area-mvc bug feature-routing investigate severity-major
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Describe the bug

In a project that utilizes Razor Pages and request localization in conjunction with an `IPageRouteModelConvention`, Urls generated through standard TagHelpers for anchors or forms do not honor routing conventions and route values.

### To Reproduce

**Current route values (page url is `/de`)**
- Page: /Index
- culture: de

**Markup:**
`Search`

**Expected Result:**
`Search`

**Actual Result:**
`Search`

There's a workaround but it is quite ugly:

`Search`

**Startup.cs:**

```c#
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Env = env;

var builder = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json", optional: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

if (env.IsDevelopment())
builder.AddUserSecrets();

Configuration = builder.Build();
}

public IConfiguration Configuration { get; }
public IWebHostEnvironment Env { get; }
public static RequestCulture DefaultRequestCulture = new RequestCulture("en-US", "en-US");

public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddSingleton(Configuration);

services.AddRazorPages(options =>
{
options.Conventions.Add(new CultureTemplateRouteModelConvention());
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.Configure(options =>
{
options.DefaultRequestCulture = DefaultRequestCulture;
options.SupportedCultures = AppConstants.SupportedCultures;
options.SupportedUICultures = AppConstants.SupportedCultures;

options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider { Options = options });
});

services.AddRouting(options =>
{
options.LowercaseUrls = true;
});

services.AddOptions();
services.AddLogging();
services.AddSingleton();
services.AddSingleton(Configuration);
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
Container = app.ApplicationServices.GetAutofacRoot();

app.UseStaticFiles();
app.UseRouting();
app.UseRequestLocalization();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
}
}
```

**CultureTemplateRouteModelConvention.cs:**

```c#
public class CultureTemplateRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;

for (var 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),
}
});
}
}
}

```

### Further technical details
- ASP.NET Core 3.0
- VS 2019

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.