🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 14 Min Lesezeit
0

ASP.NET 8 – Multilingual Application with single Resx file – Part4 – Resource Manager

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




ASP.NET 8 – Multilingual Application with single Resx file – Part4 – Resource Manager



A practical guide to building a multi-language Asp.Net 8 MVC application.



Abstract:. A practical guide to building a multi-language Asp.Net 8 MVC application where all language resource strings are kept in a single shared file, as opposed to having separate resource files for each controller/view. Here we show that old fashion approach of the Resource Manager is still working in Asp.Net 8 MVC.






1 Resource Manager is still working in Asp.Net 8 MVC



For those who like the old-fashioned approach, the good news is that the Resource Manager is still working in Asp.Net 8 MVC. You can use it together at the same time as IStringLocalizer, or even as the only localization mechanism if that is what you like.






1.1 How Resource Manager works



So, a typical solution is to use expressions in code like “Resources.SharedResource.Wellcome”. That is really a property that evaluates to the string. Evaluation to the string is done dynamically in run-time, and the string is chosen from SharedResource resx files, based on the current thread culture.






2 Other articles in this series



Articles in this series are:


ASP.NET 8 – Multilingual Application with single Resx file – Part 1


ASP.NET 8 – Multilingual Application with single Resx file – Part 2 – Alternative Approach


ASP.NET 8 – Multilingual Application with single Resx file – Part 3 – Form Validation Strings


ASP.NET 8 – Multilingual Application with single Resx file – Part 4 – Resource Manager





3 Shared Resources approach



By default, Asp.Net Core 8 MVC technology envisions separate resource file .resx for each controller and the view. But most people do not like it, since most multilanguage strings are the same in different places in the application, we would like it to be all in the same place.


Literature [1] calls that approach the “Shared Resources” approach. In order to implement it, we will create a marker class SharedResoureces.cs to group all the resources.





4 Steps to Multilingual Application





4.1 Configuring Localization Services and Middleware



Localization services are configured in Program.cs:




CODE
 private static void AddingMultiLanguageSupportServices(WebApplicationBuilder? builder)
{
if (builder == null) { throw new Exception("builder==null"); };

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { "en", "fr", "de", "it" };
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
}

private static void AddingMultiLanguageSupport(WebApplication? app)
{
app?.UseRequestLocalization();
}










4.2 Create marker class SharedResources.cs



This is just a dummy marker class to group shared resources. We need it for its name and type.


It seems the namespace needs to be the same as the app root namespace, which needs to be the same as the assembly name. I had some problems when changing the namespace, it would not work. If it doesn't work for you, you can try to use the full class name in your DI instruction, like this one:


IStringLocalizer<SharedResources01.SharedResource> StringLocalizer



There is no magic in the name "SharedResource", you can name it "MyResources" and change all references in the code to "MyResources" and all will still work.



The location seems can be any folder, although some articles ([6] claim it needs to be the root project folder I do not see such problems in this example. To me looks like it can be any folder, just keep your namespace tidy.




CODE

//SharedResource.cs===================================================
namespace SharedResources04
{
/*
* This is just a dummy marker class to group shared resources
* We need it for its name and type
*
* It seems the namespace needs to be the same as app root namespace
* which needs to be the same as the assembly name.
* I had some problems when changing the namespace, it would not work.
* If it doesn't work for you, you can try to use full class name
* in your DI instruction, like this one:
* IStringLocalizer<SharedResources04.SharedResource> StringLocalizer
*
* There is no magic in the name "SharedResource", you can
* name it "MyResources" and change all references in the code
* to "MyResources" and all will still work
*
* Location seems can be any folder, although some
* articles claim it needs to be the root project folder
* I do not see such problems in this example.
* To me looks it can be any folder, just keep your
* namespace tidy.
*/


public class SharedResource
{
}
}










4.3 Create language resources files



In the folder “Resources” create your language resources files, and make sure you name them SharedResources.xx.resx.





In Visual Studio Resource editor you need to set Access Modifier to Public for all resource files.





I built a small application to demo it, and here is the screen where I can change the language:





Note that I added some debugging info into the footer, to show the value of the Request language cookie, to see if the app is working as desired.






5 Full Code



Since most people like code they can copy-paste, here is the full code of the application. Code can be downladed at GitHub [99].




CODE
//Program.cs===========================================================================
namespace SharedResources04
{
public class Program
{
public static void Main(string[] args)
{
//=====Middleware and Services=============================================
var builder = WebApplication.CreateBuilder(args);

//adding multi-language support
AddingMultiLanguageSupportServices(builder);

// Add services to the container.
builder.Services.AddControllersWithViews();

//====App===================================================================
var app = builder.Build();

//adding multi-language support
AddingMultiLanguageSupport(app);

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=ChangeLanguage}/{id?}");

app.Run();
}

private static void AddingMultiLanguageSupportServices(WebApplicationBuilder? builder)
{
if (builder == null) { throw new Exception("builder==null"); };

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { "en", "fr", "de", "it" };
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
}

private static void AddingMultiLanguageSupport(WebApplication? app)
{
app?.UseRequestLocalization();
}
}
}


//SharedResource.cs===================================================
namespace SharedResources04
{
/*
* This is just a dummy marker class to group shared resources
* We need it for its name and type
*
* It seems the namespace needs to be the same as app root namespace
* which needs to be the same as the assembly name.
* I had some problems when changing the namespace, it would not work.
* If it doesn't work for you, you can try to use full class name
* in your DI instruction, like this one:
* IStringLocalizer<SharedResources04.SharedResource> StringLocalizer
*
* There is no magic in the name "SharedResource", you can
* name it "MyResources" and change all references in the code
* to "MyResources" and all will still work
*
* Location seems can be any folder, although some
* articles claim it needs to be the root project folder
* I do not see such problems in this example.
* To me looks it can be any folder, just keep your
* namespace tidy.
*/


public class SharedResource
{
}
}

//HomeController.cs================================================================
namespace SharedResources04.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IStringLocalizer<SharedResource> _stringLocalizer;

/* Here is, of course, the Dependency Injection (DI) coming in and filling
* all the dependencies. The key thing is we are asking for a specific
* type=SharedResource.
* If it doesn't work for you, you can try to use full class name
* in your DI instruction, like this one:
* IStringLocalizer<SharedResources04.SharedResource> stringLocalizer
*/

public HomeController(ILogger<HomeController> logger,
IStringLocalizer<SharedResource> stringLocalizer)
{
_logger = logger;
_stringLocalizer = stringLocalizer;
}

public IActionResult ChangeLanguage(ChangeLanguageViewModel model)
{
if (model.IsSubmit)
{
HttpContext myContext = this.HttpContext;
ChangeLanguage_SetCookie(myContext, model.SelectedLanguage);
//doing funny redirect to get new Request Cookie
//for presentation
return LocalRedirect("/Home/ChangeLanguage");
}

//prepare presentation
ChangeLanguage_PreparePresentation(model);
return View(model);
}

private void ChangeLanguage_PreparePresentation(ChangeLanguageViewModel model)
{
model.ListOfLanguages = new List<SelectListItem>
{
new SelectListItem
{
Text = "English",
Value = "en"
},

new SelectListItem
{
Text = "German",
Value = "de",
},

new SelectListItem
{
Text = "French",
Value = "fr"
},

new SelectListItem
{
Text = "Italian",
Value = "it"
}
};
}

private void ChangeLanguage_SetCookie(HttpContext myContext, string? culture)
{
if(culture == null) { throw new Exception("culture == null"); };

//this code sets .AspNetCore.Culture cookie
CookieOptions cookieOptions = new CookieOptions();
cookieOptions.Expires = DateTimeOffset.UtcNow.AddMonths(1);
cookieOptions.IsEssential = true;

myContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
cookieOptions
);
}

public IActionResult LocalizationExample(LocalizationExampleViewModel model)
{
string text = "Thread CurrentUICulture is [" + @Thread.CurrentThread.CurrentUICulture.ToString() + "] ; ";
text += "Thread CurrentCulture is [" + @Thread.CurrentThread.CurrentCulture.ToString() + "]";
model.ThreadCultureInController = text;
//here we test localization by Resource Manager
model.LocalizedInControllerByResourceManager1 = Resources.SharedResource.Wellcome;
model.LocalizedInControllerByResourceManager2 = Resources.SharedResource.Hello_World;
//here we test localization by IStringLocalizer
model.LocalizedInControllerByIStringLocalizer1 = _stringLocalizer["Wellcome"];
model.LocalizedInControllerByIStringLocalizer2 = _stringLocalizer["Hello World"];

return View(model);
}


public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

//ChangeLanguageViewModel.cs=====================================================
namespace SharedResources04.Models.Home
{
public class ChangeLanguageViewModel
{
//model
public string? SelectedLanguage { get; set; } = "en";

public bool IsSubmit { get; set; } = false;

//view model
public List<SelectListItem>? ListOfLanguages { get; set; }
}
}

//LocalizationExampleViewModel.cs===============================================
namespace SharedResources04.Models.Home
{
public class LocalizationExampleViewModel
{
public string? LocalizedInControllerByResourceManager1 { get; set; }
public string? LocalizedInControllerByResourceManager2 { get; set; }

public string? LocalizedInControllerByIStringLocalizer1 { get; set; }
public string? LocalizedInControllerByIStringLocalizer2 { get; set; }

public string? ThreadCultureInController { get; set; }
}
}










CODE
@* ChangeLanguage.cshtml ===================================================*@
@model ChangeLanguageViewModel

@{
<div style="width:500px">
<p class="bg-info">
<partial name="_Debug.AspNetCore.CultureCookie" /><br />
</p>

<form id="form1">
<fieldset class="border rounded-3 p-3">
<legend class="float-none w-auto px-3">Change Language</legend>
<div class="form-group">
<label asp-for="SelectedLanguage">Select Language</label>
<select class="form-select" asp-for="SelectedLanguage"
asp-items="@Model.ListOfLanguages">
</select>
<input type="hidden" name="IsSubmit" value="true">
<button type="submit" form="form1" class="btn btn-primary mt-3 float-end"
asp-area="" asp-controller="Home" asp-action="ChangeLanguage">
Submit
</button>
</div>
</fieldset>
</form>
</div>
}

@* LocalizationExample.cshtml ====================================================*@
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Localization
@using SharedResources04

@model LocalizationExampleViewModel

@* Here is of course the Dependency Injection (DI) coming in and filling
all the dependencies. The key thing is we are asking for a specific
type=SharedResource.
If it doesn't work for you, you can try to use full class name
in your DI instruction, like this one:
@inject IStringLocalizer<SharedResources04.SharedResource> StringLocalizer
*@

@inject IStringLocalizer<SharedResource> StringLocalizer

@{
<div style="width:600px">
<p class="text-success">
Controller Thread Culture: <br />
@Model.ThreadCultureInController
</p>

<p class="text-primary">
Localized In Controller By ResourceManager: <br />
@Model.LocalizedInControllerByResourceManager1
</p>

<p class="text-primary">
Localized In Controller By ResourceManager: <br />
@Model.LocalizedInControllerByResourceManager2
</p>

<p class="text-primary">
Localized In Controller By IStringLocalizer: <br />
@Model.LocalizedInControllerByIStringLocalizer1
</p>

<p class="text-primary">
Localized In Controller By IStringLocalizer: <br />
@Model.LocalizedInControllerByIStringLocalizer2
</p>

<p class="text-success">
@{
string text = "Thread CurrentUICulture is [" +
@Thread.CurrentThread.CurrentUICulture.ToString() + "] ; ";
text += "Thread CurrentCulture is [" +
@Thread.CurrentThread.CurrentCulture.ToString() + "]";
}
View Thread Culture: <br />
@text
</p>

<p class="text-primary">
Localized In View By ResourceManager: <br />
@SharedResources04.Resources.SharedResource.Wellcome
</p>

<p class="text-primary">
Localized In View By ResourceManager: <br />
@SharedResources04.Resources.SharedResource.Hello_World
</p>

<p class="text-primary">
Localized In View By IStringLocalizer: <br />
@StringLocalizer["Wellcome"]
</p>

<p class="text-primary">
Localized In View By IStringLocalizer: <br />
@StringLocalizer["Hello World"]
</p>

</div>
}










6 References



[1]


Provide localized resources for languages and cultures in an ASP.NET Core app



[3]


Globalization and localization in ASP.NET Core



[5]


ASP.NET Core Localization with help of SharedResources



[99] https://github.com/MarkPelf/AspNet8MultilingualApplicationWithSingleResxFile

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten ASP.NET 8 – Multilingual Application with single Resx file – Part4 – Resource Manager

Thematisch verwandte Begriffe: ASPNET, Multilingual, Application, with · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...