Using .resx file in Azure Function App - c#

I am creating a new webhook C# function in Azure that I wish to return fixed content in different translations depending on either an incoming lang query parameter or the Accept-Language header.
For storing the different translations I naturally think of .resx files. Is there a way to utilize .resx files in Azure Function Apps?

It doesn't look like resource files are supported properly yet.
I worked around by reading the embedded resource file(s) into a resource set.
var culture = CultureInfo.CurrentUICulture;
var resourceName = $"FunctionApp.Properties.Resources.{culture.TwoLetterISOLanguageName}.resources";
var cultureResourceSet = new ResourceSet(Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName));
var localizedString = cultureResourceSet.GetString(resourceKey);
// fallback to default language if not found

Provided answer did not help me so I've done small wrapper
public static class ResourceWrapper
{
private static Dictionary<string, ResourceSet> _resourceSets = new Dictionary<string, ResourceSet>();
static ResourceWrapper()
{
_resourceSets.Add("uk", Load("uk"));
_resourceSets.Add("ru", Load("ru"));
_resourceSets.Add("en", Emails.ResourceManager.GetResourceSet(CultureInfo.InvariantCulture, false, false));
}
private static ResourceSet Load(string lang)
{
var asm = System.Reflection.Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, "bin", lang, "Function.App.resources.dll"));
var resourceName = $"Function.App.Resources.Emails.{lang}.resources";
var tt = asm.GetManifestResourceNames();
return new ResourceSet(asm.GetManifestResourceStream(resourceName));
}
public static string GetString(string key)
{
return _resourceSets[CultureInfo.CurrentUICulture.TwoLetterISOLanguageName].GetString(key);
}
}

this was my solution:
First i do this:
public void SetLanguage(FunctionRequestDTO data)
{
if (string.IsNullOrWhiteSpace(data.LanguageSetting))
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
}
else
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(data.LanguageSetting);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(data.LanguageSetting);
}
ResourceWrapper.Load(Thread.CurrentThread.CurrentCulture.Name.ToLower());
}
Then:
public static class ResourceWrapper
{
private static Dictionary<string, ResourceSet> ResourceSets = new Dictionary<string, ResourceSet>();
private const string DEFAULT_LANGUAGE_VALUE = "default";
static ResourceWrapper()
{
try
{
ResourceSets.Add(DEFAULT_LANGUAGE_VALUE, new ResourceSet(Assembly.GetExecutingAssembly().GetManifestResourceStream("Function.Logic.Resources.Resource.resources")));
}
catch { }
}
public static void Load(string lang)
{
if (string.IsNullOrEmpty(lang) || ResourceSets.ContainsKey(lang))
{
return;
}
lock (new object())
{
if (ResourceSets.ContainsKey(lang))
{
return;
}
try
{
string rootPath = Environment.CurrentDirectory;
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HOME")))
{
rootPath = Environment.GetEnvironmentVariable("HOME") + "\\site\\wwwroot\\";
}
var asm = Assembly.LoadFrom(Path.Combine(rootPath, "bin", lang, "Function.Logic.resources.dll"));
var resourceName = $"Function.Logic.Resources.Resource.{lang}.resources";
ResourceSets.Add(lang, new ResourceSet(asm.GetManifestResourceStream(resourceName)));
}
catch { }
}
}
public static string GetString(string key)
{
string value = "";
try
{
string language = System.Threading.Thread.CurrentThread.CurrentCulture.Name.ToLower();
if (string.IsNullOrEmpty(language))
{
language = DEFAULT_LANGUAGE_VALUE;
}
if (ResourceSets.ContainsKey(language))
{
value = ResourceSets[language].GetString(key);
}
}
catch { }
return value ?? "";
}

Related

Refer multiple Resource Dictionaries in the UWP project

My UWP app has a resource dictionary used for localization named "Resources.resx" and now I want to add another "ResourcesXaml.resx". I want to know how to access both files like merged.
The code is below. I want to use the same Get(string key) method and access any resource in both files. Appreciate it if anyone can point out the change I need to make. Cheers!
static ResourceHandler()
{
const string selectedLanguage = "en";
Context = ResourceContext.GetForCurrentView();
var lang = new List<string> { selectedLanguage };
Context.Languages = lang;
ResourceStringMap = ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
}
public static string Get(string key)
{
return ResourceStringMap.GetValue(key, Context).ValueAsString;
}
You could create two ResourceMaps and look up the key in the second one if the lookup in the first one fails, e.g.:
public static class ResourceHandler
{
private const string SelectedLanguage = "en";
private static readonly ResourceContext s_resourceContext =
new ResourceContext() { Languages = new string[1] { SelectedLanguage } };
private static readonly ResourceMap s_resourcesMap =
ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
private static readonly ResourceMap s_resourcesXamlMap =
ResourceManager.Current.MainResourceMap.GetSubtree("ResourcesXaml");
public static string Get(string key)
{
string s = s_resourcesMap.GetValue(key, s_resourceContext).ValueAsString;
if (!string.IsNullOrEmpty(s))
return s;
return s_resourcesXamlMap.GetValue(key, s_resourceContext).ValueAsString;
}
}

Accessing a Json array as string array

I have this code which reads from my json file an array of words
public static string[] GetProfanity()
{
var json = string.Empty;
using (var fs = File.OpenRead("profanity.json"))
using (var sr = new StreamReader(fs, new UTF8Encoding(false)))
json = sr.ReadToEnd();
var profanityJson = JsonConvert.DeserializeObject<ProfanityJson>(json);
return profanityJson.badwords;
}
This is the json
{
"badwords" : ["bad", "stupid"]
}
And i try to access this here
public static bool ProfanityCheck(string inputString)
{
string[] badWords = GetProfanity();
string checkString = inputString.ToLower();
if (badWords.Any(checkString.Contains))
return true;
return false;
}
As requested I access the ProfanityCheck method here
[Command("echo")]
[Description("says whatever the user gives")]
public async Task Echo(CommandContext ctx, [RemainingText] string echoText)
{
bool hasProfanity = ProfanityFilter.ProfanityCheck(echoText);
if(hasProfanity)
{
var errMsg = ProfanityFilter.ErrorMessage();
var errSent = await ctx.Channel.SendMessageAsync(embed: errMsg).ConfigureAwait(false);
Thread.Sleep(3000);
await ctx.Channel.DeleteMessageAsync(errSent).ConfigureAwait(false);
await ctx.Channel.DeleteMessageAsync(ctx.Message).ConfigureAwait(false);
return;
}
await ctx.Channel.SendMessageAsync(echoText).ConfigureAwait(false);
}
and the struct I Deserialize it as
public struct ProfanityJson
{
[JsonProperty("badwords")]
public string[] badwords { get; private set; }
}
but when i attempt to search for this any bad words in a string I pass, nothing happens, no errors in the console, no output otherwise. I have it set up so that it sends me an error message when profanity is found, but in its current state it does nothing when profanity is passed
Your code seems to be correct... I would write the GetProfanity() in another way (and I wouldn't surely reread it every time a word is passed to to ProfanityCheck) but this is tangential to your problem. I've written a minimum testable example:
public class ProfanityJson
{
public string[] badwords { get; set; }
}
public static class ProfanityChecker
{
public static string[] GetProfanity()
{
var json = string.Empty;
using (var fs = File.OpenRead("profanity.json"))
using (var sr = new StreamReader(fs, new UTF8Encoding(false)))
json = sr.ReadToEnd();
var profanityJson = JsonConvert.DeserializeObject<ProfanityJson>(json);
return profanityJson.badwords;
}
public static string[] GetProfanity2()
{
using (var sr = new StreamReader("profanity.json"))
using (var jtr = new JsonTextReader(sr))
{
var ser = new JsonSerializer();
var profanityJson = ser.Deserialize<ProfanityJson>(jtr);
return profanityJson.badwords;
}
}
public static bool ProfanityCheck(string inputString)
{
string[] badWords = GetProfanity2();
Trace.WriteLine($"Loaded {badWords.Length} bad words");
string checkString = inputString.ToLower();
if (badWords.Any(checkString.Contains))
return true;
return false;
}
}
static void Main(string[] args)
{
Console.WriteLine(ProfanityChecker.ProfanityCheck("badder"));
}
So the only idea I have is that you are using a "stale" version of profanity.json. I've added a little loggin in the ProfanityCheck() method. It will go to the Output pane in Visual Studio.
(Would be a mess as a comment)
You could have your class like this:
public class ProfanityJson
{
[JsonProperty("badwords")]
public string[] Badwords { get; set; }
}
Is it like so? Json is case sensitive.

CefSharp custom SchemeHandler

Iam using CefSharp's SchemeHandler in order to grab resources from my C# project like .css, .js or .png files using a custom url for example custom://cefsharp/assets/css/style.css
I've 2 custom classes in order to archive this.
First class, MyCustomSchemeHandlerFactory will be the one that handles the custom Scheme and it looks like this, where "custom" will be the custom scheme:
internal class MyCustomSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "custom";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new MyCustomSchemeHandler();
}
}
The next class I've implemented is MyCustomSchemeHandler which will receive the call and output a response and it looks like this:
internal class MyCustomSchemeHandler : IResourceHandler
{
private static readonly IDictionary<string, string> ResourceDictionary;
private string mimeType;
private MemoryStream stream;
static MyCustomSchemeHandler()
{
ResourceDictionary = new Dictionary<string, string>
{
{ "/home.html", Properties.Resources.index},
{ "/assets/css/style.css", Properties.Resources.style}
};
}
public Stream Stream { get; set; }
public int StatusCode { get; set; }
public string StatusText { get; set; }
public string MimeType { get; set; }
public NameValueCollection Headers { get; private set; }
public Stream GetResponse(IResponse response, out long responseLength, out string redirectUrl)
{
redirectUrl = null;
responseLength = -1;
response.MimeType = MimeType;
response.StatusCode = StatusCode;
response.StatusText = StatusText;
response.ResponseHeaders = Headers;
var memoryStream = Stream as MemoryStream;
if (memoryStream != null)
{
responseLength = memoryStream.Length;
}
return Stream;
}
public bool ProcessRequestAsync(IRequest request, ICallback callback)
{
// The 'host' portion is entirely ignored by this scheme handler.
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
string resource;
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
var resourceHandler = ResourceHandler.FromString(resource);
stream = (MemoryStream)resourceHandler.Stream;
var fileExtension = Path.GetExtension(fileName);
mimeType = ResourceHandler.GetMimeType(fileExtension);
callback.Continue();
return true;
}
else
{
callback.Dispose();
}
return false;
}
void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
{
responseLength = stream == null ? 0 : stream.Length;
redirectUrl = null;
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusText = "OK";
response.MimeType = mimeType;
}
bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback)
{
//Dispose the callback as it's an unmanaged resource, we don't need it in this case
callback.Dispose();
if (stream == null)
{
bytesRead = 0;
return false;
}
//Data out represents an underlying buffer (typically 32kb in size).
var buffer = new byte[dataOut.Length];
bytesRead = stream.Read(buffer, 0, buffer.Length);
dataOut.Write(buffer, 0, buffer.Length);
return bytesRead > 0;
}
bool CanGetCookie(Cookie cookie)
{
return true;
}
bool CanSetCookie(Cookie cookie)
{
return true;
}
void Cancel()
{
}
}
Inside this class I've defined a custom resource dictionary which will dictate what file from the resources will be used, so as I stated in the first example, custom://cefsharp/assets/css/style.css should load the resource Properties.Resources.style, the problem is that nothing gets loaded once I enter to the specific url, I've tried to output the mimeType and It works but somehow the file itself won't output correctly. Is there something wrong with my implementation?
Additionaly I've tried to output the raw file in the form of:
if (ResourceDictionary.TryGetValue(fileName, out resource) && !string.IsNullOrEmpty(resource))
{
MessageBox.Show(resource);
}
And it outputs the correct file without any problems.
To load the custom Scheme I use the following code before initializing CefSharp:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = MyCustomSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new MyCustomSchemeHandlerFactory()
});
The above classes were based on the following links:
MyCustomSchemeHandlerFactory: FlashResourceHandlerFactory.cs
MyCustomSchemeHandler: CefSharpSchemeHandler.cs and ResourceHandler.cs
Since Cefsharp changed a bit in last few months here is an updated and easier way of handling 'file' protocol. I wrote blog post on this matter.
What you want to add is your scheme handler and its factory:
using System;
using System.IO;
using CefSharp;
namespace MyProject.CustomProtocol
{
public class CustomProtocolSchemeHandler : ResourceHandler
{
// Specifies where you bundled app resides.
// Basically path to your index.html
private string frontendFolderPath;
public CustomProtocolSchemeHandler()
{
frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
}
// Process request and craft response.
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
var requestedFilePath = frontendFolderPath + fileName;
if (File.Exists(requestedFilePath))
{
byte[] bytes = File.ReadAllBytes(requestedFilePath);
Stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
MimeType = GetMimeType(fileExtension);
callback.Continue();
return true;
}
callback.Dispose();
return false;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
}
And then register it before calling Cef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
If you simply need to return a string, then you can use ResourceHandler.FromString(html, mimeType). For this you just need to implement the ISchemeHandlerFactory.
https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp/ResourceHandler.cs#L98
Example reading from a file https://github.com/cefsharp/CefSharp/blob/cefsharp/47/CefSharp.Example/CefSharpSchemeHandlerFactory.cs#L17 which can be translated to reading from a string quite simply.

write and update key to ini file c#

i want write some setting to ini file with this code that search to find key and update it and if can't find the key add it to file . but it show this error :
"Object reference not set to an instance of an object."
i try this code :
internal class IniData
{
public string Key;
public string Value;
}
internal class IniSection : Dictionary<string, IniData>
{
public string Name { get; set; }
}
internal class IniFile : Dictionary<string, IniSection>
{
public string Path { get; set; }
}
public sealed class IniManager
{
private static readonly Dictionary<string, IniFile> IniFiles;
static IniManager()
{
IniFiles = new Dictionary<string, IniFile>();
}
public static void WriteIni(string fileName, string section, string key, string value)
{
/* Check if ini file exists in the ini collection */
var fileKey = fileName.ToLower();
if (!IniFiles.ContainsKey(fileKey))
{
if (!ImportIni(fileKey))
{
/* Add a new blank file */
var ini = new IniFile { Path = fileName };
IniFiles.Add(fileKey, ini);
}
}
/* Find section */
if (IniFiles[fileKey].ContainsKey(section.ToLower()))
{
/* Find key, if exists replace it */
if (IniFiles[fileKey][section.ToLower()].ContainsKey(key.ToLower()))
{
IniFiles[fileKey][section.ToLower()][key.ToLower()].Value = value;
return;
}
var data = new IniData { Key = key, Value = value };
IniFiles[fileKey][section.ToLower()].Add(key.ToLower(), data);
}
else
{
/* Create new ini section */
var sec = new IniSection { Name = section };
var data = new IniData { Key = key, Value = value };
sec.Add(key.ToLower(), data);
IniFiles[fileKey].Add(section.ToLower(), sec);
}
}
private static bool ImportIni(string fileName)
{
if (!File.Exists(fileName)) { return false; }
string[] data;
try
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
data = reader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
reader.Close();
}
stream.Close();
}
}
catch (Exception) { return false; }
if (data.Length == 0) { return false; }
var file = new IniFile { Path = fileName };
var section = new IniSection();
foreach (var s in data)
{
if (s.StartsWith("[") && s.EndsWith("]"))
{
/* Section header */
if (section.Count > 0)
{
/* Add current section */
file.Add(section.Name.ToLower(), section);
}
section = new IniSection { Name = s.Replace("[", null).Replace("]", null) };
continue;
}
/* Using current section, parse ini keys/values */
var iniData = ParseIni(s);
section.Add(iniData.Key.ToLower(), iniData);
}
if (section.Count > 0)
{
/* Add current section */
//##################Erorr : Object reference not set to an instance of an object.
file.Add(section.Name.ToLower(), section);
}
IniFiles.Add(fileName, file);
return true;
}
private static IniData ParseIni(string s)
{
var parts = s.Split('=');
return new IniData { Key = parts[0].Trim(), Value = parts.Length > 1 ? parts[1].Trim() : string.Empty };
}
}
private void button9_Click(object sender, EventArgs e)
{
IniManager.WriteIni("seting.ini", "Sec", "key", "value");
}
Instead of implementing this yourself you should just use the API functions that Windows provide. Of course, if you need to run this on Mono or other platforms than Windows, you need to go back to a pure .NET implementation, but even so I would probably go look for an existing implementation instead of creating that wheel yourself.
Anywhere, here's the API functions:
GetPrivateProfileString
WritePrivateProfileString
Here's an example LINQPad program that uses them:
(hit F4 and paste the following two lines into the additional namespace tab):
System.Runtime.InteropServices
System.ComponentModel
Then try this program:
void Main()
{
var ini = new IniFile(#"d:\temp\test.ini");
ini.WriteValue("Section", "Key", "Value");
ini.ReadValue("Section", "Key").Dump();
ini["Main", "Key2"] = "Test";
ini["Main", "Key2"].Dump();
}
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName,string lpDefault, StringBuilder lpReturnedString, uint nSize,string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);
public class IniFile
{
const int MAX_SIZE = 1024;
private readonly string _FilePath;
public IniFile(string filePath)
{
if (filePath == null)
throw new ArgumentNullException("filePath");
_FilePath = filePath;
}
public string this[string section, string key]
{
get
{
return ReadValue(section, key);
}
set
{
WriteValue(section, key, value);
}
}
public string ReadValue(string section, string key, string defaultValue = null)
{
var result = new StringBuilder(MAX_SIZE);
if (GetPrivateProfileString(section, key, defaultValue ?? string.Empty, result, (uint)result.Capacity, _FilePath) > 0)
return result.ToString();
throw new Win32Exception();
}
public void WriteValue(string section, string key, string value)
{
if (!WritePrivateProfileString(section, key, value, _FilePath))
throw new Win32Exception();
}
}
The problem here is that if the file starts with a key and not with a section, the foreach doesn't match the if (s.StartsWith("[") && s.EndsWith("]")) at all and so the Section.Name is never set, thus it is null when called in file.Add(section.Name.ToLower(), section);
BTW: your code seems quite buggy, try to redesign it at least in the main foreach of ImportIni

how do I set the current class to the return types results

I have this class:
using System.IO;
using System.Xml.Serialization;
namespace ssscc.Settings
{
public class AppSettings
{
private string _companyName;
public string CompanyName
{
set { _companyName = value; }
get
{
if (string.IsNullOrWhiteSpace(_companyName))
{
LoadSettings();
}
return _companyName;
}
}
private string _companyPhone;
public string CompanyPhone
{
set
{
_companyPhone = value;
}
get
{
if (string.IsNullOrWhiteSpace(_companyPhone))
{
LoadSettings();
}
return _companyPhone;
}
}
private string GetSettingsFile()
{
var exePath = System.Windows.Forms.Application.StartupPath;
var sharedDirectory = Path.Combine(exePath, "shared");
var settingsDirectory = Path.Combine(sharedDirectory, "settings");
var settingsFile = Path.Combine(settingsDirectory, "ssscc.xml");
if (!Directory.Exists(sharedDirectory))
{
Directory.CreateDirectory(sharedDirectory);
}
if (!Directory.Exists(settingsDirectory))
{
Directory.CreateDirectory(settingsDirectory);
}
return settingsFile;
}
internal void SaveSettings(AppSettings settings)
{
var serializer = new XmlSerializer(typeof(AppSettings));
using (var stream = File.OpenWrite(GetSettingsFile()))
{
serializer.Serialize((Stream) stream, (object) settings);
}
}
internal void LoadSettings()
{
if (!File.Exists(GetSettingsFile()))
{
return;
}
var serializer = new XmlSerializer(typeof(AppSettings));
using (var stream = File.OpenRead(GetSettingsFile()))
{
var appsetting = (AppSettings) serializer.Deserialize(stream);
CompanyPhone = appsetting.CompanyPhone;
CompanyName = appsetting.CompanyName;
}
}
}
}
My question is about this code:
var appsetting = (AppSettings) serializer.Deserialize(stream);
CompanyPhone = appsetting.CompanyPhone;
CompanyName = appsetting.CompanyName;
I am pretty sure there is a way to return the appsettings directly to the class that contains the method so I do not have to loop through each property such as this:
CompanyPhone = appsetting.CompanyPhone;
CompanyName = appsetting.CompanyName;
Can I assign the properties directly without having to maintain this code?
You are getting a new instance of AppSettings while deserializing from file. You may use it, can't you? Try to replace LoadSettings with a static factory method like this:
internal static AppSettings GetInstance()
{
if (!File.Exists(GetSettingsFile()))
return null;
var serializer = new XmlSerializer(typeof(AppSettings));
using (var stream = File.OpenRead(GetSettingsFile()))
return (AppSettings)serializer.Deserialize(stream);
}
while to save your settings, you have no need to pass the settings object as an argument. I guess the following code should do the job:
internal void SaveSettings()
{
var serializer = new XmlSerializer(typeof(AppSettings));
using (var stream = File.OpenWrite(GetSettingsFile()))
serializer.Serialize((Stream)stream, this);
}
Use the factory GetInstance method to initialize settings (well, as an example):
var s = AppSettings.GetInstance();
if (s == null)
{
s = new AppSettings
{
CompanyName = "MyCompany",
CompanyPhone = "######"
};
s.SaveSettings();
}
P.S.: if properties getters and setters have no additional logic (LoadSettings method no longer exists), you could use auto-properties:
public string CompanyName { get; set; }
public string CompanyPhone { get; set; }
and GetSettingsFile may be declared as static, as it does not operate any of the instance class members:
private static string GetSettingsFile()
{
//...
return settingsFile;
}
Do you really need to have lazy-loading in here, if not, make your methods explicitly:
public class AppSettings
{
private static readonly XmlSerializer Serializer
= new XmlSerializer(typeof(AppSettings));
public string CompanyName { get; set; }
public string CompanyPhone { set; get; }
private static string GetSettingsFile()
{
return null;
}
public static void SaveSettings(AppSettings settings)
{
using (var stream = File.OpenWrite(GetSettingsFile()))
Serializer.Serialize(stream, settings);
}
internal static AppSettings LoadSettings()
{
if (!File.Exists(GetSettingsFile()))
return null;
object appsetting = null;
using (var stream = File.OpenRead(GetSettingsFile()))
appsetting = Serializer.Deserialize(stream);
return appsetting as AppSettings;
}
}
Do you can use:
var setting = AppSettings.LoadSettings();
and:
AppSettings.SaveSettings(setting);
Please note in here, creating XmlSerializer everytime will get the memory leak,
The XmlSerializer constructor will generate a pair of classes derived from XmlSerializationReader and XmlSerializationWriter by analyzing the Person class using reflection. It will create temporary C# files, compile the resulting files into a temporary assembly, and finally load that assembly into the process. Code gen like this is also relatively expensive. So the XmlSerializer caches the temporary assemblies on a per-type basis. This means that the next time an XmlSerializer for the Person class is created, the cached assembly is used rather than a new one generated.
Therefore, you should keep XmlSerializer as static.

Categories

Resources