Reputation: 2780
I am developing a ASP.NET Core MVC 1.1 application and I am struggling to find a clean and efficient solution for formatting decimal
as currency with custom currency code (i.e. different than specified in the CultureInfo
).
Currently, I have the following decimal
extension class:
public static class DecimalExtensions
{
public static readonly Dictionary<string, string> CurrencyCodeToSymbol = new Dictionary<string, string>() {
{ "EUR", "€"},
{ "USD", "$"},
{ "GBP", "£"},
};
public static string FormatCurrency(this decimal decimalValue, string currencyCode)
{
var culture = (CultureInfo) CultureInfo.CurrentCulture.Clone();
culture.NumberFormat.CurrencySymbol = CurrencyCodeToSymbol[currencyCode];
return decimalValue.ToString("C", culture);
}
}
My current solution consists of two parts:
CultureInfo
instance with the right CurrencySymbol
property.Sadly, I don't like either part.
For the first part, I could put the mapping into appsettings.json
and fill the Dictionary
in the Startup
class. However, I would still prefer to skip this altogether and iterate over system supported cultures and currencies. However, as I have done my research, this is not yet possible in ASP.NET Core MVC 1.1.
For the second part, I don't like the Clone()
part at all. Since the CultureInfo.CurrentCulture
is readonly, I will probably have to clone it at some point, but preferably not at each call to my extension method.
Is there any way to cache the cloned and altered CultureInfo
? Since this is an extension class, I guess Dependency Injection is out of the picture.
Upvotes: 3
Views: 2833
Reputation: 1372
If you are still looking for an answer, I've tweaked your extension method to cache the cloned culture info objects.
public static class DecimalExtensions
{
private static readonly IDictionary<String, String> _currencyCodeToSymbol = new Dictionary<String, String>
{
{ "EUR", "€"},
{ "USD", "$"},
{ "GBP", "£"},
};
private static readonly ConcurrentDictionary<String, CultureInfo> _currencyCodeToLocale =
new ConcurrentDictionary<String, CultureInfo>();
public static String FormatCurrency(this Decimal decimalValue, String currencyCode = "USD")
{
if (!_currencyCodeToSymbol.ContainsKey(currencyCode))
{
throw new NotImplementedException($"Currency code {currencyCode} is not supported");
}
var cultureInfo = _currencyCodeToLocale.GetOrAdd(currencyCode, _ =>
{
var info = CultureInfo.CurrentCulture.Clone() as CultureInfo;
info.NumberFormat.CurrencySymbol = _currencyCodeToSymbol[currencyCode];
return info;
});
return decimalValue.ToString("C", cultureInfo);
}
}
Upvotes: 2