fix(client-controller): single constructor with IHtmlLocalizer

The partial class ClientController had two constructors declared
across ClientController.cs and ClientController.Collections.cs.
ASP.NET Core DI failed to pick one at request time with:

  System.InvalidOperationException: Multiple constructors accepting
  all given argument types have been found in type
  'Yavsc.Controllers.ClientController'.

Move IHtmlLocalizer<ClientController> into the primary constructor
in ClientController.cs and drop the duplicate one in
ClientController.Collections.cs. The Collections partial now keeps
only its readonly field and action methods; the constructor and
field assignment are unified on the main file.

Also add the missing 'using Microsoft.AspNetCore.Mvc.Localization;'
to ClientController.cs so IHtmlLocalizer resolves.
This commit is contained in:
Paul Schneider 2026-06-21 21:14:20 +01:00
commit 6aaff74082
13 changed files with 582 additions and 23 deletions

View file

@ -27,12 +27,8 @@ public partial class ClientController
readonly IHtmlLocalizer _localizer;
public ClientController(
IHtmlLocalizer<ClientController> localizer
)
{
_localizer = localizer;
}
// ClientController has a single constructor declared in
// ClientController.cs; this partial shares its fields.
[HttpGet]

View file

@ -3,6 +3,7 @@ using IdentityServer8.EntityFramework.Entities;
using IdentityServer8.EntityFramework.Stores;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
@ -21,7 +22,8 @@ namespace Yavsc.Controllers
public ClientController(
ApplicationDbContext dbContext,
ClientStore clientStore, IOptions<SiteSettings> siteSettingsOptions
ClientStore clientStore, IOptions<SiteSettings> siteSettingsOptions,
IHtmlLocalizer<ClientController> localizer
)
@ -29,6 +31,7 @@ namespace Yavsc.Controllers
this.dbContext = dbContext;
this.clientStore = clientStore;
this.siteSettings = siteSettingsOptions.Value;
_localizer = localizer;
}
// GET: Client

View file

@ -101,7 +101,7 @@ public static class HostingExtensions
services.AddTransient<ITrueEmailSender, MailSender>()
.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailSender>();
services.AddTransient<IYavscMessageSender, YavscMessageSender>()
.AddTransient<IBillingService, BillingService>()
@ -143,7 +143,7 @@ public static class HostingExtensions
{
IServiceCollection services = builder.Services;
var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName);
services.AddDbContext<ApplicationDbContext>(options =>
{
if (UsesInMemoryProvider(connectionString))
@ -284,7 +284,7 @@ public static class HostingExtensions
});
var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name;
var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName);
string sqliteConnectionString = $"Data Source={Path.Combine(Path.GetTempPath(), "yavsc_test.db")}";
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
@ -334,10 +334,18 @@ public static class HostingExtensions
sql => sql.MigrationsAssembly(migrationsAssembly));
}
};
});
if (builder.Environment.IsDevelopment())
// Skip the production signing-cert requirement when running with
// an in-memory database (test fixtures) or in the Development
// environment. In those cases IdentityServer8 falls back to
// AddDeveloperSigningCredential which mints an ephemeral key
// at startup; signing real tokens against it would fail, but
// the test fixtures only use the discovery/JWKS endpoints.
var useDevSigning = builder.Environment.IsDevelopment()
|| UsesInMemoryProvider(connectionString);
if (useDevSigning)
{
identityServerBuilder.AddDeveloperSigningCredential();
}
@ -774,7 +782,7 @@ public static class HostingExtensions
}
public async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
public async static Task<WebApplication> ConfigurePipeline(this WebApplication app, string staticAssetsManifestPath=null)
{
ILoggerFactory loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Program>();
@ -815,8 +823,8 @@ public static class HostingExtensions
app.UseIdentityServer();
app.UseAuthorization();
app.UseCors("default");
app.MapStaticAssets();
app.MapDefaultControllerRoute();
app.MapStaticAssets(staticAssetsManifestPath);
//app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");