Path.GetDirectoryName changes in .NET Framework 4.6.2 - c#

Recently I updated my unit test project from .NET 4.5.1 to a higher version. When you update .net to 4.6.2 and higher there are changes in Path.GetDirectoryName behavior. It is known that in 4.6.2 version it become stricter, not allowing uri syntax anymore. But in my case I observe that it becomes LESS strict in some cases. The wrong path "/:\test\temp.txt" which caused an exception before now passes. Is this also a known issue or are there reasons for it?
using System.IO;
...
string dir = Path.GetDirectoryName("/:\\test\\temp.txt");
// .net 4.6.1: throws ArgumentException: The path is not of a legal form.
// .net 4.6.2 and above: dir = \:\test

Related

Enumerable.ToHashSet missing after framework upgrade

Sketch of the usage scenario:
HashSet<SomeClass> nodesToCopy = someList.Where(SomePredicate).ToHashSet();
After I have upgraded my project from the target .net framework version 4.5 to 4.5.2, the method Enumerable.ToHashSet<> is suddenly not available anymore, which gives me errors. As I look into the documentation, Microsoft tells me that Enumerable.ToHashSet has been introduced with version 4.7.2.
Now I am a little bit confused because it has definitly been there (and working) with version 4.5, because I got no errors then. I also did not define the extension method myself, which has been confirmed by searching my old code (and otherwise an extension method would also be there when I switch the framework to 4.5.2). It is also clear that I have not missed any 'using' declarations or assembly references, because otherwise it would not have worked in the first place.
So, isn't 4.5.2 downward compatible to 4.5 ? And I can hardly imagine that Microsoft is tampering with history (at least not deliberately) with regards to version 4.7.2. Maybe they had ToHashSet as a 'hidden feature' in 4.5?
While I appreciate and understand foreseeable recommendations to use newer frameworks, I cannot do this at the moment for various reasons. And I think I need to change to 4.5.2 to incorporate an external dll which is also compiled for 4.5.2. Of course, one solution would be to implement ToHashSet myself.
But my point is not primarily the solution, but I want to understand ('cause knowledge is power) if there is a sane reason for ToHashSet to once be there and then again not in a later framework. Does anyone know what is going on here?
Update 20230209: I have set up a minimal 'working' example. ToHashSet produces the desired (but unexpected, as for framework 4.5) result, no errors. Just a plain console application:
using System;
using System.Linq;
using System.Collections.Generic;
namespace ToHashSetError
{
class Program
{
public static void Main(string[] args)
{
List<string> myList = new List<string>(new[]{"abcd","efg"});
HashSet<string> myHashSet = myList.ToHashSet();
Console.Write(String.Join(",", myHashSet));
Console.Write("\r\nPress any key to continue . . . ");
Console.ReadKey(true);
}
}
}
with the default assembly references SharpDevelop chooses, and with target framework 4.5 set:
What is remarkable, the same code when trying to compile it on a different PC, fails as expected with an error (ToHashSet not available) for framework 4.5. So it is obviously something rooted in the jungle of different framework installations. But how to fix this, or even just find out the reason?

Error with Entity Framework Core when trying to migrate from .NET 3.11 to .NET 6 [duplicate]

I used the database first approach.
The model is right (or at least it looks like)
But I always get this error. Please, I've already tried so many things..
The full code of my program (and even sql script by which I create my database)
is here: https://github.com/AntonioParroni/test-task-for-backend-stack/blob/main/Server/Models/ApplicationContext.cs
Since I have a mac. I created my model with dotnet ef cli commands (dbcontext scaffold)
I can use my context. But I can't touch any DbSet..
public static void Main(string[] args)
{
using (ApplicationContext context = new ApplicationContext())
{
Console.WriteLine(context.Database.CanConnect());
var months = context.Months.ToList();
foreach (var month in months)
{
Console.WriteLine(month.MonthName);
}
}
//CreateHostBuilder(args).Build().Run();
}
It is not my first time using EF. And everything was working fine before, in many simple projects or tasks. While here.... It doesn't matter what I do (I even tried to rename all of my columns name, erase all tables except one, modify the context code, use the same steps from this project on a new, totally empty project..)
It is always..
Unhandled exception. System.TypeInitializationException: The type initializer for 'Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor' threw an exception.
---> System.TypeInitializationException: The type initializer for 'Microsoft.EntityFrameworkCore.Query.QueryableMethods' threw an exception.
---> System.InvalidOperationException: Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException() in System.Linq.dll:token 0x600041c+0xa
ect....
Here is my package reference file
"restore":{"projectUniqueName":"/Users/mac/Documents/GitHub/test-task-for-backend-stack/Server/Server.csproj",
"projectName":"Server","projectPath":"/Users/mac/Documents/GitHub/test-task-for-backend-stack/Server/Server.csproj",
"outputPath":"/Users/mac/Documents/GitHub/test-task-for-backend-stack/Server/obj/","projectStyle":
"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},
"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},
"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":
{"targetAlias":"net6.0","dependencies":{"EntityFramework":
{"target":"Package","version":"[6.4.4, )"},
"Microsoft.EntityFrameworkCore.Design":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent":"All","target":"Package","version":"[5.0.0, )"},
"Microsoft.EntityFrameworkCore.SqlServer":{"target":"Package","version":"[5.0.0, )"},
"Swashbuckle.AspNetCore":{"target":"Package","version":"[5.6.3, )"}},
"imports":["net461","net462","net47","net471","net472","net48"],
"assetTargetFallback":true,"warn":true,
"frameworkReferences":{"Microsoft.AspNetCore.App":{"privateAssets":"none"},
"Microsoft.NETCore.App":{"privateAssets":"all"}},
"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/6.0.100-preview.6.21355.2/RuntimeIdentifierGraph.json"}}
It's been already a few days. And I'm becoming really confused and mad.
Why is this happening.. and why there is not that much info about this type of error in the internet. Please, just point me in the right direction..
You have net6.0 target framework which is still not released while you have installed EF6 which is a previous iteration Entity Framework (mainly used with legacy .NET Framework projects) and you also have EF Core (a modern iteration of it) but older version - 5.0 (which you are actually using for your context, see the using Microsoft.EntityFrameworkCore; statements there).
Try removing EntityFramework package and installing preview version of Microsoft.EntityFrameworkCore.SqlServer (possibly just updating to the latest 5 version also can help) and either removing completely or installing preview version of Microsoft.EntityFrameworkCore.Design. (Also I would recommend to update your SDK to rc and install rc versions of packages).
Or try removing the reference to EntityFramework (not Core one) and changing target framework to net5.0 (if you have it installed on your machine).
As for why do you see this exception - I would guess it is related to the new methods added to Queryable in .NET 6 which made one of this checks to fail.
TL;DR
As mentioned in the comments - update EF Core to the corresponding latest version (worked for 5.0 and 3.1) or update to .NET 6.0 and EF Core 6.

In .NET, DbGeography.PointFromText is throwing a Not Implemented exception, when it should be implemented?

So I'm trying to do some simple Geography stuff in an old .NET 4.6.2 project. I have EF 5 installed (not planning on upgrading to EF 6).
When I try and do some simple DbGeography.PointFromText("POINT 1 1", 4326); I get a Not Implemented Exception thrown.
e.g.
SqlServerTypes.Utilities.LoadNativeAssemblies (AppDomain.CurrentDomain.BaseDirectory);
var xxx = System.Data.Spatial.DbGeography.PointFromText("POINT(1 1)", 4326);
I thought EF 5 has this method in it and it's totally ok to use? (e.g. reference material about using DbGeograpghy).
Am I doing something wrong? Is it possible the wrong (old?) dll is getting used and therefore, thrown?
Update 1 (Possibly not a duplicate).
It was suggested that the issue is because DbGeography requires (from nuget) Microsoft.SqlServer.Types package. So I tried installing that from nuget, then making sure I 'load' these special dll's at the start of my test. Problem still existed.
Update 2
Using NuGet Microsoft.SqlServer.Types version 14.0.314.76 (current version as of the time of this post)

Get the current dot net version of my application

How do I get the running dot net version of my asp.net application.
I tried the solution from here
Is there an easy way to check the .NET Framework version?
It gives the highest version installed but I need the running version.
Use Environment.Version for getting the run time version. It will give the version number of .Net CLR which is being used for executing current application.
You need to be careful here, it will only return run time version not framework version. The CLR for .NET 3.0 and .NET 3.5 is the same CLR from .NET 2.0.
Use Environment.Version - it gives you the exact version of .NET running the application.
Hope this one helps,
DirectoryEntry site = new DirectoryEntry(#"IIS://localhost/w3svc/1/Root");
PropertyValueCollection values = site.Properties["ScriptMaps"];
foreach (string val in values)
{
if (val.StartsWith(".aspx"))
{
string version = val.Substring(val.IndexOf("Framework") + 10, 9);
MessageBox.Show(String.Format("ASP.Net Version is {0}", version));
}
}
The script map property is an array of strings. If the app supports asp.net one of those strings will be a mapping of the aspx file extension to the asp.net handler which will a the full path to a DLL. The path will be something like
%windir%/Microsoft.NET/Framework//aspnet_isapi.dll.
You can get the version out of this string with some simple parsing.

Can I make a preprocessor directive dependent on the .NET framework version?

Here's a concrete example of what I want to do.
Consider the string.Join function. Pre-.NET 4.0, there were only two overloads, both of which required a string[] parameter.
As of .NET 4.0, there are new overloads taking more flexible parameter types, including IEnumerable<string>.
I have a library which includes a Join function that does essentially what the .NET 4.0 string.Join function does. I was just wondering if I could make this function's implementation dependent on the .NET framework being targeted. If 4.0, it could simply call string.Join internally. If 3.5 or older, it could call its own internal implementation.
Does this idea make sense?
If it does make sense, what's the most logical way to do it? I guess I'm just assuming a preprocessor directive would make the most sense, since a call to string.Join with an IEnumerable<string> parameter won't even compile when targeting a .NET version older than 4.0; so whatever approach I use would have to take place prior to compilation. (Checking the Environment.Version property at runtime, for example, wouldn't work.)
You can take a look at another question on Stack Overflow that illustrates how to set conditional constants through the project file's XML:
Detect target framework version at compile time
Then using that you can determine if you should use the .NET 4 overloads or your own library.
At some point (not sure when), Microsoft added predefined symbols for .NET versions into the MSBuild build system. Everything here works if you are using MSBuild from the .NET 5+ SDK (even if the project you are building with that SDK is using a much older target framework).
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives
Target Frameworks
Symbols
Additional symbols available in .NET 5+ SDK
.NET Framework
NETFRAMEWORK, NET48, NET472, NET471, NET47, NET462, NET461, NET46, NET452, NET451, NET45, NET40, NET35, NET20
NET48_OR_GREATER, NET472_OR_GREATER, NET471_OR_GREATER, NET47_OR_GREATER, NET462_OR_GREATER, NET461_OR_GREATER, NET46_OR_GREATER, NET452_OR_GREATER, NET451_OR_GREATER, NET45_OR_GREATER, NET40_OR_GREATER, NET35_OR_GREATER, NET20_OR_GREATER
.NET Standard
NETSTANDARD, NETSTANDARD2_1, NETSTANDARD2_0, NETSTANDARD1_6, NETSTANDARD1_5, NETSTANDARD1_4, NETSTANDARD1_3, NETSTANDARD1_2, NETSTANDARD1_1, NETSTANDARD1_0
NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, NETSTANDARD1_6_OR_GREATER, NETSTANDARD1_5_OR_GREATER, NETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, NETSTANDARD1_2_OR_GREATER, NETSTANDARD1_1_OR_GREATER, NETSTANDARD1_0_OR_GREATER
.NET 5+ (and .NET Core)
NET, NET6_0, NET5_0, NETCOREAPP, NETCOREAPP3_1, NETCOREAPP3_0, NETCOREAPP2_2, NETCOREAPP2_1, NETCOREAPP2_0, NETCOREAPP1_1, NETCOREAPP1_0
NET6_0_OR_GREATER, NET5_0_OR_GREATER, NETCOREAPP3_1_OR_GREATER, NETCOREAPP3_0_OR_GREATER, NETCOREAPP2_2_OR_GREATER, NETCOREAPP2_1_OR_GREATER, NETCOREAPP2_0_OR_GREATER, NETCOREAPP1_1_OR_GREATER, NETCOREAPP1_0_OR_GREATER
This allows you to, for example, do this:
#if NET5_0_OR_GREATER
Console.WriteLine("This is .NET 5 or later.");
#elif NETCOREAPP
Console.WriteLine("This is an older version of .NET Core.");
#elif NETFRAMEWORK
Console.WriteLine("This is the legacy .NET Framework.");
#else
Console.WriteLine("This is something else.");
#endif
Yes, I think it makes sense (for your particular case, since the change is relatively minor), though obviously that sort of thing could scale out of control fairly quickly.
IMHO, the most logical way to go about it would be to create different solution/project configurations for each version, then define a custom symbol (say, NET40) in your 4.0 configurations, then use that with an #if. I'm not certain if configurations will allow you to change the runtime version (that would obviously be the perfect solution), but your worst-case is having to change the version manually.
EDIT: I just saw the answer linked to in Joshua's answer, and that seems like a more streamlined solution, but I'll leave this here anyway, since it does, strictly speaking, answer the question.
You can prepare your code for .NET 4.0 and write the similar code for the .NET 3.5 base on framework detection.
#if NOT_RUNNING_ON_4
public static class GuidExtensions
{
public static bool TryParse(this string s, out Guid result)
{
if (s.IsNullOrEmpty())
return null;
try
{
return new Guid(s);
}
catch (FormatException)
{
return null;
}
}
}
#else
#error switch parsing to .NET 4.0
#endif
And put his line to your *.csproj
<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>

Categories