We are starting to use semantic versioning for some of our projects here, and are struggling to incorporate it into the .NET world. Semantic versioning seems to use 3 digits, a major, minor and patch. WPF projects in .NET use 4 digits.
When printing the version using the Assembly.GetExecutingAssembly().GetName().Version property the program will obviously return 4 digits and we would like only 3. Is there any way to achieve this? We want support for semantic versioning in our projects. I've tried just deleting the fourth digit in the Assembly Information, and although it does allow me to delete it, the Version property will always print that 4th digit. What can I do?
I use this method in my WPF applications (although its for the fileversion rather than the assembly version - I always have these the same in my small projects):
public static string ReturnApplicationVersion()
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
string versionMajor = fvi.ProductMajorPart.ToString();
string versionMinor = fvi.ProductMinorPart.ToString();
string versionBuild = fvi.ProductBuildPart.ToString();
string versionPrivate = fvi.ProductPrivatePart.ToString();
string fVersion = fvi.FileVersion;
return versionMajor + "." + versionMinor + "." + versionBuild + "." + versionPrivate;
}
You can easily modify it to return just 3 numbers. If you absolutely have to have the assembly version rather than the fileversion then perhaps someone else can help.
According to MSDN the way that versioning in .NET works is Major.Minor.Build.Revision. You can do this without defining a revision, but note that in C#, if the revision is undefined Version#Revision will return -1. If you are using the .NET Framework it is likely worthwhile to follow their semantic versioning principles.
Related
I have an ASP.Net Core Project with an MVC configuration. I use ASP.Net Core Version 5.0
My native language is german and therefore our database is also filled with german words, for example the word "fußball" (which means football or soccer, depending on where you are from).
As you can see, this word has an ß. In german, this "ß" is basically equivalent to "ss". Therefore if I have the string "fußball" I want to be able to find it if someone searches for "fussball" also.
I understand that ASP.Net Core has good localization and globalization options, I just can't seem to figure this one out.
Consider the following code:
var currCulture = CultureInfo.CurrentCulture.Name; // = "de-AT"
var str1 = "fußball";
str1.StartsWith("fuss"); //returns false
str1.StartsWith("fuss", StringComparison.InvariantCulture); //returns false
String.Equals("ß", "ss", StringComparison.InvariantCulture); //returns false
since I use my Windows-PC in an english language and I read in another Stackoverflow question that the CultureInfo is dependent on the operating system, I decided to insert the following into my Startup.cs-File, as suggested in this Stackoverflow question
var cultureInfo = new CultureInfo("de-AT"); //de-AT for Austria, i tried with de-DE too for germany, but the result was the same
cultureInfo.NumberFormat.CurrencySymbol = "€";
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
unfortunately, with my current setup, it always tells me that "ß" and "ss" are not the same when comparing them in strings. The same goes for "ä" and "ae", but I need these to be found in the same way. Regardless of if the input is "ä"/"ae" or "ß"/"ss".
Any ideas what I've been doing wrong are greatly appreciated, I just can't seem to get this to work.
Thank you in advance & best regards!
.NET Core on Windows had used the OS's built-in NLS localisation library, whereas other operating systems used the cross-platform and standard-compliant ICU library. Because NLS and ICU differ in implementation, this meant that the same .NET Core program could produce different results on different platforms when comparing strings.
To prevent this confusion, from .NET 5 the decision was made to use ICU for all platforms, including Windows. However, since many apps (yours included) are written on Windows and thus assume that string comparisons work in the NLS way, there are some things you need to do to make them work as expected with ICU.
In your case, you can explicitly set the CurrentCulture then ensure you explicitly use it in string comparisons:
using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("de-AT", false);
Console.WriteLine($"CurrentCulture is {CultureInfo.CurrentCulture.Name}.");
string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";
bool b = string.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine($"The two strings {(b ? "are" : "are not")} equal.");
// CurrentCulture is de-AT.
// The two strings are equal.
By placing the following in your .csproj you can revert to NLS if ICU causes too many issues for your application, but this should only really be used while you are upgrading your code to work with ICU:
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
</ItemGroup>
As #chadnt's answer described NET5 introduced a breaking change that causes this problem.
Here I found another solution which works even with NET6/7.
string sb = "ß";
string ss = "ss";
StringComparer sc1 = StringComparer.Create(CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace);
Console.WriteLine(sc1.Compare(sb, ss));
//returns 0 - zero means sb a ss are equal;
After reading the following:
CLR Needed for C# 6.0
Does C# 6.0 work for .NET 4.0
it seemed to me that aside from String Interpolation any project I compiled in VS2015 against .NET 4.51 could use the new C# language features.
However I tried the following code on my dev machine using VS2015 targeting 4.51:
string varOne = "aaa";
string varTwo = $"{varOne}";
if (varTwo == "aaa")
{
}
and not only did I not receive a compiler error, it worked as varTwo contained aaa as expected.
Can someone explain why this is the case as I would not have expected this to work? I am guessing I am missing what FormattableString really means. Can someone give me an example?
As mentioned in the comments, string interpolation works in this case as all the new compiler does is convert the expression into an "equivalent string.Format call" at compile time.
From https://msdn.microsoft.com/en-us/magazine/dn879355.aspx
String interpolation is transformed at compile time to invoke an equivalent string.Format call. This leaves in place support for localization as before (though still with traditional format strings) and doesn’t introduce any post compile injection of code via strings.
The FormattableString is a new class allows you to inspect the string interpolation before rendering so you can check the values and protect against injection attacks.
// this does not require .NET 4.6
DateTime now = DateTime.Now;
string s = $"Hour is {now.Hour}";
Console.WriteLine(s);
//Output: Hour is 13
// this requires >= .NET 4.6
FormattableString fs = $"Hour is {now.Hour}";
Console.WriteLine(fs.Format);
Console.WriteLine(fs.GetArgument(0));
//Output: Hour is {0}
//13
Can someone explain why this is the case as I would not have expected this to work?
This works since you're compiling with the new Roslyn compiler which ships with VS2015, and knows how to parse the string interpolation syntactic sugar (it simply calls the proper overload of string.Format). If you'd try to take advantage of .NET Framework 4.6 classes that work nicely with string interpolation, such as FormattableString or IFormattable, you'd run into a compile time error (unless you add them yourself. See bottom part of the post).
I am guessing I am missing what FormattableString really means.
FormattableString is a new type introduced in .NET 4.6, which allows you to use the new string interpolation feature with a custom IFormatProvider of your choice. Since this can't be done directly on the interpolated string, you can take advantage of FormattableString.ToString(IFormatProvider) which can be passed any custom format.
This question already has an answer here:
FileVersionInfo doesn't match Details tab in Explorer
(1 answer)
Closed 4 years ago.
if I make a right-click in explorer on an executable file and choose "properties". then in the properties dialog I select the tab "version". Then I click on the productversion. This is the value which I need to get with c#.
I tried it with "fileversioninfo.productversion", but if I get in the explorer "1.85" the fileversioninfo returns me weird values like: 1,00000,8,00. Dots become commas and the last digits are stripped off. I use net 2 on win 7 64 bit, if that matters.
fileversioninfo doesn't return what I would expect or what explorer does.
I tried also "fileversioninfo.fileversion", but it somehow returns even exact the same weird value like the fileversioninfo.productversion. In explorer view there is a clear difference between fileversion and productversion in the original fileproperties dialog window.
.Net with its fileversioninfo class doesn't display the values in that way how explorer would.
What must I do to get the values of the version in the explorer way?
Re-reading your post, you want to get the file version of another exe or your exe?
For another exe, use FileVersionInfo's FileMajorPart, FileMinorPart, FileBuildPart, FilePrivatePart, or ProductMajorPart, ProductMinorPart, ProductBuildPart, ProductPrivatePart, then format the values however you wish.
Be aware that depending on what version fields were used by the company or person who compiled the exe in question, it may or may not contain certain version fields.
If you use the FileVersion or ProductVersion property, it returns a 64-bit number where the four 16-bit shorts in the 64-bit long are the major.minor.build.private components.
However, this should format correctly if you use the .ToString() so:
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo("C:\\MyFile.txt");
string = fvi.ProductVersion.ToString();
If it does not format correctly, then use each individual component of the version information.
To display the formatted version of another exe:
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo("C:\\MyFile.txt");
int major = fvi.ProductMajorPart;
int minor = fvi.ProductMinorPart;
int build = fvi.ProductBuildPart;
int revsn = fvi.ProductPrivatePart;
string = String.Concat(major.ToString(), ".", minor.ToString(), ".", build.ToString(), ".", revsn.ToString());
Or just:
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo("C:\\MyFile.txt");
string = String.Concat(fvi.ProductMajorPart.ToString(), ".", fvi.ProductMinorPart.ToString(), ".", fvi.ProductBuildPart.ToString(), ".", fvi.ProductPrivatePart.ToString());
To retrieve this information for your executing exe you use:
version = Assembly.GetExecutingAssembly().GetName().Version;
Display as a string in the format M.m.b.r using:
string = Assembly.GetExecutingAssembly().GetName().Version.ToString();
Which is the full version major.minor.build.revision which can be retrieved as its component parts with:
major = Assembly.GetExecutingAssembly().GetName().Version.Major;
minor = Assembly.GetExecutingAssembly().GetName().Version.Minor;
build = Assembly.GetExecutingAssembly().GetName().Version.Build;
revision = Assembly.GetExecutingAssembly().GetName().Version.Revision;
This question applies to C#, .net Compact Framework 2 and Windows CE 5 devices.
I encountered a bug in a .net DLL which was in use on very different CE devices for years, without showing any problems. Suddenly, on a new Windows CE 5.0 device, this bug appeared in the following code:
string s = "Print revenue receipt"; // has only single space chars
int i = s.IndexOf(" "); // two space chars
I expect i to be -1, however this was only true until today, when indexOf suddenly returned 5.
Since this behaviour doesn't occur when using
int i = s.IndexOf(" ", StringComparison.Ordinal);
, I'm quite sure that this is a culture based phenomenom, but I can't recognize the difference this new device makes. It is a mostly identical version of a known device (just a faster cpu and new board).
Both devices:
run Windows CE 5.0 with identical localization
System.Environment.Version reports '2.0.7045.0'
CultureInfo.CurrentUICulture and CultureInfo.CurrentCulture report 'en-GB' (also tested with 'de-DE')
'all' related registry keys are equal.
The new device had the CF 3.5 preinstalled, whose GAC files I experimentally renamed, with no change in the described behaviour. Since at runtime always Version 2.0.7045.0 is reported, I assume these assemblies have no effect.
Although this is not difficult to fix, i can not stand it when things seem that magical. Any hints what i was missing?
Edit: it is getting stranger and stranger, see screenshot:
One more:
I believe you already have the answer using an ordinal search
int i = s.IndexOf(" ", StringComparison.Ordinal);
You can read a small section in the documentation for the String Class which has this to say on the subject:
String search methods, such as String.StartsWith and String.IndexOf, also can perform culture-sensitive or ordinal string comparisons. The following example illustrates the differences between ordinal and culture-sensitive comparisons using the IndexOf method. A culture-sensitive search in which the current culture is English (United States) considers the substring "oe" to match the ligature "œ". Because a soft hyphen (U+00AD) is a zero-width character, the search treats the soft hyphen as equivalent to Empty and finds a match at the beginning of the string. An ordinal search, on the other hand, does not find a match in either case.
Culture stuff can really appear to be quite magical on some systems. What I came to always do after years of pain is always set the culture information manually to InvariantCulture where I do not explicitly want different behaviour for different cultures. So my suggestion would be: Make that IndexOf check always use the same culture information, like so:
int i = s.IndexOf(" ", StringComparison.InvariantCulture);
The reference at http://msdn.microsoft.com/en-us/library/k8b1470s.aspx states:
"Character sets include ignorable characters, which are characters that are not considered when performing a linguistic or culture-sensitive comparison. In a culture-sensitive search, if value contains an ignorable character, the result is equivalent to searching with that character removed."
This is from 4.5 reference, references from previous versions don't contain nothing like that.
So let me take a guess: they have changed the rules from 4.0 to 4.5 and now the second space of a two space sequence is considered to be a "ignorable character" - at least if the engine recognizes your string as english text (like in your example string s), otherwise not.
And somehow on your new device, a 4.5 dll is used instead of the expected 2.0 dll.
A wild guess, I know :)
I'm using XPATH to select certain nodes from an XML document.
The user is able to insert a value for the location. It's working fine, but it does not work if different cases are used.
I've decided that changing both the XML values and the user's input to lower case before being compared is probably the best way to go about it.
I've got this as my selector at the moment:
NodeIter = nav.Select("/Houses/House/location[contains(../location, '" + location_input + "')]");
I've tried putting the lower-case() function in various locations, but it isn't happy with it.
How do I make it so that the value of ../location is compared as lower case?
Note: location_input is set to lower using ToLower() within my c# code.
The lower-case() function is only supported from XPath 2.0 onwards. If your environment supports this version of the standard, you can write:
NodeIter = nav.Select("/Houses/House/location[contains(lower-case(.), '"
+ location_input + "')]");
However, chances are you're stuck with XPath 1.0. In that case, you can abuse the translate() function:
NodeIter = nav.Select("/Houses/House/location[contains(translate(., "
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '"
+ location_input + "')]");
translate(../location, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') if you can get away with just A-Z
lower-case http://www.w3.org/TR/xpath-functions/#func-lower-case is part of XPath 2.0 and XQuery 1.0 so you need to use an XPath 2.0 or XQuery 1.0 implementation like XQSharp or like the .NET version of Saxon 9 if you want to use such functions.
With XPath 1.0 all you can do is NodeIter = nav.Select(string.Format("/Houses/House/location[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXZY', 'abcdefghijklmnopqrstuvwxyz'), '{0}')]", location_input));.
Note that strictly speaking, translating two strings to lower (or upper) case is not a correct way to do a case-blind comparison, because the mapping of lower-case to upper-case characters in Unicode is not one-to-one. In principle, in XPath 2.0 you should use a case-blind collation. Unfortunately though, although many XSLT 2.0 and XQuery 1.0 processors allow you to use a case-blind collation, there are no standards for collation URIs, so your code becomes processor-dependent.
As long as you are dealing with .net, you can use a Microsoft extension to do a case-insensitive comparison: ms:string-compare
https://msdn.microsoft.com/en-us/library/ms256114(v=vs.120).aspx
I had same dilemma using VS2017(NetFramework 4.6.1) and installed the XPath2 NuGet package. So far it has been worked fine for me when using XPath2 functions.