Translations not working remotely only in a local environment - c#

On my browser that I run from my local environemnt, the strings are translated as supposed to. When I upload to Azure, it still works. However, when I switch to Edge (that I never use for anything other than downloading FireFox), the strings are not translated anymore. I verified with external users on a wide range of browsers and it seems be platform independent issue.
I have all my translations in a global file placed in the root directory and I have the dummy file so I can inject it into views and controllers, as proposed by the docs. Somehow, the RESX file seems not to be found so I put it to Always upload. No change in misbehavior, though.
I'm not sure how to diagnose it further or if the RESX file is compiled into the DLL or uploaded straight off to the server and read from on the fly. Is it possible to verify that the file is "up there" somehow?
My config is like this.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddLocalization(a => a.ResourcesPath = "");
services.Configure<RequestLocalizationOptions>(a =>
{
CultureInfo[] supportedCultures = {
new CultureInfo("sv-SE"),
new CultureInfo("se")
};
a.DefaultRequestCulture = new RequestCulture("se");
a.SupportedCultures = supportedCultures;
a.SupportedUICultures = supportedCultures;
});
...
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseRequestLocalization();
...
app.UseMvcWithDefaultRoute();
}
edit
I've noticed that it works in Chrome when I have those lines.
RequestLocalizationOptions options = app.ApplicationServices
.GetService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization(options);
It stops working when I have those instead.
//RequestLocalizationOptions options = app.ApplicationServices
// .GetService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization();
In IE it doesn't work in either case.

Couple words about culture configuration. I guess you wanted to specify only Swedish locale so you have these line of code
CultureInfo[] supportedCultures = {
new CultureInfo("sv-SE"),
new CultureInfo("se")
};
It turns out that sv-SE is definitely Swedish culture, but se is Northern Sami culture. If your intention is only Swedish culture you need to set sv instead of se
CultureInfo[] supportedCultures = {
new CultureInfo("sv-SE"),
new CultureInfo("sv")
};
a.DefaultRequestCulture = new RequestCulture("sv");
Back to the main problem. By default there are 3 ways to set request culture, via query string, cookies or Accept-Language header. It looks like you don't specify a culture in request cookies or query string, but your browser sends Accept-Language header from which ASP.NET Core reads request culture. If a browser sends en-US, en, and sv cultures, none of them matches to supportedCultures (which are sv-SE and se) the framework falls back to DefaultRequestCulture (which is se) and reads resources from Lingo.se.resx and everything is fine. But it looks like Edge (on any other browser but on another computer) sent different set of cultures within Accept-Language header which included sv-SE containing in supportedCultures. So resource reader searched for Lingo.sv-se.resx or Lingo.sv.resx file but with no luck and thus no translation were provided.
If my assumption is right changing se to sv in your code and renaming Lingo.se.resx to Lingo.sv.resx will fix the problem.

Related

Kendo CurrencyTextBox displays 200.00 as 20000

I am using kendo UI to create an input box,
I want to automatically display the amount user have to pay in the textbox before,
so that user will only have to insert an amount if it differs from default
The data is given as decimal number.
I have tried:
#(Html.Kendo().CurrencyTextBoxFor(model => model.Paid).Format("R#0.00").Min(0))
And now also:
#(Html.Kendo().NumericTextBoxFor<decimal>(model => model.Paid).Format("R#.##").Min(0))
for some reason the textbox just keeps displaying two extra zeros
For some reason the textbox just keeps displaying two extra zeros
Yes, as per my investigation upon your code snippet it might be because of your default-culture. However, we can customize it as per the requirement. You could follow below steps:
Program.cs:
var defaultCulture = "en-US";
var ci = new CultureInfo(defaultCulture);
ci.NumberFormat.NumberDecimalSeparator = "."; // Defining my preferrence for number
ci.NumberFormat.CurrencyDecimalSeparator = ".";
// Configuring Number Seperator Using Localization middleware
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(ci),
SupportedCultures = new List<CultureInfo>
{
ci,
},
SupportedUICultures = new List<CultureInfo>
{
ci,
}
});
Note: As you can see in NumberFormat.NumberDecimalSeparator I am setting my preferrence for seperator. You are open to use anything you want, any kind of charaters. Please consider the order as well while placing the code in middleware. Best use would be end of your current middleware. As following:
Update for Classic Asp.net 4.8 and Older:
We can configure above steps for asp.net classic project as well. To set the UI culture and culture for all pages, add a globalization section to the Web.config file, and then set the uiculture and culture attributes, as shown in the following example:
<system.web>
<globalization
culture="en-US"/>
</system.web>
Note: More details can be found here in official document.
Output:
Note: For further reference you could check our official document below.
Custom numeric format strings
The "." custom specifier

Why are .NET 6 Application + Application Gateway + Open ID Connect - Path based routing on different app services not working

I have an application gateway set up ("gateway"):
apps.mydomain.com
I have an app service set up ("app"):
my-app-service.azurewebsites.net
The path based rule is set on the listener for on the gateway address above.
/apps/app1/*
The default backend target and settings are set to the root of the gateway address above.
I am using AADS as the authentication store.
Both work correctly independently as I have another route set up on the gateway. I can go to the app service and it will prompt me for credentials, then take me to the index page at the root.
my-app-service.azurewebsites.net/
What I am trying to do is set up a path based rule that routes through the gateway and lands on a path under apps.mydomain.com. For example,
apps.mydomain.com/apps/app1.
I have set up the gateway properly as I can get to a static page. For example,
apps.mydomain.com/apps/app1/somedirectory/mystaticpage.html.
My problem is that when I try to authenticate, I think the signin-oidc is routing the request incorrectly. I am able to authenticate, and it appears to pass back to apps.mydomain.com/apps/app1/signin-oidc and then the middleware passes back to the root. It is authenticating, because when it hits the error page, it shows me as logged in.
I have tried overriding the cookie policy options:
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.Secure = CookieSecurePolicy.SameAsRequest;
options.MinimumSameSitePolicy = SameSiteMode.None;
//options.HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.None;
});
I have tried listening to the OnRedirectToIdentityProvider:
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
//options.CallbackPath = new PathString("/apps/app1/");
//options.CallbackPath = new PathString("/apps/app1/signin-oidc");
//options.CallbackPath = "/apps/app1/signin-oidc";
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = (context) =>
{
//https://stackoverflow.com/questions/50262561/correlation-failed-in-net-core-asp-net-identity-openid-connect
context.Options.NonceCookie.Path = "https://apps.mydomain.com/apps/app1/signin-oidc";
context.Options.CorrelationCookie.Path = "https://apps.mydomain.com/apps/app1/signin-oidc";
//https://learn.microsoft.com/en-us/azure/frontdoor/front-door-http-headers-protocol#front-door-to-backend
context.ProtocolMessage.RedirectUri = "https://apps.mydomain.com/apps/app1/signin-oidc";
return Task.FromResult(0);
}
};
});
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
My guess is that just setting the otions.CallbackPath should work, but I just get correlation or sorry, we cannot log you in errors when I try that. Not sure if there is an error in the library.
I have spent over a month on and off and engaged MS technical support trying to solve this, but have not been able to get this to work. I can't imagine I am the only one doing this. I know it is in the open ID connect middleware somewhere, but cannot find the correct combination.
This is just a demo project in .NET 6 to get this working correctly. Any code will do. If there is actual working code somewhere that would be great. Just need to get the path based routing with authentication to work.

IdentityServer 4, trying to capture traffic with fiddler?

Console application trying to get discovery
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
Works fine, however i'm trying to figure out how this thing works and I cant seem to capture the http traffic.
if i use http://localhost.fiddler to redirect to the local proxy Errors With:
Error connecting to localhost.fiddler:5000/.well-known/openid-configuration: HTTPS required (it's not setup with HTTPS, the error msg is misleading!)
Strangely later in the code when we try to authenticate to web-api with
var response = await client.GetAsync("http://localhost.fiddler:5001/identity");
localhost.fiddler works fine, now this is running in the same console.app, in program.cs so the same file. This is driving me potty why on earth can't I capture traffic going to 5000 it's HTTP!!! so what mysteries are causing this ? is there another way to view the magic http traffic going to and from Identity Server ?
Added Startup class
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
}
}
added Blog, will update it and credit if we can resolve this.
As you correctly figured out, you need to use, for example, http://localhost.fiddler, to route localhost traffic through fiddler. However, using DiscoveryClient.GetAsync uses DiscoveryClient with default policy. That default policy has the following settings important for this case:
RequireHttps = true
AllowHttpOnLoopback = true
So, it requires https unless you query loopback address. How it knows what is loopback address? There is DiscoveryPolicy.LoopbackAddresses property. By default it contains:
"localhost"
"127.0.0.1"
For that reason you have "HTTPS required" error - "localhost.fiddler" is not considered a loopback address, and default policy requires https for non-loopback addresses.
So to fix, you need to either set RequireHttps to false, or add "localhost.fiddler` to loopback address list:
var discoClient = new DiscoveryClient("http://localhost.fiddler:5000");
discoClient.Policy.LoopbackAddresses.Add("localhost.fiddler");
//discoClient.Policy.RequireHttps = false;
var disco = await discoClient.GetAsync();
If you do this - you will see disovery request in fiddler, however it will fail (response will contain error), because server will report authority as "http://localhost:5000" and you query "http://localhost.fiddler:5000". So you also need to override authority in your policy:
var discoClient = new DiscoveryClient("http://localhost.fiddler:5000");
discoClient.Policy.LoopbackAddresses.Add("localhost.fiddler");
discoClient.Policy.Authority = "http://localhost:5000";
var disco = await discoClient.GetAsync();
Now it will work as expected.

ASP.NET Core Reverse Proxy and IdentityOptions Paths

I am running my Kestrel servers behind an IIS Reverse Proxy (.NET Core 1.0.0). It works great, except, certain cases - such as being redirected to a login page upon failed access - results in the user being sent to http://localhost:8080/Account/Login (the address that Kestrel is bound to) instead of http://www.example.net/Account/Login (the reverse proxy address).
I know that I can configure IdentityOptions in Startup.cs, which also includes the ability to set LoginPath, like:
services.Configure<IdentityOptions>(options =>
{
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(1);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
options.Cookies.ApplicationCookie.LoginPath = PathString("/Admin/Login");
});
Unfortunately, I cannot set an absolute path.
I also looked into the possibility to inspect and rewrite the URL per this response, but I feel like this may not be the right way to go, though I don't have any direct reason as to why.
app.Use(async (context, next) =>
{
var baseUri = Configuration["Site:BaseUri"];
if (baseUri.Contains(context.Request.Host.ToString()))
{
await next();
}
else
{
var newUri = $"{context.Request.Scheme}://{baseUri}{context.Request.Pat‌​h}{context.Request.Q‌​ueryString}";
context.Response.Redirect(newUri);
}
});
On top of all of this, I did find this link from the FunnelWeb project which basically looks like what I am wanting to do (although, for an older version of ASP.NET).
I would appreciate any guidance to point me in the right direction.

How to test localized web application?

I work out of New Zealand developing a web application for some Romanian clients. The application should default to ro-RO when viewed by a client using a Romanian machine and en-GB for pretty much everyone else at this stage. Problem is ALL machines I have used to test this are defaulting to en-US. That is, machines on Windows Azure European data centers, local machines here in NZ and various machine in Romania which I access via RDP.
So i use this code in a controller to set language based on user defaults:
public static void OnBeginExecuteCore(Controller controller)
{
if (controller.RouteData.Values[Constants.ROUTE_PARAMNAME_LANG] != null &&
!string.IsNullOrWhiteSpace(controller.RouteData.Values[Constants.ROUTE_PARAMNAME_LANG].ToString()))
{
// set the culture from the route data (url)
var lang = controller.RouteData.Values[Constants.ROUTE_PARAMNAME_LANG].ToString();
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang);
}
else
{
// load the culture info from the cookie
var cookie = controller.HttpContext.Request.Cookies[Constants.COOKIE_NAME];
var langHeader = string.Empty;
if (cookie != null)
{
// set the culture by the cookie content
langHeader = cookie.Value;
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader);
}
else
{
// set the culture by the location if not specified
langHeader = controller.HttpContext.Request.UserLanguages[0];
if (langHeader.ToLower() == "en-us") langHeader = "en-GB";
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader);
}
// set the lang value into route data
controller.RouteData.Values[Constants.ROUTE_PARAMNAME_LANG] = langHeader;
}
// save the location into cookie
HttpCookie cultCookie;
cultCookie = new HttpCookie(Constants.COOKIE_NAME, Thread.CurrentThread.CurrentUICulture.Name)
{
Expires = DateTime.Now.AddYears(1)
};
controller.HttpContext.Response.SetCookie(cultCookie);
}
where
langHeader = controller.HttpContext.Request.UserLanguages[0];
is always en-US. There are in fact 3 entries in this collection however:
but ro is clearly not weighted correctly. This is the same across all machines in all locales.
Globalization in web config is set to auto:
<globalization requestEncoding="utf-8"
culture="auto"
uiCulture="auto"
And regional windows settings are as follows:
Browser:
How can I make this work?
ANSWER
As per Martins answer in comments. Problem was that I had this in apparently all settings the world over.
when what I really wanted was this in Chrome... will get to the other browsers soon.
Ensure that your browser of choice (Internet Explorer, Chrome, Firefox, Safari etc.) has been set up to specify ro as the first language in the User Languages sent over HTTP to the server.
Updating the Windows and/or browser's UI language won't necessarily cause a non-English language ISO code to be sent to the server, which means that you'd just get English returned.
In Firefox, for example, this setting can be found under Options->Content->Languages->Choose.

Categories