I’m writing a windows service C# service.
Within it I need a piece of functionality that can take a value (string) and look to an external file to try and match it and return the matching value, also a string.
So for example, the file might have:
Stringone – anothertwo
So if Stringone was passed the return value would be anothertwo
I need to it to be quite quick and importantly I must be able to make changes without having the recompile, so putting it into the resource file is not really an option.
Going to be less than 100 entries. So DB seems overkill.
Does anyone have some suggestions of what might be the best way to accomplish this?
Thanks.
Why dont you try XML or JSON? Create Serializable class.
Like
public class Entries
{
[JsonMember]
public string key{get;set;}
[JsonMember]
public string value{get;set;}
}
and use its collection to read.
Since it's a very small amount of entries, I think the easiest thing would be to create a dictionary<string, string>, serialize to json (since it's simple), and in the start method of the service just deserialize it.
Then, when your service gets a request, all you have to do is something like this:
public string GetTranslation(string source)
{
string returnValue = "";
_Dictionary.TryGetValue(source, out returnValue);
return returnValue; // if TryGetValue fails, you simply return an empty string
}
Or, you can return the source if there is no translation:
public string GetTranslation(string source)
{
string returnValue = "";
return _Dictionary.TryGetValue(source, out returnValue) ? source, returnValue;
}
Either way it's going to be super quick.
Related
I just discovered this nice tool XmlUnit that allows me to evaluate 2 different XML documents and display the eventual discrepencies.
string control = "<a><b attr=\"abc\"></b></a>";
string test = "<a><b attr=\"xyz\"></b></a>";
var myDiff = DiffBuilder.Compare(Input.FromString(control))
.WithTest(Input.FromString(test))
.Build();
Assert.IsFalse(myDiff.HasDifferences(), myDiff.ToString());
However, I have found that the myDiff.ToString() only displays the first difference encountered.
Is there a way to display them all ?
I just found the solution
Assert.IsFalse(myDiff.HasDifferences(), string.Join(Environment.NewLine, myDiff.Differences));
I assume that you are using the xmlunit.net library (You didn't say the name of the tool that you found but your example seems to match).
You can search their GitHub repo and find the DiffBuilder class file. If you look at the Build method you will see it returns a Diff object. If you go to the Diff class file you will find that it's ToString method looks like this.
public override string ToString() {
return ToString(formatter);
}
Which doesn't tell you a lot but if you go to the other ToString overload you find this.
public string ToString(IComparisonFormatter formatter) {
if (!HasDifferences()) {
return "[identical]";
}
return differences.First().Comparison.ToString(formatter);
}
Now we are getting somewhere. We now know that Diff stores its list of differences in a private differences field and why ToString() only returns one difference (The .First() call). If you look through that class you will find that there's a public property called Differences which exposes that field as an IEnumerable. So the way to get all differences is to loop through that property and collect all of them like so.
string control = "<a><b attr=\"abc\" attr2=\"123\"></b></a>";
string test = "<a><b attr=\"xyz\" attr2=\"987\"></b></a>";
var myDiff = DiffBuilder.Compare(Input.FromString(control))
.WithTest(Input.FromString(test))
.Build();
var sb = new StringBuilder();
foreach(var dif in myDiff.Differences)
{
sb.AppendLine(dif.Comparison.ToString());
}
Assert.IsFalse(myDiff.HasDifferences(), sb.ToString());
Note that I got the syntax for formatting the difference from the Diff class's ToString code. Also notice that I added a second attribute to your examples to demonstrate that this really is showing all the differences.
I am currently working on a D&D program for my friends and I. It is pretty much finished except for the fact that it is going to be extremely hard for my friends to add all their stats into the program. I am currently storing all the information for the persons character in a .txt document and calling it to my program as seen below.
labelCharisma.Text = line[0];
labelStrength.Text = line[1];
but the my problem being there is no format for my friends to follow. they would have to look in the code of my program, and find out what label or textbox correlates to which line on the text document. Is there any way for me to put a some sort of indicator in the .txt document before the value to show them what they need to put where in the .txt document?
IE
(Line 0 is for Charisma): 16
(line 0 is for strength): 14
but when calling the line leave everything out but the value.
I realize this would be much easier to use a database, but at this time I want to keep it simple by using .txt document.
Or is there a way to reference an .xlsx?
An easy format for settings is the good old *.INI format. It looks like this:
[Section1]
Setting1 = value 1
Setting2 = value 2
[Another section]
Setting3 = value 3
Charisma = high
Strength = 2
While other formats like XML or JSON are more versatile and allow to build complex hierarchical structures, INI-files are easy to understand by everyone, even by non-programmers.
You can write a class for the access of these settings like this
public class IniSettings
{
private string _filename;
public IniSettings(string filename)
{
_filename = filename;
}
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key,
string val, string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key,
string def, StringBuilder retVal, int size, string filePath);
public string this[string section, string key]
{
get
{
StringBuilder sb = new StringBuilder(1024);
GetPrivateProfileString(section, key, String.Empty, sb, 1024, _filename);
return sb.ToString();
}
set
{
WritePrivateProfileString(section, key, value, _filename);
}
}
}
Use it like this:
var settings = new IniSettings(myIniFile);
string charisma = settings["Another section", "Charisma"];
Depending on the technology you're using, you would probably want to use XML or JSON.
Both of these are structured text files, and have great support in navigating, accessing and extending its content.
If you're using Microsoft tech, I'd suggest using XML, and if it's a website type application I'd suggest looking at JSON. Personally I like XML more as I think it's cleaner and easier to maintain.
an example of how your structure will look in xml will be something like this...
<character>
<name>Wizard King</name>
<strength>3</strength>
<intelligence>9</intelligence>
etc.
hope it helps.
I am coding in C# on Visual Studio 2013 and I'm trying to deserialize some JSON using ServiceStack 3.9.71. They are contained in files (not under my control) and when I try to deserialize it, I end up with the correct array of DTO's but in addition, I have a null object at the end of the array. I've narrowed it to a carriage return ("\r") at the end of the file. A few solutions I can do is to trim the string, or remove all the "\r", or disable CRLF auto switch in GIT and just be super diligent when committing, however, I feel that seems like a "hack". I feel that DeserializeFromString should be able to handle carriage returns at the end of the string. On the brighter side, when I'm run the same code on OSX, it works perfectly fine since the file is now in Unix format that only uses linefeeds and not a combination of carriage returns and line feeds.
Has anyone else seen this? Any recommended fixes besides the ones I've mentioned?
To prove it to myself, I wrote a simple test (fails both Windows and OSX).
My DTO:
class DeserializeTestData
{
public int someData { get; set; }
public String moreData { get; set; }
}
My Test:
[Test]
public void ShouldNotContainNullItemsWhenDeserializing()
{
var deserializeMe = "[\r\n\t{\r\n\t\t\"someData\": 1,\r\n\t\t\"moreData\": \"I'm data!\r\nokok\r\n\"\r\n\t\t},\r\n\t{\r\n\t\t\"someData\": 2,\r\n\t\t\"moreData\": \"I'm also some data!\"\r\n\t\t}\r\n]\r\n";
var rows = ServiceStack.Text.JsonSerializer.DeserializeFromString<DeserializeTestData[]>(deserializeMe);
foreach (var row in rows)
{
Assert.That(row, Is.Not.EqualTo(null));
}
}
The results:
Test Name: ShouldNotContainNullItemsWhenDeserializing
Test Outcome: Failed
Test Duration: 0:00:00.125
Result Message:
Expected: not null
But was: null
Manipulating the input values for \r\n etc. becomes dicey.
also, afaik, JsConfig doesn't involve a setting to ignore null values on deserialization.
the best available option is to just ignore null Rows in the post-deserialized values.
var nonNullRows = rows.Where(r => r != null).ToList();
not the most elegant, but under the conditions, should do the job.
We suppose that for example i have a string, and i want to escape it, and to be well reading)
need a working extension what will solve this problem
i tried.
var t = "'";
t.Escape();// == "%27" (what i need), but it not assign result to var. t
t = t.Escape();//works, but ugly.
and the extension
public static string Escape(this string string_2)
{
if (string_2.HasValue())
string_2 = Uri.EscapeDataString(string_2);
return string_2;
}
how to fix this extension be working?
t = t.Escape(); is the usual idiom in .NET for changing a string. E.g. t = t.Replace("a", "b"); I'd recommend you use this. This is necessary because strings are immutable.
There are ways around it, but they are uglier IMO. For example, you could use a ref parameter (but not on an extension method):
public static string Escape (ref string string_2) { ... }
Util.Escape(ref t);
Or you could make your own String-like class that's mutable:
public class MutableString { /** include implicit conversions to/from string */ }
public static string Escape (this MutableString string_2) { ... }
MutableString t = "'";
t.Escape();
I'd caution you that if you use anything besides t = t.Escape();, and thus deviate from normal usage, you are likely to confuse anyone that reads the code in the future.
"Mutable string" in C# is spelled StringBuilder.
So you could do something like this:
public static void Escape(this StringBuilder text)
{
var s = text.ToString();
text.Clear();
text.Append(Uri.EscapeDataString(s));
}
But using it wouldn't really be that great:
StringBuilder test = new StringBuilder("'");
test.Escape();
Console.WriteLine(test);
The real answer is to use the "ugly" string reassignment
t = t.Escape();//works, but ugly.
You'll get used to it. :)
I have a device that sends out string data representing its settings, but the data is encoded in the string as its unicode(?) representation. For example, the device sends the string "00530079007300740065006D" which represents the string "System". Are there function built into C# that will convert the string data sent from the device to the actual string? If not, can someone advise me on how best to perform this conversion?
Totally jumping on #Will Dean's solution bandwagon here (so dont mark me as the answer).
If you're using Will's solution alot, I suggest wrapping it into a string extension:
public static class StringExtensions
{
public static string HexToString(this string input)
{
return new String(Enumerable.Range(0, input.Length/4)
.Select(idx => (char) int.Parse(input.Substring(idx*4,4),
NumberStyles.HexNumber)).ToArray());
}
}
This isn't a built-in function, but it is only one line of code:
string input = "00530079007300740065006D";
String output = new String(Enumerable.Range(0, input.Length/4)
.Select(idx => (char)int.Parse(input.Substring(idx * 4,4),
NumberStyles.HexNumber)).ToArray());
Here's another one, which is perhaps a little more high-minded in not doing the hacky char/int cast:
string out2 =
Encoding.BigEndianUnicode.GetString(Enumerable.Range(0, input.Length/2)
.Select(idx => byte.Parse(input.Substring(idx * 2, 2),
NumberStyles.HexNumber)).ToArray());
Yes, .NET has a built in way to move from a given encoding type to another type, say UTF8 -> ASCII or somesuch. The namespace you'll need is System.Text.Encoding.