Different Target .Net Framework on each C# Project - c#

is it ok if i have this X project using .net2.0, and that X project is calling Y project which is using .net3.5.. i got customized buttons in Y project and im using that button in X project also, there's a method in Y project that has LINQ and X project is calling that method... i cant test it because i installed the latest .net framework.. :)
this is my code in project that has the .net3.5
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetDriveType(string lpRootPathName);
public enum DriveType : int
{
Unknown = 0,
NoRoot = 1,
Removable = 2,
Localdisk = 3,
Network = 4,
CD = 5,
RAMDrive = 6
}
var selectedDrives = from s in Environment.GetLogicalDrives() where Enum.GetName(typeof(DriveType), GetDriveType(s)).Equals(DriveType.Removable) select s;
foreach (String drives in selectedDrives)
{
MessageBox.Show(drives);
}
correct also the LINQ statement if i did it wrong.. :)

If the 3.5 framework is not installed on the machine that executes this, it will fail as System.Linq.dll won't exist. You can use LINQBridge with .NET 2.0 and C# 3.0 (which will give you access to a re-implementation of LINQ-to-Objects) but in reality it may be easier to get the client to upgrade. 2.0 is pretty old now.
Alternatively... if all you need is a where, there are easier routes. For example:
foreach (String drives in Environment.GetLogicalDrives())
{
if(!Enum.GetName(typeof(DriveType), GetDriveType(s))
.Equals(DriveType.Removable))
{
continue;
}
MessageBox.Show(drives);
}

A .NET 2.0 project cannot call a method in a .NET 3.5 project.

Related

How can I find the version of .NET run-time programmatically?

I need a solution to give me the .NET run-time version of both the full framework as well as the .NET Core.
On a machine with the following .NET versions:
Full: 4.7.2
Core: 2.1.104
Running:
RuntimeInformation.FrameworkDescription
Gives me:
Full: .NET Framework 4.7.2558.0
Core: .NET Core 4.6.26212.01
Running:
Environment.Version
Gives me:
Full: 4.0.30319.42000
Core: 4.0.30319.42000
How can I accurately get the run-time versions across different platforms knowing that the registry option is not available outside Windows.
There isn't a unified way to do this yet, although there is an open request for this here that you can track. If you click through the various issues that reference that discussion and the issues referenced further downstream, you'll see there are also some bugs in some implementations right now, but there is active work (one of the issues had a related check-in just 8 hours ago).
For .NET Framework:
using System;
...
string ver = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
and for .NET Core:
using System.Reflection;
using System.Runtime.Versioning;
...
string ver = Assembly.GetEntryAssembly()?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
Output:
.NETFramework,Version=v4.5.1
.NETCoreApp,Version=v2.0
Obviously these are a bit of a hassle to use programmatically, hence the requests for a better API (including this open issue from Microsoft discussing a new API specifically focused on testing for a minimum target framework).
The other piece of the puzzle that will probably always be impossible is that a given application can reference many targets. Under the hood you might be pulling in .NET Standard 2.x and .NET Standard 1.x libraries, for example. I doubt there will ever be a good way to get a complete picture of all the targets behind a given collection of executing assemblies...
If you want to know which version of .NET Framework is installed on a machine you should use the documented 'Release Key' Registry Key. That key is registered in the system when .NET Framework is installed.
This is publicly documented here:
https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/versions-and-dependencies
You have to write the code that will read that registry key and map it to an actual .NET Framework version. Here is code that does that for .NET Framework versions betwee 4.5 and 4.7.1. You can further customize that as you need to. (from https://github.com/dotnet/corefx/blob/master/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs#L33)
private static Version GetFrameworkVersion()
{
using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"))
{
if (ndpKey != null)
{
int value = (int)(ndpKey.GetValue("Release") ?? 0);
if (value >= 528040)
return new Version(4, 8, 0);
if (value >= 461808)
return new Version(4, 7, 2);
if (value >= 461308)
return new Version(4, 7, 1);
if (value >= 460798)
return new Version(4, 7, 0);
if (value >= 394802)
return new Version(4, 6, 2);
if (value >= 394254)
return new Version(4, 6, 1);
if (value >= 393295)
return new Version(4, 6, 0);
if (value >= 379893)
return new Version(4, 5, 2);
if (value >= 378675)
return new Version(4, 5, 1);
if (value >= 378389)
return new Version(4, 5, 0);
throw new NotSupportedException($"No 4.5 or later framework version detected, framework key value: {value}");
}
throw new NotSupportedException(#"No registry key found under 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' to determine running framework version");
}
}
I know you said that you don't want to use the registry, however I recommend you use the registry path if you are running on .NET Framework (you can detect that by looking at the path where assembly containing System.Object is loaded from) as that is the recommended and supported way (we use the same inside the .NET Runtime when we need to check what version is installed on a machine).
For .NET Core there isn't a registry key you can check. However, you can use the location of the assembly that contains System.Object to identify the version on which your code is running on.
public static Version GetVersion()
{
string runtimePath = System.IO.Path.GetDirectoryName(typeof(object).Assembly.Location);
// Making the assumption that the path looks like this
// C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6
string version = runtimePath.Substring(runtimePath.LastIndexOf('\\') + 1);
return new Version(version);
}
I faced a similar problem, for Inno Setup, I needed to find out if NET Core was installed and if so which version? Using the registry is not the way. For this reason, I reading console outputs:
/// <summary>
/// Detect installed NET Core version (major).
/// The method for .NET Framework applications and library when you need to know are the NETCore application running is possible
/// For NETCore application simple use Environment.Version Property
/// </summary>
/// <returns>
/// NET Core version or error code:
/// -1: some exception
/// -2: not installed or wrong dotnet prompt
/// -3: access file system problems
/// </returns>
[DllExport("GetNETCoreVersion", CallingConvention = CallingConvention.StdCall)]
public static int GetNETCoreVersion()
{
try
{
//we need create and run .cmd file to make console output redirection to file with using ">" operator (OLD GOOD MS DOS)
string cmdFileName = Path.GetTempFileName() + ".cmd";
string versionFileName = Path.GetTempFileName();
//like: cmd dotnet --version with console output redirection to file "versionFileName"
//full command id: cmd dotnet --version >> "versionFileName"
File.WriteAllText(cmdFileName, "dotnet --version > " + versionFileName);
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
{
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
WorkingDirectory = Path.GetDirectoryName(cmdFileName),
FileName = cmdFileName
};
System.Diagnostics.Process process = new System.Diagnostics.Process
{
StartInfo = startInfo
};
process.Start();
process.WaitForExit();
//after success dotnet --version >> "tempFileName", the "tempFileName" file must be exists and contains NET Core version
if (File.Exists(versionFileName))
{
string versionsinfo = File.ReadAllText(versionFileName);
File.Delete(versionsinfo);
//only major version is interested
versionsinfo = versionsinfo.Substring(0, versionsinfo.IndexOf("."));
int version = -2;
int.TryParse(versionsinfo, out version);
return version;
}
return -3;
}
catch
{
return -1;
}
}

Can't change C# version in project's subfolders

In my project, I've tried to tidy up the structure a bit and put all the C# classes into a separate folder (App_Code).
The problem is that it seems even if the project is set to use C# 7.1 (and .net framework 4.7)
Trying to create in subfolder class with newer syntax in example:
Namespace MyProject {
public static class Class1
{ (//*****Available since C# 6.0****)
public static string Test1 { get; } = ConfigurationManager.AppSettings["User"];
public static int Test2 ()
{
string s = "10";
int.TryParse(s, out int y); //*****Available since C# 7.0
return y;
}
}
This causes a compilation error stating, that this feature requires version 6.x (or 7.x in the case of "Test2" above) instead of 5.0.
Intelisense prompts me to change the version but even after following the prompt
the error persists.
Not sure if it matters, but classes in the App_Code folder have the same namespace as the ones in the rest of the project.
I use VS 2017 Pro.

Dapper called in application, and called in DLL is throwing a MissingMethodException

I'm wondering why my application that is referencing a dll I created that also uses Dapper is failing.
I get a Method not found: 'System.Collections.Generic.IEnumerable'1<!!0> Dapper.SqlMapper.Query(System.Data.IDbConnection, System.String, System.Object)'. error message.
When I track this down to the offending code it appears to be in DotPdfInvoideLayout.dll # InvoiceManager.LoadData()
Here below is the code for the method that is failing, because I'm calling this as a dll, the Stack Trace points to the last curly brace of the method. Line 1988. I am assuming that my real problem is the line that makes the call to Query()
public void loadData(IEnumerable<IPdfRenderable> textBoxes)
{
var conn = new SqlConnection("Server=something;DataBase=TRIMS;UID=user;Password=password;");
var output = conn.Query<TRIMNameAddressMaster>("Select top 1 * from Trims.dbo.TRIMNAMEADDRESSMASTER where id = '" + _transaction.strap + "'", null).FirstOrDefault();
var type = output.GetType();
var properties = type.GetProperties();
var r = new System.Text.RegularExpressions.Regex(#"((?<=\{)[^}]*(?=\}))+");
foreach (var textbox in textBoxes)
{
var matches = r.Matches(((PdfTextBox)textbox).Text);
foreach (Match match in matches)
{
try
{
var p = properties.Single(pi => pi.Name.ToLower() == match.Value.ToLower());
((PdfTextBox)textbox).Text = ((PdfTextBox)textbox).Text.Replace(
"{" + match.Value + "}", (p.GetValue(output, null) ?? string.Empty).ToString());
}
catch (Exception ex)
{
Console.WriteLine("No Mapping occurred" + match.Value);
}
}
}
}
As a console application DotPdfInvoiceLayout runs perfectly fine.
I removed the Main() and changed the project properties to run this as a Class Library then copied the
generated dll into the bin of my web application and referenced the dll in the web project.
I've tried to make sure both are using the same version of Dapper.
This sounds like one of the projects is referencing the down-level 3.5 library, and one is referencing the up-level 4.0/4.5 library. We intentioanally have the .NET 3.5 project configured to only use C# 3.0 syntax - although in some ways this is actually a legacy thing from "back in the day" when dapper was deployed as a code file rather than an assembly. As a consequence of using C# 3.0, it doesn't have the same level of support for optional parameters, so it uses overloads instead. These overloads have simply never existed in the 4.0/4.5 library. Due to this, the 3.5 project is not directly interchangeable with the 4.0 project.
Change the projects so that they are both targeting the same .net level in terms of "dapper", and it should work.

C# 4.0 project targeting earlier framework

Lets suppose if I have created a C# project which uses C# 4.0 features - optional parameter. What will happen if I select '.Net Framework 2.0' as a target framework? Will the compiler be intelligent enough to generate IL compatible with 2.0 on its own or will the Exe give runtime error when deployed on a machine that has only .Net framework 2.0?
In the specific case of optional parameters, compatibility will work as default values to use are stored in the caller's assembly and not in the called assembly so compatibility with other assemblies is ensured. If it compiles, it will run.
Optional parameters are just a syntaxic sugar. The following code compiles and run for a target framework 2.0 :
internal class Program
{
public static class DummyClass
{
public static string Bar(int b = 10, int a = 12)
{
return a.ToString();
}
}
private static void Main(string[] args)
{
Console.WriteLine("{0}", DummyClass.Bar(a: 8));
Console.ReadKey();
}
}
Read a full explanation by Mr Botelho

GetSystemMetrics() returns different results for .NET 4.5 & .NET 4.0

During a .NET 4.0 -> .NET 4.5 application migration process I've discovered an extremely strange behavior. I've been able to track this issue down to this short code snippet:
class Program
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
static void Main(string[] args)
{
const int CXFRAME = 0x20;
const int CYFRAME = 0x21;
var dx = GetSystemMetrics(CXFRAME);
var dy = GetSystemMetrics(CYFRAME);
Console.WriteLine("{0}x{1}", dx, dy);
Console.ReadKey();
}
}
When compiled with Target Framework = 4.0 (and also 2.0, 3.0, 3.5), it outputs 8x8
When compiled with Target Framework = 4.5, it outputs 4x4
Running this sample with MSVS2012 debugger also always outputs 4x4 (with any target framework).
Other options (target framework profile, target platform, enabling/disabling Aero) do not affect the result, the only things that change the output are target framework and running with debugger. I've been able to reproduce this issue on 3 computers, unfortunately they are almost identical in terms of installed software:
Windows 7 Ultmate SP1 (russian, all updates installed) with MSVS2012 (english/rusian) Update 1
Windows 8 (on virtual machine)
Currently I'm thinking about patching some .NET classes (SystemParameters for example), which call GetSystemMetrics() using reflection, but I'm not sure how to get correct metric values.
Questions:
Am I missing something? How can GetSystemMetrics() be affected by target framework?
Is there any way to call GetSystemMetrics() from .NET 4.5 app and get correct results?
I'm open to any suggestions on fixing this issue. Also, if you cannot reproduce the issue, please leave a short system description in comments.
So, it's actually a by-design behavior, and if someone has similar issues, here is the code which always outputs the same result:
const int CXFRAME = 0x20;
const int CYFRAME = 0x21;
const int CXPADDEDBORDER = 92;
var dx = GetSystemMetrics(CXFRAME);
var dy = GetSystemMetrics(CYFRAME);
var d = GetSystemMetrics(CXPADDEDBORDER);
dx += d;
dy += d;
Console.WriteLine("{0}x{1}", dx, dy);
Console.ReadKey();
Also note that RibbonWindow WPF control, which uses WindowChrome and now comes as a part of .NET 4.5 does not know about this changes and displays messy window borders (fortunately, I think it can be fixed using modified styles).
According to Microsoft, this is by-design.
See here for full details:
The SystemParameters.WindowResizeBorderThickness seems to return incorrect value - Microsoft Connect (no archived version available)
Regression: ::GetSystemMetrics delivers different values - Microsoft Connect (archived)
Despite MS saying it's "by design", I still think it's a bug!

Categories