From ad9da5735b66970946ce0720aa7b76e4bf5d402f Mon Sep 17 00:00:00 2001 From: Jon P Smith Date: Thu, 15 Dec 2022 14:24:52 +0000 Subject: [PATCH] Got .NET localization working in Example1 --- AuthPermissions.AspNetCore/SetupExtensions.cs | 5 +- .../Model/AppSummary.cs | 2 +- .../Pages/Index.cshtml | 5 +- .../Pages/Localization/SetCulture.cshtml | 16 +++ .../Pages/Localization/SetCulture.cshtml.cs | 43 +++++++ .../Pages/Shared/_Layout.cshtml | 10 +- .../PermissionsCode/AppAuthSetupData.cs | 2 +- .../Program.cs | 113 ++++++++++++++++-- .../Startup.cs | 91 -------------- .../appsettings.json | 4 +- 10 files changed, 178 insertions(+), 113 deletions(-) create mode 100644 Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml create mode 100644 Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml.cs delete mode 100644 Example1.RazorPages.IndividualAccounts/Startup.cs diff --git a/AuthPermissions.AspNetCore/SetupExtensions.cs b/AuthPermissions.AspNetCore/SetupExtensions.cs index d2f17386..ed1c65a6 100644 --- a/AuthPermissions.AspNetCore/SetupExtensions.cs +++ b/AuthPermissions.AspNetCore/SetupExtensions.cs @@ -1,9 +1,6 @@ // Copyright (c) 2021 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/ // Licensed under MIT license. See License.txt in the project root for license information. -using System; -using System.Linq; -using System.Threading.Tasks; using AuthPermissions.AdminCode; using AuthPermissions.AdminCode.Services; using AuthPermissions.AspNetCore.AccessTenantData; @@ -266,7 +263,7 @@ private static void RegisterCommonServices(this AuthSetupData setupData) setupData.Services.AddTransient(); //Localization services - //NOTE: The developer must register the .NET localization service and add + //NOTE: If you want to use the localization services you need to setup / register the .NET IStringLocalizer service setupData.Services.AddSingleton(typeof(ILocalizeWithDefault<>), typeof(LocalizeWithDefault<>)); //Other services diff --git a/Example1.RazorPages.IndividualAccounts/Model/AppSummary.cs b/Example1.RazorPages.IndividualAccounts/Model/AppSummary.cs index 9ec62efd..6e125e2c 100644 --- a/Example1.RazorPages.IndividualAccounts/Model/AppSummary.cs +++ b/Example1.RazorPages.IndividualAccounts/Model/AppSummary.cs @@ -14,6 +14,6 @@ public class AppSummary "Individual accounts: InMemoryDatabase", "AuthPermissions: In-memory database (uses SQLite in-memory)" }; - public string Note { get; } = "This is a basic example of AuthPermissions Roles and permissions."; + public string Note { get; } = "Shows basics of Roles and permissions, plus multi-language support."; } } \ No newline at end of file diff --git a/Example1.RazorPages.IndividualAccounts/Pages/Index.cshtml b/Example1.RazorPages.IndividualAccounts/Pages/Index.cshtml index 762ea768..7eca1d0b 100644 --- a/Example1.RazorPages.IndividualAccounts/Pages/Index.cshtml +++ b/Example1.RazorPages.IndividualAccounts/Pages/Index.cshtml @@ -1,12 +1,13 @@ @page @using Example1.RazorPages.IndividualAccounts.Model +@using Microsoft.AspNetCore.Identity @model IndexModel @{ ViewData["Title"] = "Home page"; }
-

Example1 - looking at Roles and Permissions

+

Example1 - looking at Roles/Permissions, plus localization

Application summary

    @@ -34,7 +35,7 @@ NOTE: The Email address is also the password in these cases.

      - @foreach (var user in @Model.Users) + @foreach (var user in @Model.Users ?? new List() ) {
    • @user.UserName
    • } diff --git a/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml b/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml new file mode 100644 index 00000000..438c18d7 --- /dev/null +++ b/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml @@ -0,0 +1,16 @@ +@page +@model SetCultureModel +@{ +} + +

      Select the culture you want

      + +
      +
      + +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml.cs b/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml.cs new file mode 100644 index 00000000..b354c909 --- /dev/null +++ b/Example1.RazorPages.IndividualAccounts/Pages/Localization/SetCulture.cshtml.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.Extensions.Options; + +namespace Example1.RazorPages.IndividualAccounts.Pages.Localization; + +public class SetCultureModel : PageModel +{ + private readonly IOptions _locOptions; + + public SetCultureModel(IOptions locOptions) + { + _locOptions = locOptions; + } + + [BindProperty] public List CultureList { get; set; } + [BindProperty] public string SetLanguage { get; set; } + + public void OnGet() + { + CultureList = _locOptions.Value.SupportedUICultures + .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName }) + .ToList(); + } + + public IActionResult OnPost() + { + Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(SetLanguage)) + ); + + return RedirectToPage("/Index"); + } +} \ No newline at end of file diff --git a/Example1.RazorPages.IndividualAccounts/Pages/Shared/_Layout.cshtml b/Example1.RazorPages.IndividualAccounts/Pages/Shared/_Layout.cshtml index 6930753e..459efb2e 100644 --- a/Example1.RazorPages.IndividualAccounts/Pages/Shared/_Layout.cshtml +++ b/Example1.RazorPages.IndividualAccounts/Pages/Shared/_Layout.cshtml @@ -1,4 +1,6 @@ - +@using System.Threading +@using Microsoft.Net.Http.Headers + @@ -32,6 +34,12 @@ User's claims + +
    • + Change +
    diff --git a/Example1.RazorPages.IndividualAccounts/PermissionsCode/AppAuthSetupData.cs b/Example1.RazorPages.IndividualAccounts/PermissionsCode/AppAuthSetupData.cs index c6fac6a8..3009a2c3 100644 --- a/Example1.RazorPages.IndividualAccounts/PermissionsCode/AppAuthSetupData.cs +++ b/Example1.RazorPages.IndividualAccounts/PermissionsCode/AppAuthSetupData.cs @@ -19,7 +19,7 @@ public static class AppAuthSetupData public static readonly List UsersWithRolesDefinition = new() { new ("Staff@g1.com", null, "Role1"), - new ("Mananger@g1.com", null, "Role2"), + new ("Manager@g1.com", null, "Role2"), new ( "Super@g1.com", null, "SuperAdmin"), }; } diff --git a/Example1.RazorPages.IndividualAccounts/Program.cs b/Example1.RazorPages.IndividualAccounts/Program.cs index df4c98a5..0900935b 100644 --- a/Example1.RazorPages.IndividualAccounts/Program.cs +++ b/Example1.RazorPages.IndividualAccounts/Program.cs @@ -1,20 +1,111 @@ +using Example1.RazorPages.IndividualAccounts.PermissionsCode; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System.Collections.Generic; +using System.Globalization; +using AuthPermissions; +using AuthPermissions.AspNetCore; +using AuthPermissions.AspNetCore.Services; +using AuthPermissions.AspNetCore.StartupServices; +using Example1.RazorPages.IndividualAccounts.Data; +using Microsoft.EntityFrameworkCore; +using RunMethodsSequentially; +using Microsoft.Extensions.Options; -namespace Example1.RazorPages.IndividualAccounts +namespace Example1.RazorPages.IndividualAccounts; + +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + + builder.Services.AddDbContext(opt => + opt.UseInMemoryDatabase(nameof(ApplicationDbContext))); + + builder.Services.AddDefaultIdentity( + options => options.SignIn.RequireConfirmedAccount = false) + .AddEntityFrameworkStores(); + + //Example of configure a page as only shown if you log in + builder.Services.AddRazorPages(options => { - CreateHostBuilder(args).Build().Run(); - } + options.Conventions.AuthorizePage("/AuthBuiltIn/LoggedInConfigure"); + }) + #region localization + .AddViewLocalization(options => options.ResourcesPath = "Resources"); + #endregion - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => + #region localization + builder.Services.Configure(options => { + List supportedCultures = new List { - webBuilder.UseStartup(); - }); + new ("en"), + new ("fr"), + }; + options.DefaultRequestCulture = new RequestCulture("en"); + options.SupportedCultures = supportedCultures; + options.SupportedUICultures = supportedCultures; + + options.RequestCultureProviders = new List() + { + new CookieRequestCultureProvider(), + //new AcceptLanguageHeaderRequestCultureProvider(), + //new QueryStringRequestCultureProvider() + }; + }); + #endregion + + builder.Services.RegisterAuthPermissions() + .UsingInMemoryDatabase() + .IndividualAccountsAuthentication() + .AddRolesPermissionsIfEmpty(AppAuthSetupData.RolesDefinition) + .AddAuthUsersIfEmpty(AppAuthSetupData.UsersWithRolesDefinition) + .RegisterAuthenticationProviderReader() + .RegisterFindUserInfoService() + .AddSuperUserToIndividualAccounts() + .SetupAspNetCoreAndDatabase(options => + { + //Migrate individual account database + options.RegisterServiceToRunInJob>(); + //Add demo users to the database + options.RegisterServiceToRunInJob(); + }); + + + var app = builder.Build(); + + #region localization + + var options = app.Services.GetRequiredService>().Value; + app.UseRequestLocalization(options); + + #endregion + + // Configure the HTTP request pipeline. + if (!app.Environment.IsDevelopment()) + { + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.MapRazorPages(); + + app.Run(); } -} + +} \ No newline at end of file diff --git a/Example1.RazorPages.IndividualAccounts/Startup.cs b/Example1.RazorPages.IndividualAccounts/Startup.cs deleted file mode 100644 index 55f72782..00000000 --- a/Example1.RazorPages.IndividualAccounts/Startup.cs +++ /dev/null @@ -1,91 +0,0 @@ -using AuthPermissions; -using AuthPermissions.AspNetCore; -using AuthPermissions.AspNetCore.Services; -using AuthPermissions.AspNetCore.StartupServices; -using Example1.RazorPages.IndividualAccounts.Data; -using Example1.RazorPages.IndividualAccounts.PermissionsCode; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using RunMethodsSequentially; - -namespace Example1.RazorPages.IndividualAccounts -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddDatabaseDeveloperPageExceptionFilter(); - - services.AddDbContext(opt => - opt.UseInMemoryDatabase(nameof(ApplicationDbContext))); - - services.AddDefaultIdentity( - options => options.SignIn.RequireConfirmedAccount = false) - .AddEntityFrameworkStores(); - - //Example of configure a page as only shown if you log in - services.AddRazorPages(options => - { - options.Conventions.AuthorizePage("/AuthBuiltIn/LoggedInConfigure"); - }); - - services.RegisterAuthPermissions() - .UsingInMemoryDatabase() - .IndividualAccountsAuthentication() - .AddRolesPermissionsIfEmpty(AppAuthSetupData.RolesDefinition) - .AddAuthUsersIfEmpty(AppAuthSetupData.UsersWithRolesDefinition) - .RegisterAuthenticationProviderReader() - .RegisterFindUserInfoService() - .AddSuperUserToIndividualAccounts() - .SetupAspNetCoreAndDatabase(options => - { - //Migrate individual account database - options.RegisterServiceToRunInJob>(); - //Add demo users to the database - options.RegisterServiceToRunInJob(); - }); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseMigrationsEndPoint(); - } - else - { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - }); - } - } -} diff --git a/Example1.RazorPages.IndividualAccounts/appsettings.json b/Example1.RazorPages.IndividualAccounts/appsettings.json index d0f520ea..11f69d3b 100644 --- a/Example1.RazorPages.IndividualAccounts/appsettings.json +++ b/Example1.RazorPages.IndividualAccounts/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Example1.RazorPages.IndividualAccounts;Trusted_Connection=True;MultipleActiveResultSets=true" + //Example1 uses Sqlite in-memory database }, "Logging": { "LogLevel": { @@ -15,5 +15,5 @@ "Email": "Super@g1.com", "Password": "Super@g1.com" }, - "DemoUsers": "Trainee@g1.com,Staff@g1.com,Mananger@g1.com" + "DemoUsers": "Trainee@g1.com,Staff@g1.com,Manager@g1.com" }