Cannot get localization working in MVC 4 - c#

I've been trying to follow the blog post found here. I've added a new assembly that hosts my resource files (I used a separate assembly as the resources may need to be shared between multiple projects). I have added the following to my web.config:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="MyResources.Resources"/> <!-- New entry for resources -->
</namespaces>
</pages>
</system.web.webPages.razor>
And I have gone though and added resource strings to a few files for testing purposes. Now the problem that I seem to be running into, is that I cannot set the resource to be anything other than the default. So for example, in the generated resource file designer there is the following:
/// <summary>
/// Looks up a localized string similar to Log in was unsuccessful. Please correct the errors and try again..
/// </summary>
public static string Account_LoginUnsuccessful {
get {
return ResourceManager.GetString("Account_LoginUnsuccessful", resourceCulture);
}
}
If I set a breakpoint in this method, resourceCulture is NEVER anything but null. Even though I have tried the following:
In Global.asax.ca:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
var culture = new System.Globalization.CultureInfo("fr");
// Modify current thread's cultures
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture.Name);
} // End of Application_AcquireRequestState
In a base mvc controller that all of my other controller inherit:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
SetCulture(requestContext.HttpContext.Request);
base.Initialize(requestContext);
}
protected override void ExecuteCore()
{
SetCulture(Request);
base.ExecuteCore();
}
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
SetCulture(requestContext.HttpContext.Request);
base.Execute(requestContext);
}
protected override IAsyncResult BeginExecute(System.Web.Routing.RequestContext requestContext, AsyncCallback callback, object state)
{
SetCulture(requestContext.HttpContext.Request);
metrics = Metrics.BeginTimer();
return base.BeginExecute(requestContext, callback, state);
}
private void SetCulture(HttpRequestBase Request)
{
string cultureName = "fr";
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
Now, to my understanding setting the threading current culture should be causing my resource files culture to change. I can't seem to get this working of the life of me (hence why I have tried setting the cultire in about ten different locations).
Any suggestions on what I am doing wrong here?

Just to verify, try setting the language in a ActionFilterAttribute:
public class ChangeLanguageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(
ActionExecutingContext filterContext)
{
string languageCode = "fr";
CultureInfo info =
CultureInfo.CreateSpecificCulture(languageCode.ToString());
Thread.CurrentThread.CurrentCulture = info;
Thread.CurrentThread.CurrentUICulture = info;
}
}
This is the exact code Im using, so I know this works.

this is the code i came up with, it should be on Application_OnBeginRequest :
public void Application_OnBeginRequest(object sender, EventArgs e)
{
System.Globalization.CultureInfo NC = new System.Globalization.CultureInfo(1036, true);
NC.NumberFormat.CurrencyDecimalDigits = 2;
NC.NumberFormat.CurrencySymbol = "euro";
NC.NumberFormat.CurrencyDecimalSeparator = ".";
NC.NumberFormat.PercentDecimalSeparator = ".";
NC.NumberFormat.NumberDecimalSeparator = ".";
NC.NumberFormat.CurrencyGroupSeparator = "";
NC.NumberFormat.PercentGroupSeparator = "";
NC.NumberFormat.NumberGroupSeparator = "";
System.Threading.Thread.CurrentThread.CurrentCulture = NC;
}

Related

Explain some code about dynamic connection string

So, I'm doing a website that does a lot of things and one of them is, doing a dynamic connection string... I already did it, but because I took the code from the internet, I'm kinda lost, so I was hoping that somebody could help and explain how it works and what each thing does...
Here's the code:
protected void Page_Load(object sender, EventArgs e)
{
AddUpdateConnectionString("ConString");
}
void AddUpdateConnectionString(string name)
{
bool isNew = false;
string path = Server.MapPath("~/Web.Config");
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList list = doc.DocumentElement.SelectNodes(string.Format("connectionStrings/add[#name='{0}']", name));
XmlNode node;
isNew = list.Count == 0;
if (isNew)
{
node = doc.CreateNode(XmlNodeType.Element, "add", null);
XmlAttribute attribute = doc.CreateAttribute("name");
attribute.Value = name;
node.Attributes.Append(attribute);
attribute = doc.CreateAttribute("connectionString");
attribute.Value = "";
node.Attributes.Append(attribute);
attribute = doc.CreateAttribute("providerName");
attribute.Value = "System.Data.SqlClient";
node.Attributes.Append(attribute);
}
else
{
node = list[0];
}
string conString = node.Attributes["connectionString"].Value;
SqlConnectionStringBuilder conStringBuilder = new SqlConnectionStringBuilder(conString);
conStringBuilder.InitialCatalog = TxtBaseDeDados.Text;
conStringBuilder.DataSource = TxtHost.Text;
conStringBuilder.IntegratedSecurity = false;
conStringBuilder.UserID = TxtUtilizador.Text;
conStringBuilder.Password = TxtPalavraPasse.Text;
node.Attributes["connectionString"].Value = conStringBuilder.ConnectionString;
if (isNew)
{
doc.DocumentElement.SelectNodes("connectionStrings")[0].AppendChild(node);
}
doc.Save(path);
}
protected void Button1_Click(object sender, EventArgs e)
{
AddUpdateConnectionString("ConString");
}
If you are wanting to load a connection string from the web.config file I would encourange you to use the ConfigurationManager class like this:
ConfigurationManager.ConnectionStrings["WingtipToys"].ConnectionString
WingtipToys would be stored like this in web.config
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="WingtipToys" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=WingtipToys;Integrated Security=True;Pooling=False" />
</connectionStrings>
Here is more info: https://learn.microsoft.com/en-us/dotnet/api/system.configuration.configurationmanager?view=netframework-4.8
It creates or updates the setting in your web.config file used to store the details of how to connect to your back-end database. Config files are XML documents (which are laid out in hierarchical format), so the code finds the config, finds the right section inside of the config (creating it if it's not there), constructs a new connection string, stores it in the XML and saves the changes.

C# How do I modify configuration file of another application and save the change?

I know similar question was asked before more than once. I read some of the answers yet didn't find a clear one for my issue. To the point, I two applications say A & B. App A has a configuration file as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key = "Key0" value = "4567" />
<add key = "Key1" value = "1" />
<add key = "Key2" value = "2" />
</appSettings>
</configuration>
App B tries to modify "Key0" of App A configuration file:
namespace ModifyOtherConfig
{
public partial class Form1 : Form
{
string otherConfigFilePath;
public Form1()
{
InitializeComponent();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = #"c:\users\om606\documents\visual studio 2015\projects\csharptesting\csharptesting\bin\debug\csharptesting.exe";
Configuration otherConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
string otherSetting = otherConfig.AppSettings.Settings["Key0"].Value;
MessageBox.Show(otherSetting);
otherSetting = "098";
MessageBox.Show(otherSetting);
otherConfig.SaveAs(fileMap.ExeConfigFilename, ConfigurationSaveMode.Full);
}
}
}
When I try to run this code I get the following error:
An unhandled exception of type 'System.Configuration.ConfigurationErrorsException' occurred in System.Configuration.dll
Additional information: Data at the root level is invalid. Line 1, position 1.
What do I do wrong? Do I miss something very obvious? I'd appreciate if someone could point me in the right direction.
Oh, you're pointing your fileMap.ExeConfigFilename to the .exe, change it to point to the .config file instead. That's why you are seeing the xml error.
fileMap.ExeConfigFilename = #"c:\users\om606\documents\visual studio 2015\projects\csharptesting\csharptesting\bin\debug\csharptesting.exe.config";
for your other issue, do:
otherConfig.AppSettings.Settings.Remove("Key0");
otherConfig.AppSettings.Settings.Add("Key0", "098");
then save it.

Is there a way to write to a Custom app.Config Configuration from code

So far I have:
<section name="PinnedPhotos" type="PhotoViewer.PinnedPhotos, PhotoViewer" allowLocation="true" allowDefinition="Everywhere"/>
<PinnedPhotos>
<add location="Location1.jpg"/>
<add location="Location2.jpg"/>
</PinnedPhotos>
in my app.Config
and in my Code I have:
PinnedPhotos config = (PinnedPhotos)System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location).Sections["PinnedPhotos"];
But I would like to update and save config from code e.g. Adding more photos to be pinned to the existing list. Is there a way to do this?
EDIT
var isReadOnly = config.Photos.IsReadOnly();
returns False... So I guess there should be a way to write to this collection?
Got it:
I needed to add the two Methods to my Collection:
public void Add(string location)
{
PhotoElement pe = new PhotoElement(location);
BaseAdd(pe);
}
public void Remove(string location)
{
BaseRemove(location);
}
and then It was just a Case of calling:
config.CurrentConfiguration.Save();

WSE 3.0 and SoapExtensions

I'm trying to consume an Axis web service with a .NET client and I'm having some trouble setting up the WSE configuration to work with it. I know that WSE 3.0 is an outdated technology, but I'm stuck with a VS2005 and .NET 2.0 environment, so I'll have to work with this.
Currently I've created a new ASP.NET Website application and enabled WSE on it. It generages a bunch of sections like the WS:Addressing and WS:Timestamp sections from it that the server cannot handle and I'm looking to remove them. I couldn't find a config setting to do it, so after some searching on SO, I've started working with SoapExtensions to intercept the message and remove the sections manually.
My problem currently seems to be that the code in the SoapExtensions isn't getting executed at all. Here's my web.config -
<configuration>
<configSections>
<section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<appSettings>
<add key="WebSvc.SecureService" value="<Trimmed>" />
</appSettings>
<connectionStrings />
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<authentication mode="Windows" />
<webServices>
<soapExtensionImporterTypes>
<add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</soapExtensionImporterTypes>
<soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</webServices>
</system.web>
<microsoft.web.services3>
<security>
<x509 verifyTrust="false" />
<defaultTtlInSeconds value="0" />
<timeToleranceInSeconds value="0" />
</security>
<diagnostics>
<trace enabled="true" input="InputTrace.webinfo" output="OutputTrace.webinfo" />
</diagnostics>
<policy fileName="wse3policyCache.config" />
</microsoft.web.services3>
</configuration>
And my web service method -
[WebMethod]
[TestApplication.TraceExtensionAttribute]
public void SendTestMessage()
{
WebSvc.B2BSecureServiceServiceWse svcClient = new WebSvc.B2BSecureServiceServiceWse();
svcClient.SetPolicy("Policy1");
WebSvc.B2BRequest request = new WebSvc.B2BRequest();
WebSvc.B2BRequestHeader WebSvc= new WebSvc.B2BRequestHeader();
// Set Request header properties
request.header = requestHeader;
request.msgPayload = ""; // Text removed
try
{
WebSvc.Response response = svcClient.processRequest(request);
}
catch (Exception ex)
{
}
}
And here's my SoapExtension Class -
public class Snoop : SoapExtension
{
Stream oldStream;
Stream newStream;
string filename;
// Save the Stream representing the SOAP request or SOAP response into
// a local memory buffer.
public override Stream ChainStream(Stream stream)
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
// When the SOAP extension is accessed for the first time, the XML Web
// service method it is applied to is accessed to store the file
// name passed in, using the corresponding SoapExtensionAttribute.
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return ((TraceExtensionAttribute)attribute).Filename;
}
// The SOAP extension was configured to run using a configuration file
// instead of an attribute applied to a specific XML Web service
// method.
public override object GetInitializer(Type WebServiceType)
{
// Return a file name to log the trace information to, based on the
// type.
return "C:\\" + WebServiceType.FullName + ".log";
}
// Receive the file name stored by GetInitializer and store it in a
// member variable for this specific instance.
public override void Initialize(object initializer)
{
filename = (string)initializer;
}
// If the SoapMessageStage is such that the SoapRequest or
// SoapResponse is still in the SOAP format to be sent or received,
// save it out to a file.
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
WriteOutput(message);
break;
case SoapMessageStage.BeforeDeserialize:
WriteInput(message);
break;
case SoapMessageStage.AfterDeserialize:
break;
}
}
public void WriteOutput(SoapMessage message)
{
newStream.Position = 0;
FileStream fs = new FileStream(filename, FileMode.Append,
FileAccess.Write);
StreamWriter w = new StreamWriter(fs);
string soapString = (message is SoapServerMessage) ? "SoapResponse" : "SoapRequest";
w.WriteLine("-----" + soapString + " at " + DateTime.Now);
w.Flush();
Copy(newStream, fs);
w.Close();
newStream.Position = 0;
Copy(newStream, oldStream);
}
public void WriteInput(SoapMessage message)
{
Copy(oldStream, newStream);
FileStream fs = new FileStream(filename, FileMode.Append,
FileAccess.Write);
StreamWriter w = new StreamWriter(fs);
string soapString = (message is SoapServerMessage) ?
"SoapRequest" : "SoapResponse";
w.WriteLine("-----" + soapString +
" at " + DateTime.Now);
w.Flush();
newStream.Position = 0;
Copy(newStream, fs);
w.Close();
newStream.Position = 0;
}
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
}
// Create a SoapExtensionAttribute for the SOAP Extension that can be
// applied to an XML Web service method.
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private string filename = "c:\\log.txt";
private int priority;
public override Type ExtensionType
{
get { return typeof(Snoop); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
public string Filename
{
get
{
return filename;
}
set
{
filename = value;
}
}
}
I'm guessing I'm doing something wrong while trying to assign the SoapExtension to that method call, so any help is much appreciated!
For anyone who comes across this problem, here's how I've solved it using SoapFilters. Here's the process from MSDN - http://msdn.microsoft.com/en-us/library/aa528788.aspx

How to get the values of a ConfigurationSection of type NameValueSectionHandler

I'm working with C#, Framework 3.5 (VS 2008).
I'm using the ConfigurationManager to load a config (not the default app.config file) into a Configuration object.
Using the Configuration class, I was able to get a ConfigurationSection, but I could not find a way to get the values of that section.
In the config, the ConfigurationSection is of type System.Configuration.NameValueSectionHandler.
For what it worth, when I used the method GetSection of the ConfigurationManager (works only when it was on my default app.config file), I received an object type, that I could cast into collection of pairs of key-value, and I just received the value like a Dictionary. I could not do such cast when I received ConfigurationSection class from the Configuration class however.
EDIT:
Example of the config file:
<configuration>
<configSections>
<section name="MyParams"
type="System.Configuration.NameValueSectionHandler" />
</configSections>
<MyParams>
<add key="FirstParam" value="One"/>
<add key="SecondParam" value="Two"/>
</MyParams>
</configuration>
Example of the way i was able to use it when it was on app.config (the "GetSection" method is for the default app.config only):
NameValueCollection myParamsCollection =
(NameValueCollection)ConfigurationManager.GetSection("MyParams");
Console.WriteLine(myParamsCollection["FirstParam"]);
Console.WriteLine(myParamsCollection["SecondParam"]);
Suffered from exact issue. Problem was because of NameValueSectionHandler in .config file. You should use AppSettingsSection instead:
<configuration>
<configSections>
<section name="DEV" type="System.Configuration.AppSettingsSection" />
<section name="TEST" type="System.Configuration.AppSettingsSection" />
</configSections>
<TEST>
<add key="key" value="value1" />
</TEST>
<DEV>
<add key="key" value="value2" />
</DEV>
</configuration>
then in C# code:
AppSettingsSection section = (AppSettingsSection)ConfigurationManager.GetSection("TEST");
btw NameValueSectionHandler is not supported any more in 2.0.
Here's a good post that shows how to do it.
If you want to read the values from a file other than the app.config, you need to load it into the ConfigurationManager.
Try this method: ConfigurationManager.OpenMappedExeConfiguration()
There's an example of how to use it in the MSDN article.
Try using an AppSettingsSection instead of a NameValueCollection. Something like this:
var section = (AppSettingsSection)config.GetSection(sectionName);
string results = section.Settings[key].Value;
Source:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d5079420-40cb-4255-9b3b-f9a41a1f7ad2/
The only way I can get this to work is to manually instantiate the section handler type, pass the raw XML to it, and cast the resulting object.
Seems pretty inefficient, but there you go.
I wrote an extension method to encapsulate this:
public static class ConfigurationSectionExtensions
{
public static T GetAs<T>(this ConfigurationSection section)
{
var sectionInformation = section.SectionInformation;
var sectionHandlerType = Type.GetType(sectionInformation.Type);
if (sectionHandlerType == null)
{
throw new InvalidOperationException(string.Format("Unable to find section handler type '{0}'.", sectionInformation.Type));
}
IConfigurationSectionHandler sectionHandler;
try
{
sectionHandler = (IConfigurationSectionHandler)Activator.CreateInstance(sectionHandlerType);
}
catch (InvalidCastException ex)
{
throw new InvalidOperationException(string.Format("Section handler type '{0}' does not implement IConfigurationSectionHandler.", sectionInformation.Type), ex);
}
var rawXml = sectionInformation.GetRawXml();
if (rawXml == null)
{
return default(T);
}
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(rawXml);
return (T)sectionHandler.Create(null, null, xmlDocument.DocumentElement);
}
}
The way you would call it in your example is:
var map = new ExeConfigurationFileMap
{
ExeConfigFilename = #"c:\\foo.config"
};
var configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var myParamsSection = configuration.GetSection("MyParams");
var myParamsCollection = myParamsSection.GetAs<NameValueCollection>();
This is an old question, but I use the following class to do the job. It's based on Scott Dorman's blog:
public class NameValueCollectionConfigurationSection : ConfigurationSection
{
private const string COLLECTION_PROP_NAME = "";
public IEnumerable<KeyValuePair<string, string>> GetNameValueItems()
{
foreach ( string key in this.ConfigurationCollection.AllKeys )
{
NameValueConfigurationElement confElement = this.ConfigurationCollection[key];
yield return new KeyValuePair<string, string>
(confElement.Name, confElement.Value);
}
}
[ConfigurationProperty(COLLECTION_PROP_NAME, IsDefaultCollection = true)]
protected NameValueConfigurationCollection ConfCollection
{
get
{
return (NameValueConfigurationCollection) base[COLLECTION_PROP_NAME];
}
}
The usage is straightforward:
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
NameValueCollectionConfigurationSection config =
(NameValueCollectionConfigurationSection) configuration.GetSection("MyParams");
NameValueCollection myParamsCollection = new NameValueCollection();
config.GetNameValueItems().ToList().ForEach(kvp => myParamsCollection.Add(kvp));
Here are some examples from this blog mentioned earlier:
<configuration>
<Database>
<add key="ConnectionString" value="data source=.;initial catalog=NorthWind;integrated security=SSPI"/>
</Database>
</configuration>
get values:
NameValueCollection db = (NameValueCollection)ConfigurationSettings.GetConfig("Database");
labelConnection2.Text = db["ConnectionString"];
-
Another example:
<Locations
ImportDirectory="C:\Import\Inbox"
ProcessedDirectory ="C:\Import\Processed"
RejectedDirectory ="C:\Import\Rejected"
/>
get value:
Hashtable loc = (Hashtable)ConfigurationSettings.GetConfig("Locations");
labelImport2.Text = loc["ImportDirectory"].ToString();
labelProcessed2.Text = loc["ProcessedDirectory"].ToString();
Try this;
Credit: https://www.limilabs.com/blog/read-system-net-mailsettings-smtp-settings-web-config
SmtpSection section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp");
string from = section.From;
string host = section.Network.Host;
int port = section.Network.Port;
bool enableSsl = section.Network.EnableSsl;
string user = section.Network.UserName;
string password = section.Network.Password;
This works like a charm
dynamic configSection = ConfigurationManager.GetSection("MyParams");
var theValue = configSection["FirstParam"];

Categories

Resources