Future-proofing the .NET version detection - c#

Not to beat the dead horse, however, I am looking for a way to detect the installed .NET frameworks. It seems like the provided solutions (in the links) are all good up until the point a new version of the framework is released and then all bets are off. The reason for this is that the detection relies on the registry keys and it seems that v4 of the framework has broken the convention and one now has to take extra steps to detect v4.
Is there a way to detect the .NET framework that will also work when .NET v5 appears.
EDIT: Ok, for future generations of frustrated .NET Version seekers, here is the code to make it happen:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using Microsoft.Win32;
private List<string> GetInstalledDotNetFrameworks()
{
string key = string.Empty;
string version = string.Empty;
List<string> frameworks = new List<string>();
var matches = Registry.LocalMachine
.OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP")
.GetSubKeyNames().Where(keyname => Regex.IsMatch(keyname, #"^v\d"));
// special handling for v4.0 (deprecated) and v4 (has subkeys with info)
foreach (var item in matches)
{
switch (item)
{
case "v4.0": // deprecated - ignore
break;
case "v4":// get more info from subkeys
key = #"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
string[] subkeys = Registry.LocalMachine
.OpenSubKey(key)
.GetSubKeyNames();
foreach (var subkey in subkeys)
{
key = #"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item + #"\" + subkey;
version = Registry.LocalMachine
.OpenSubKey(key)
.GetValue("Version").ToString();
version = string.Format("{0} ({1})", version, subkey);
frameworks.Add(version);
}
break;
case "v1.1.4322": // special case, as the framework does not follow convention
frameworks.Add(item);
break;
default:
try
{
// get the Version value
key = #"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
version = Registry.LocalMachine
.OpenSubKey(key)
.GetValue("Version").ToString();
frameworks.Add(version);
}
catch
{
// most likely new .NET Framework got introduced and broke the convention
}
break;
}
}
// sort the list, just in case the registry was not sorted
frameworks.Sort();
return frameworks;
}

In short, you can use this approximately (see below for more complete solution):
Microsoft.Win32.Registry.LocalMachine
.OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP")
.GetSubKeyNames().Where(keyname=>Regex.IsMatch(keyname,#"^v\d"))
On my machine, this returns: v2.0.50727, v3.0, v3.5, v4, v4.0. Subkeys could be used to detect service packs (which are probably relevant). Also, using the key SOFTWARE\Microsoft\.NETFramework returns v2.0.50727, v3.0 and v4.0.30319 - ehhh, lovely, slightly different!
There's no guarantee this pattern will hold, but it's a pretty reasonable bet :-). http://support.microsoft.com/kb/318785 has some more info on the details of the registry describing the versioning, and in particular, you may need to check for Install - but that's tricky as v4.0 demonstrates.
Edit: I've extended this to detect arbitrary sub-key's of the registry that include installation info so as to detect v4 Client and Full profiles correctly. Also, the RegistryKey type is IDisposable, and it looks like the Dispose method is indeed doing something (registry key unlocking).
var versionList = new List<string>();
using(var ndpKey=Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP")) {
Action<RegistryKey, Action<RegistryKey,string>> processKids = (node, action) => {
foreach(var childname in node.GetSubKeyNames())
using(var child = node.OpenSubKey(childname))
action(child,childname);
};
Action<RegistryKey, Func<RegistryKey, bool>> visitDescendants = null;
visitDescendants = (regkey, isDone) => {
if(!isDone(regkey))
processKids(regkey, (subkey, subkeyname)=>visitDescendants(subkey,isDone));
};
processKids(ndpKey, (versionKey, versionKeyName) => {
if(Regex.IsMatch(versionKeyName,#"^v\d")) {
visitDescendants(versionKey, key => {
bool isInstallationNode = Equals(key.GetValue("Install"), 1) && key.GetValue("Version") != null;
if(isInstallationNode)
versionList.Add(
key.Name.Substring(ndpKey.Name.Length+1)
+ (key.GetValue("SP")!=null ? ", service pack "+ key.GetValue("SP"):"")
+ " ("+key.GetValue("Version") +") "
);
return isInstallationNode;
});
}
});
}
versionList then contains:
v2.0.50727, service pack 2 (2.0.50727.4927)
v3.0, service pack 2 (3.0.30729.4926)
v3.5, service pack 1 (3.5.30729.4926)
v4\Client (4.0.30319)
v4\Full (4.0.30319)

Do you expect we can tell you the future? :) Why do you need that in the first place? I mean, if you write an app for v4, what difference does it make if v5 is installed or not? You can specify in the app.config what versions you support, but you can't know in advance what the next version will be, or even if your app will run on that. Whenever a new framework comes out, you'll have to test your app, and decide if you want to migrate or not. If you migrate, then you make changes to the app.config and possibly the code, too, and release a new version. If you don't, then you'll still require that an older framework version be installed. It's not like v5 comes out and people will start uninstalling all the previous frameworks. I still have v1.1 and v2 on my machine and I guess they'll stick around for a while.

I am in agreement with fejesjoco. Why do you even want to detect a future version that your code has not been compiled against?
If you look in the Framework folder (C:\Windows\Microsoft.NET\Framework) you will see that all previous versions of the Framework are install along with the most recent version. If your code is compiled against 4.0 and 5.0 comes out it will still have a folder for 4.0.
If you could give us a bit more context as to why you want to detect future versions we may be able to help you better.

Include an auto-update feature in the detection tool?

Related

Octopus client, getting version from project name in C#

First of, I am completely new to octopus client, used it for the first time just before posting this.
So, I've been landed with this project to update the version number on a webpage monitoring some of our octopus deployed projects. I have been looking around the octopus client and not really gotten anywhere. The best I have so far is:
OctopusServerEndpoint endPoint = new OctopusServerEndpoint(server, apiKey);
OctopusRepository repo = new OctopusRepository(endPoint);
var releases = repo.Releases.FindAll();
From these releases I can get the ProjectId and even the Version, the issue is that releases is 600 strong and I am only looking for 15 of them.
The existing code I have to work from used to parse the version from local files so that is all out the window. Also, the existing code only deals with the actual names of the projects, like "AWOBridge", not their ProjectId, which is "Projects-27".
Right now my only option is to manually write up a keyList or map to correlate the names I have with the IDs in the octopus client, which I of course rather not since it is not very extendable or good code practice in my opinion.
So if anyone has any idea on how to use the names directly with octopus client and get the version number from that I would very much appriciate it.
I'll be getting down into octopus client while waiting. Let's see if I beat you to it!
Guess I beat you to it!
I'll just leave an answer here if anyone ever has the same problem.
I ended up using the dashboardto get what I needed:
OctopusServerEndpoint endPoint = new OctopusServerEndpoint(server, apiKey);
OctopusRepository repo = new OctopusRepository(endPoint);
DashboardResource dash = repo.Dashboards.GetDashboard();
List<DashboardItemResource> items = dash.Items;
DashboardItemResource item = new DashboardItemResource();
List<DashboardProjectResource> projs = dash.Projects;
var projID = projs.Find(x => x.Name == projectName).Id;
item = items.Find(x => x.ProjectId == projID && x.IsCurrent == true);
The dashboard is great since it contains all the info that the web dashboard shows. So you can use Project, Release, Deployment and Environment with all the information they contain.
Hope this helps someone in the future!
I'm using LINQPad to run C# snippets for Octopus automation using the Octopus Client library and I have come up with following to get any version of a project making use of Regular expression pattern. It works quite well if you use Pre-release semantic versioning.
For example to get latest release for a project:
var project = Repo.Projects.FindByName("MyProjectName");
var release = GetReleaseForProject(project);
To get specific release use that has 'rc1' in the version for example (also useful if you use source code branch name in the version published to Octopus:
var release = GetReleaseForProject(project, "rc1");
public ReleaseResource GetReleaseForProject(ProjectResource project, string versionPattern = "")
{
// create compiled regex expression to use for search
var regex = new Regex(versionPattern, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
var releases = Repo.Projects.GetReleases(project);
if (!string.IsNullOrWhiteSpace(versionPattern) && !releases.Items.Any(r => regex.IsMatch(r.Version)))
{
return null;
}
return (!string.IsNullOrWhiteSpace(versionPattern)) ? releases.Items.Where(r => regex.IsMatch(r.Version))?.First() : releases.Items?.First();;
}

'System.IO.Directory' does not contain a definition for 'EnumerateDirectories'

I have this code for looping through folders in a location, but I am getting some error I can't understand, here's the code
var directoryNames = Directory.EnumerateDirectories(filePath).Where(dir => dir.EndsWith(".user"));
foreach (var directoryName in directoryNames)
{
// some stuff
}
I get this error
'System.IO.Directory' does not contain a definition for 'EnumerateDirectories'
If this is something to do with the Framework version (my project has Framework 2.0, lowest possible so it can install easier on all machines), can you please:
Tell me an alternative code that would work like this, and will work on Framework 2.0
or
Tell me if I can use higher version of Framework, and guarantee that it will be supported on most machines (meaning the user will not be required to download Framework)
EnumerateDirectories was introduced in .NET 4.0. For .NET 2.0, you could use GetDirectories instead. You can specify your filter as a search pattern; this would cause the filtering to be performed by the filesystem itself.
var directoryNames = Directory.GetDirectories(filePath, "*.user");
foreach (var directoryName in directoryNames)
{
// ...
}

Recommended way to test for iOS Version specific feature at runtime

I'm targetting IOS 4.3 and 5.0 with an app built against the 5.0 SDK and would like to add support for the Twitter functionality introduced in iOS5 only when the app runs on a iOS5 device. What is the recommended way to reliably test for the availability of these OS features at runtime without having your app crash?
I know you do this using respondsToSelector in Objective-C but how is it done in C#?
With recent MonoTouch versions you can use the following code:
if (UIDevice.CurrentDevice.CheckSystemVersion (5, 0)) {
window.RootViewController = navigation;
} else {
window.AddSubview (navigation.View);
}
Otherwise you can get a string from UIDevice.CurrentDevice.SystemVersion and do some checks with your own code.
Follow up to comments, including mine...
If you want to check by feature you can do something like:
MonoTouch.Twitter.TWRequest req = new MonoTouch.Twitter.TWRequest ();
if (req.Handle == IntPtr.Zero) {
Console.WriteLine ("No Twitter support before iOS5");
}
What happens is that the selector to create the TWRequest instance will return null and the .NET object will be created in an invalid (unusable) state that you can query with the Handle property. Again YMMV, testing is key :-)

What is the most reliable way to detect windows OS Architecture (x86,x64) on .NET 2.0

i am using Visual C# 2010 express and i need the most reliable way (on button click) and in .NET 2.0 framework to detect if windows is currently x86 or x64 in a message box.. up till now i have been using this code but i need to know if there is a more accurate way?
string target = #"C:\Windows\SysWow64";
{
if (Directory.Exists(target))
{
MessageBox.Show("x64");
}
else
{
MessageBox.Show("x86");
}
By far the simplest test is to check the size of an IntPtr:
if (IntPtr.Size == 8)
{
MessageBox.Show("x64");
}
else
{
MessageBox.Show("x86");
}
Which assumes you build your EXE with the default Platform Target set to "Any CPU". Beware that this default changed in VS2010.
You can use the PROCESSOR_ARCHITECTURE environment variable...
System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
It will return one of: x86, AMD64, IA64.
You are probably only interested in the x86 and AMD64 values, the IA64 is not very popular and not being supported by Microsoft in the future. It is for Itanium and Itanium 2 processors.
Another simple method is to look in the registry to see if SOFTWARE\Wow6432Node exists for HKLM or HKCU.
I think the best way is to use: System.Environment.Is64BitOperatingSystem.
Had this for a while. I believe it's .NET 2.0 compatible but I'm not totally sure. You're probably only interested in cases 0 and 9 (they're the most common anyways).
public static string GetCpuArch()
{
ManagementScope scope = new ManagementScope();
ObjectQuery query = new ObjectQuery("SELECT Architecture FROM Win32_Processor");
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection results = search.Get();
ManagementObjectCollection.ManagementObjectEnumerator e = results.GetEnumerator();
e.MoveNext();
ushort arch = (ushort)e.Current["Architecture"];
switch (arch)
{
case 0:
return "x86";
case 1:
return "MIPS";
case 2:
return "Alpha";
case 3:
return "PowerPC";
case 6:
return "Itanium";
case 9:
return "x64";
default:
return "Unknown Architecture (WMI ID " + arch.ToString() + ")";
}
}
The PROCESSOR_ARCHITECTURE environment variable contains the address width of the running process, which is not necessarily that of the operating system or processors. A quick way to see this is by running the following command...
$Env:PROCESSOR_ARCHITECTURE
...in 32- and 64-bit PowerShell sessions and comparing the output.
So, if GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") returns "AMD64" then you definitely have a 64-bit process, operating systems, and processors. If it returns "x86" then you definitely have a 32-bit process, though you still won't know if the operating system and processors are 32- or 64-bit.
If you're really after the address width of the operating system, then .NET 4 offers the Environment.Is64BitOperatingSystem property. You can also use WMI on any version of .NET to read the OSArchitecture property of the Win32_OperatingSystem class:
static string GetOSArchitecture()
{
var query = new WqlObjectQuery("SELECT OSArchitecture FROM Win32_OperatingSystem");
using (var searcher = new ManagementObjectSearcher(query))
using (var results = searcher.Get())
using (var enumerator = results.GetEnumerator())
{
enumerator.MoveNext();
return (string) enumerator.Current.GetPropertyValue("OSArchitecture");
}
}
...though, unfortunately, the OSArchitecture property only exists on Windows Vista/Server 2008 and above.
For all versions of Windows since 2000, you might try p/invoking the GetSystemInfo() function and checking the wProcessorArchitecture member of the SYSTEM_INFO structure.

C# Regex Compatibility Issue (.NET 3.5 vs .Net 2.0)

I have the following regex expression on a dev machine that is running .NET 3.5 and it works as designed. However when it is deployed to our test environment (which is running .NET 2.0) it doesn't work right and always seems to return false. Does anyone know what the culprit may be? Thanks
using System.Text.RegularExpressions;
protected void emailContactCheck(object source, ServerValidateEventArgs args)
{
string[] allContacts = this.Contacts.InnerText.ToString().Split(";,".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Regex rx = new Regex(#"^(([^<>()[\]\\.,;:\s#\""]+"
+ #"(\.[^<>()[\]\\.,;:\s#\""]+)*)|(\"".+\""))#"
+ #"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
+ #"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
+ #"[a-zA-Z]{2,}))$", RegexOptions.IgnoreCase);
foreach (String contact in allContacts)
{
if (!rx.IsMatch(contact.Trim()))
{
args.IsValid = false;
return;
}
}
args.IsValid = true;
}
According to regular-expressions.info, there are no differences in regex support between .NET 2.0 and 3.x, so the problem is probably not with the regex engine.
I would try to set the .Net version of your dev machine to .Net 2.0 too. Can be done on the project build properties. You should always use the same version as on your test/production system.
Then you can try to check whether you can reproduce the problem also on your dev machine running .Net 2.0.

Categories

Resources