I have a multilingual web-forms web application which I am using resource files and a BasePage class which sets the culture based on the QueryString that was included in the page which is inheriting from this class. This is all working well, if a tad clunky as I am having to do this sort of thing for every button which takes the user to a different page to maintain the culture:
if (Thread.CurrentThread.CurrentCulture.ToString() == "cy-GB")
{
return "~/Secure/Details.aspx?lang=cy-GB&PersonId=" + currentPersonId;
}
else
{
return "~/Secure/Details.aspx?PersonId=" + currentPersonId;
}
I knew there was probably a better way of doing this but being a novice as it worked I simply made do.
This was until I had to implement an asp:SiteMapPath control. I initially assumed that I could simply create a resource entry for the url property like I had done for the title:
<siteMapNode
title="$resources:SiteMapLocalizations,HomePageTitle"
description="Home"
url="~$resources:SiteMapLocalizations,HomePageUrl">
However this resulted in a server error:
A potentially dangerous Request.Path value was detected from the client (:).
I've done some reading and I believe I need to somehow store the current culture to a session variable which will follow the user around so when they click 'Home' on the breadcrumb it will be consistent with the culture and grab the appropriate text from the resource files, I'm also hoping this will allow me to remove all of the IF ELSE statements I've had to write to maintain the current language throughout the application.
My question is however, where do I start with this, I cannot find any guide step by step to follow in order to achieve this, can anyone provide some instructions?
Make sure you have a button of some sort which triggers the change of language. In my case I have two versions of the header, one with an English link which will append the Query String to English and one for Welsh, something like:
ASP
<a id="languagelink" runat="server" title="Cymraeg">Cymraeg</a>
C#
if (Thread.CurrentThread.CurrentCulture.ToString() == "en-GB")
{
Uri uri = new Uri(currentPage);
languagelink.HRef = String.Format(uri.GetLeftPart(UriPartial.Path)+"?lang=cy-GB");
}
Every page which requires the language switch needs to inherit from my custom BasePage like so:
Inheritance
public partial class Secure_CustomerSummary : BasePage
Base_Page
public partial class BasePage : System.Web.UI.Page
{
protected override void InitializeCulture()
{
if (Session["language"] == null)
{
Session["language"] = "en-GB";
}
else
{
if (Request.QueryString["lang"] == null)
{
SetSessionCulture();
}
if (Request.QueryString["lang"] != null)
{
string qs = Request.QueryString["lang"];
Session["language"] = qs;
}
SetSessionCulture();
}
SetSessionCulture();
}
private void SetSessionCulture()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Session["language"].ToString());
Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["language"].ToString());
base.InitializeCulture();
}
}
Related
I have a site that uses Angular on the frontend and C# on the backend. I have a c# class that obtains data from a database. I have a new field (spanish translation of the value)I want to add, and am not sure which of the following 3 scenarios would be optimal.
This is what the code currently looks like:
public class CustomerIssueManager
{
static public List<GenericRecordDTO> GetCustomerIssues(MyStore db)
{
List<GenericRecordDTO> responseDTO = new List<GenericRecordDTO>();
try
{
var customerIssues = db.CustomerIssues.Where(m => m.IsActive && m.Name.ToLower() != "none").OrderBy(o => o.Name).ToList();
foreach (var c in customerIssues)
{
GenericRecordDTO issue = new GenericRecordDTO();
issue.ID = c.ID;
issue.Value = c.Name;
responseDTO.Add(issue);
}
}
}
}
public class GenericRecordDTO
{
public int ID { get; set; }
public string Value {get; set; } = "";
}
These are the scenarios I am considering:
Scenario 1:
Is there any significant difference between adding the following to GenericRecordDTO:
public string SpanishValue { get; set; } = "";
Ramifications: There are many classes that use GenericRecordDTO that won't need SpanishValue
Scenario 2:
As opposed to creating another class:
public class GenericRecordTransDTO
and adding SpanishValue to it?
Solves the problem from scenario 1
Scenario 3:
As opposed to keeping GenericRecordDTO.cs as is, but in CustomerIssueManager.cs setting a conditional for spanish site:
if(englishSite) { issue.Value = c.Name; }
else { issue.Value = c.SpanishName; }
Not sure if I can check for Spanish site at this point or if I need to do it later? And are there any drawbacks to checking spanish site here vs later in the TypeScript/Angular?
My question would be, why do this on the front end at all? This requires you to handle localization at two levels, while also sending extra data back to the browser that in many cases you do not need.
For me, I would decide the language server side and load content appropriately. If it is a Spanish client requesting the data, then the Name field would be the Spanish name, English user then an English name, etc ... This has the benefit of handling all of the localization on the server side, at least as far as strings are concerned.
However, it is important to understand, localization is more than just text, so you may still need client side formatting for numbers, dates, etc ... For this, I would recommend using a formatting library that takes locale information, then deliver this information from the server via a configuration payload.
As far as detection of the language server side, this could be done quite a few ways. For example:
You could send an explicit header or variable with your requests instructing it which language to use.
You could use the Accept-Language header sent by the browser to decide which language you would like to use.
You could make it a configuration option that the user can set in their profile, and check a database record for the active user to decide which language you would like to use.
I have a method inside MVC Controller which is called from href inside anchor tag.
public ActionResult DoSomething(string value)
{
if(true)
{
return new RedirectResult("http://google.com");
}
}
when I debug and hit that method Response.Redirect does nothing no exceptions either. any ideas?
Thanks in advance!
Use Redirect
return Redirect("http://www.google.com");
Response.Redirect is not preferred way of doing redirects in asp.net mvc
Response.Redirect and ASP.NET MVC – Do Not Mix
Update: It seems that you are trying to redirect ajax request. If you redirect ajax request, your main page won't be redirected.
There are a few things you need to do here to avoid all these issues.
Starting with the AJAX errors you're getting, they most like relate to the javascript debugger, which Microsoft refer to as "BrowserLink".
If you use Firefox or Chrome, this feature simply doesn't work, which is probably the easiest way to avoid the issue, however you can disable the feature here:
You can change the default browser to run the website in just to the left.
In terms of Response.Redirect, I think that's been well covered, you should use return Redirect() instead, however your code needs to be refactored to allow for that.
Assuming that method is a helper method which is required to be separate from the controller itself, there are a couple of main approaches to doing what you're trying to to do.
1) Magic Values
This could include "redirect1" or also commonly null, and would look something like:
public ActionResult MyAction
{
string data = ProcessString("some data");
if (data == null) { return Redirect("google.com"); }
}
public string ProcessString(string input)
{
if (condition) { return null; }
string output = input + "!"; // or whatever you need to do!
return input;
}
2) Handle via exceptions
Assuming the problem is that the data is in some way bad, and you want to redirect away because you cant process it, Exception handling is most likely the way to go. It also allows for different types of exceptions to be raised by a single method and handled independently without having magic values which then can't be used as normal data.
public ActionResult MyAction
{
string data; // remember this will be null, not "" by default
try
{
data = ProcessString("some data");
}
catch (OwlMisalignedException ex)
{
return RedirectToAction("Index", "Error", new { exData = ex.Code });
}
// proceed with controller as normal
}
public string ProcessString(string input)
{
if (condition)
{
throw new OwlMisalignedException(1234);
// this is (obviously) a made up exception with a Code property
// as an example of passing the error code back up to an error
// handling page, for example.
}
string output = input + "!"; // or whatever you need to do!
return input;
}
By using that approach you can effectively add extra return states to methods without having to fiddle with your return type or create loads of magic values.
Don't use throw Exception - either use one of the more specific types ArgumentException and ArgumentNullException will probably come in handy, or create your own types if needs be.
You'll find info on creating your own Exception types on here easily enough.
I have been using Thread.CurrentThread.CurrentUICulture with System.Threading and System.Globalization, for a while now to manually set the language used by my ASP.net pages, mainly WebForms and WebPages with Razor.
See MSDN: Thread.CurrentThread.CurrentUICulture
I recently read a tutorial that was using Page.UICulture instead (actually, UICulture which appears to be strongly typed). To my surprise I ended up with exactly the same result; they both changed my websites' ui language settings and read the correct resource file.
See MSDN: Page.UICulture
To me, the Thread.CurrentUICulture makes more sense (I say that intuitively, since it's literally "changing the culture of the current thread").
But calling Page.Culture is much easier and doesn't require to call yet another pair of ASP.net using, so I've settled for that solution for now.
Is there a fundamental difference between the two or are they perfectly interchangeable ?
The reason why I worry is that I have a bunch of old websites developed with the first method and I am afraid to run into interchangeability conflicts if I update them to the second one rashly.
Note: I usually focus on UICulture in my line of work and Culture is very accessory to what I do, but I am asking the question for the both of them.
Page.UICulture is a wrapper around Thread.CurrentThread property and is ment for internal .NET framework use:
This property is a shortcut for the CurrentThread property. The culture is a property of the executing thread
This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
Looking at the source code, you can clearly see that:
public string UICulture
{
set
{
CultureInfo newUICulture = null;
if(StringUtil.EqualsIgnoreCase(value, HttpApplication.AutoCulture))
{
CultureInfo browserCulture = CultureFromUserLanguages(false);
if(browserCulture != null)
{
newUICulture = browserCulture;
}
}
else if(StringUtil.StringStartsWithIgnoreCase(value, HttpApplication.AutoCulture))
{
CultureInfo browserCulture = CultureFromUserLanguages(false);
if(browserCulture != null)
{
newUICulture = browserCulture;
}
else
{
try
{
newUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(value.Substring(5));
}
catch {}
}
}
else
{
newUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(value);
}
if (newUICulture != null)
{
Thread.CurrentThread.CurrentUICulture = newUICulture;
_dynamicUICulture = newUICulture;
}
}
get { return Thread.CurrentThread.CurrentUICulture.DisplayName; }
}
They do exactly the same thing.
As you can see on the documentation page:
This property is a shortcut for the CurrentThread property. The culture is a property of the executing thread
I am trying to finalize a C# / XAML page and am running into trouble. Basically, when I try to compile it is complaining that the name of the variable (Courier_List) does not exist in the current context. I understand by concept why as it has not been declared yet anywhere in the code. However, the reason I have not declared it is because this packaged .dll is meant to work with a management pack (XML file) that contains that definition there (Courier_List) defined as a list and contains the coordinates instructing the visual compiler where to place the list on the form.
I am guessing the solution must be to declare the list variable in the form... but I am not sure how (and if it will work) to just declare the variable and not use it anywhere within the .dll, then when everything is put together it will call the Courier_List from the management pack and not get confused between the two same name variables.
My description may be confusing as it was hard to explain this, so if anyone needs clarification please let me know. I have included the code below:
[assembly: CLSCompliant(true)]
namespace Flexity.RMA
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
class RMATask : CreateWithLinkHandler
{
public RMATask()
{
try
{
// Sealed Class GUID
this.createClassGuid = new Guid("9ebd95da-1b16-b9ea-274d-6b0c16ce1bf3");
this.classToDelegate = new Dictionary<Guid, CreateLinkHelperCallback>()
{
{ ApplicationConstants.WorkItemTypeId, new CreateLinkHelperCallback (this.WorkItemCallback) }
};
}
catch (Exception exc1)
{
MessageBox.Show(exc1.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void WorkItemCallback(IDataItem RMAForm, IDataItem IncidentForm)
{
try
{
// Note to self: RelatedWorkItems should be in MP XML as alias under TypeProjections
if (RMAForm != null && RMAForm.HasProperty("RelatedWorkItems"))
{
// Perform Linking
RMAForm["RelatedWorkItems"] = IncidentForm;
// Copy Incident Title to RMA Title
RMAForm["Title"] = IncidentForm["Title"];
// Copy Incident Description to RMA Description
RMAForm["Description"] = IncidentForm["Description"];
// Copy Incident ID to RMA Display Name
RMAForm["DisplayName"] = "From " + IncidentForm["Id"];
}
}
catch (Exception exc2)
{
MessageBox.Show(exc2.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
public partial class WITemplate: UserControl
{
private readonly RelatedItemsPane _relatedItemsPane;
public WITemplate()
{
InitializeComponent();
var paneConfig = new WorkItemRelatedItemsConfiguration("RelatedWorkItems", "RelatedWorkItemSource",
"RelatedConfigItems", "RelatedKnowledgeArticles",
"FileAttachments");
_relatedItemsPane = new RelatedItemsPane(paneConfig);
tabItemRelItems.Content = _relatedItemsPane;
}
private void Tracking_Button_Click(object sender, RoutedEventArgs e)
{
switch (Courier_List.SelectedValue.ToString())
{
case "UPS":
System.Diagnostics.Process.Start("http://wwwapps.ups.com/ietracking/tracking.cgi?loc=CA_CA^&tracknum^=" + Tracking_Num.Text.ToString());
break;
case "FedEX":
System.Diagnostics.Process.Start("https://www.fedex.com/fedextrack/index.html?tracknumbers^="+Tracking_Num.Text.ToString()+"^&locale=en_CA^&cntry_code=ca_english");
break;
case "UPS SCS":
System.Diagnostics.Process.Start("https://www.upspostsaleslogistics.com/cfw/trackOrder.do?trackNumber^=" + Tracking_Num.Text.ToString());
break;
default:
break;
}
}
}
}
I think you're correct about the obvious solution. Your button click handler doesn't know about the contents of the management pack XML unless you explicitly connect them.
So, you will need to create a variable for use in your Tracking_Button_Click handler for that switch statement. This is a pretty common pattern; if there is a resource somewhere that is needed in C# code you have to have a line or two of code that looks up the resource and assigns it to a variable you declare.
Done correctly, you will not be duplicating data. Rather, the system will set a reference to the existing classes. That in turn will permit you to use the management pack XML in the C# code.
I don't have examples for your management pack, but here are a couple others which follow the pattern. If you want to get at a XAML resource, you do something like:
var myList = (XAMLResourceType) this.TryFindResource("myResourceKey");
You don't need exactly this, but you need something very similar, in the code in your handler. Then your switch statement will work.
I'm using a WebBrowser control to automate management of a web page. When I start my WPF application, it shows the webpage ant lets me login. Then my application starts to do some automated tasks by going to a page, filling a form and submitting (it’s a POST-form). It submits the same form ~100 times with different values.
Right now my code is as follows:
void webBrowser1_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var doc = (HTMLDocument) webBrowser1.Document;
var form = doc.getElementById("theForm");
SetValueOfFormInput(doc, "id", Foo.ID);
SetValueOfFormInput(doc, "item1", Foo.Item1);
SetValueOfFormInput(doc, "item2", Foo.Item2);
form.all.item("submit").click();
}
private static void SetValueOfFormInput(HTMLDocument doc, string name, string value)
{
var item = doc.all.item(name);
item.setAttribute("value", value);
}
Can I do this on a better way and can I do it in a MVVM way?
And no, I can't modify the the webpage to do the management easier :-(
Edit:
Ideally, I would be able to do this without having to use the WebBrowser control. The program logon to the website and performs all tasks without having to modify the forms in the html pages
Why not using the WebClient or WebRequest classes?
For the webclient, you can use the UploadValues method which will do exactly what you want (http://msdn.microsoft.com/en-us/library/9w7b4fz7.aspx) and you can also simply addapt the class to use cookies so your login will be "permanent" (http://stackoverflow.com/questions/1777221/c-using-cookiecontainer-with-webclient-class)
If you like to do it even more model driven, i would use the WebRequest (has allready a cookiecontainer) and have some class with the needed data. This one would derive from a class, which can serialize all needed properties into a simple string you would post to the server - AFAIK it's same like the getter-parameters (param1=val1¶m2=val2&...)
so basically:
class Data : Postable { public string Param1{get;set;} public string Param2{get;set;} ...}
class Postable
{
public override string ToString()
{
StringBuilder ret = new StringBuilder();
foreach(Property p in GetType().GetProperties())
{
ret.Append("{0}={1}&", p.Name, p.<GetValue>);
}
return ret.ToString();
}
}