Closed ststeiger closed 1 year ago
@ststeiger does it work on master, rather than 2.1?
It seems it was added here https://github.com/dotnet/corefx/blob/master/src/System.Data.SqlClient/src/System/Data/Sql/IBinarySerialize.cs
I'm experiencing the same problem, but when interacting with a table that has a HierarchyId column on it.
I believe the main issue here is that Microsoft.SqlServer.Types.dll is not available for .NET Core. This library is part of the SQL Server product.
@karelz based on this and our exchange on https://github.com/dotnet/core/issues/2273#event-2108607462, I added the "tracking-external-issue". Is this the right label?
There are a few workarounds:
For spatial data, we have improved compatibility with third party types that exist for .NET Core, called NetTopologySuite. I previously explained how this is used in EF Core 2.2, but the types and the ability to serialize and deserialize geography and geometry columns from SQL Server is available at the ADO.NET layer using NetTopologySuite.IO.SqlServerBytes.
@dotMorten has created a version of the Microsoft.SqlServer.Types library that works on .NET Core, but my understanding is that it does not implement spatial calculations.
That's the right label + no assignment + Future milestone + bug label. What is the external issue? Which (internal?) db? Which product?
@dotMorten has created a version of the Microsoft.SqlServer.Types library that works on .NET Core, but my understanding is that it does not implement spatial calculations.
That is correct. While I could probably implement most of the calculations, the results are going to be slightly off. I don't think that's a good idea (for now perform those calculations server-side as part of your query). I'd rather we can get the native part of the spatial types open-sourced, so we can recompile it for more platforms (that would be a lot less work than porting it to C#).
+1 for implementing Microsoft.SqlServer.Types for .NET Standard. We're attempting to convert our class libraries from .NET Framework to .NET Standard, and the code is littered with references to SqlGeography and SqlGeometry. I appreciate @dotMorten for building his nuget package, but it doesn't implement enough of the original to be viable for us to port to. Trying to convert to using NetTopologySuite looks promising, but would be a huge effort to implement...
Well, basically, If there were any fully managed C# library that would correctly implement STUnion of two WGS84-polygons, that would have been sufficient. At the time, I found nothing that did it halfway reliably. But now it looks like DotSpatial.Topology does that.
@ststeiger @justintoth Are you still running on Windows though? If so, we can still use the native library and call into it from .NET Core. Just wouldn't work on Linux/mac/android/ios etc.
@dotMorten Yes, we're only running our applications on Windows. I saw in SO threads that you can supposedly reference the .NET framework version of the Microsoft.SqlServer.Types dll's and then call something like this in .NET Core:
Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);
However, I tried it and the Utilities class doesn't exist in Microsoft.SqlServer.Types so it was a dead end for me. Any idea the proper way to do this?
@justintoth I was able to make it work in .NET core. I added the System.Data.SqlClient v4.6.0
and Microsoft.SqlServer.Types v14.0.1016.290
nuget packages.
Next I manually added the Loader.cs file from inside the nuget package to my project as well as the required native libraries:
<ItemGroup>
<Content Include="$(USERPROFILE)\.nuget\packages\microsoft.sqlserver.types\14.0.1016.290\nativeBinaries\**\*.dll">
<Link>SqlServerTypes\%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Compile Include="$(USERPROFILE)\.nuget\packages\microsoft.sqlserver.types\14.0.1016.290\content\SqlServerTypes\Loader.cs" Link="Loader.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SqlServer.Types" Version="14.0.1016.290" />
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
</ItemGroup>
After this, I was successfully able to do the following in a .NET Core 3.0 app (I'm guessing it'll work on earlier versions too):
SqlServerTypes.Utilities.LoadNativeAssemblies(".");
SqlGeometry p1 = SqlGeometry.Point(23, 34, 4326);
SqlGeometry p2 = SqlGeometry.Point(23, 35, 4326);
var union = p1.STUnion(p2);
Of course this will ONLY work when running your app on Windows as x86 or x64,
WOAH I even got this working on UWP. And because I don't have to deal with AnyCPU, I don't even need the LoadNativeAssemblies
call. Here's what I added to .csproj to make it work in UWP:
<ItemGroup>
<PackageReference Include="System.Data.SqlClient">
<Version>4.6.0</Version>
</PackageReference>
<Reference Include="Microsoft.SqlServer.Types, Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>$(USERPROFILE)\.nuget\packages\microsoft.sqlserver.types\14.0.1016.290\lib\net40\Microsoft.SqlServer.Types.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)'=='x64'">
<Content Include="$(USERPROFILE)\.nuget\packages\microsoft.sqlserver.types\14.0.1016.290\nativeBinaries\x64\*.dll">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(Platform)'=='x86'">
<Content Include="$(USERPROFILE)\.nuget\packages\microsoft.sqlserver.types\14.0.1016.290\nativeBinaries\x86\*.dll">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
(just note that the binaries violate store certification checks so you won't be able to put it in the store)
@dotMorten: Yea well, our Windows-only shop runs on Windows. But on my private laptop(s) which I use use to test new things on the way to and from work, there I only have Linux, and at home as well. Windows just doesn't go into standby and back fast enough, and it crashes, too. Also, I don't like the endless updates at moments in time that I don't want them (such as on a metered connection or when I have to change a train) and can't do anything against them, because although I have switched everything off and to manual and marked the connection as metered, it still does so whenever it feels like it...
I think if I remember right, I just did it in SQL on SQL-server, which worked on Linux, too - to my not little surprise. Which would probably indicate that the binaries are ported, or at the very least they found a replacement.
SELECT
geography::STPolyFromText('POLYGON((7.5999034 47.5506347,7.6001195 47.550805,7.5999759 47.5508885,7.5998959 47.5508256,7.5997595 47.5507183,7.5999034 47.5506347))', 4326)
.STUnion(
geography::STPolyFromText('POLYGON((7.6003356 47.5509754,7.6001926 47.551059,7.6000322 47.5509328,7.5999759 47.5508885,7.6001195 47.550805,7.6003356 47.5509754))', 4326)
).STAsText()
@dotMorten How did you add the Microsoft.SqlServer.Types nuget package to your .NET Core package when it's a .NET Framework nuget package? When I try to add it to my .NET Standard class library it fails to add.
@justintoth i just "did it". Nothing fancy. It warns you it might not be compatible but still goes ahead. Are you targeting 3.0? I can't remember if it's a 3.0 thing to allow that
@dotMorten It's a .NET Standard 2.0 project. Here is the error I get when trying to download from nuget packet manager.
Error NU1701 Package 'Microsoft.SqlServer.Types 14.0.1016.290' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project.
Yeah that wouldn't work. You'd need to target .NET Core App. The title here is about supporting .NET Core, not .NET Standard.
@dotMorten: If it helps implementing, this is how to do STUnion (with polygons) in NetTopologySuite: https://github.com/ststeiger/AnySqlWebAdmin/blob/master/AnySqlWebAdmin/Code/PolygonUnion/Program.cs
If the union is done, all that is needed is converting the geometry to sql-server geometry.
Some help for ST_Area covered in dept here: https://gis.stackexchange.com/questions/169422/how-does-st-area-in-postgis-work/258107#258107 (sql-server behaves differently than postgresql with respect to geography vs. geometry)
STDistance is trivial (on a sphere) because it can be googled. However, STDistance as in SQL-server is a bit less trivial. DotSpatial.Positioning seems to have a corresponding implementation, however.
public static double SpatialDistanceBetweenPlaces(Wgs84Coordinates a, Wgs84Coordinates b)
{
var fablat = new DotSpatial.Positioning.Latitude((double)a.Latitude);
var fablng = new DotSpatial.Positioning.Longitude((double)a.Longitude);
var sglat = new DotSpatial.Positioning.Latitude((double)b.Latitude);
var sglng = new DotSpatial.Positioning.Longitude((double)b.Longitude);
var fab = new DotSpatial.Positioning.Position(fablat, fablng);
var sg = new DotSpatial.Positioning.Position(sglat, sglng);
DotSpatial.Positioning.Distance dist = fab.DistanceTo(sg);
return dist.ToMeters().Value;
} // End Function SpatialDistanceBetweenPlaces
I have updated DotSpatial to NetStandard2_0 here: https://github.com/ststeiger/DotSpatial
All you need is DotSpatial.Projections and NetTopologySuite for polygons, and DotSpatial.Positioning for distance.
This is one of the last things keeping us from moving to .net core. Libraries are no doubt going to use this. Targeting .NET Core App seems like a hack.
@qcc-na This ended up working for us...
Although this is using the .NET Framework version of Microsoft.SqlServer.Types, it has worked for us so far in our .NET Standard class libraries and .NET Core applications. Good luck!
@justintoth: Copying a native *.dll will not work on Linux, Mac or Android.
Come to think of it, if you just copied a 32 xor 64-bit dll, it will not work with AnyCPU on Windows either.
Come to think of it further, if you didn't xcopy the C/C++ runtime libraries (of the right version) along with any other dependencies, it won't work for sure on a single CPU either.
At the very least, do a System.IntPtr.Size*8 == 64, and copy either a 32 or 64 bit library from the embedded resources to the ExecutingAssembly directory, and load the library with LoadLibrary (ASP.NET) or use SetDLL !
Realistically, you'll need to have to deploy the right C/C++ runtime libraries from the embedded resources as well, plus any pinvokes need to work with the same signature types on 32 & 64 bit, on all processors, on all operating systems supported by .NET Core/NetStandard2.
Just saying implicitly, the approach with a native library is a technically impossible/prohibitive proposition, if it is to be guaranteed to work on (xcopy) deployment (without administrative rights to install anything, such as the C/C++ runtime). If you want this to work with simply copying the dll, you need to statically link the C/C++ runtime, which you can't because you don't have the dll's source code.
Come to think of it even further, you'll need to check the dll's license to see if you are even allowed to do so (without an sql-server license, publicly) in the first place ...
I read somewhere (don't remember where) that the PostgreSQL entity-framework provider does internally convert the NetTopologySuite geometry types to pgsql-types - perhaps the place to start looking.
But i think MS geometry has a reverse rotation of the polygon points. Very expedient.
As recently announced in the .NET Blog, focus on new SqlClient features an improvements is moving to the new Microsoft.Data.SqlClient package. For this reason, we are moving this issue to the new repo at https://github.com/dotnet/SqlClient. We will still use https://github.com/dotnet/corefx to track issues on other providers like System.Data.Odbc and System.Data.OleDB, and general ADO.NET and .NET data access issues.
@David-Engel just wanted to give you the heads up on why I moved this issue here. I understand that technically Microsoft.SqlServer.Types isn't a component of SqlClient, and that the SqlClient team doesn't own it, but from the customer perspective, these types are part of the functionality offered by SqlClient.
I will continue to talk to the owners on SQL Server about the priority of enabling this. But we need an issue to track it somewhere and I believe it belongs here more than on CoreFx.
I just want to add that we also have an API that is heavily using the GetSchemaTable
reader function, to retrieve the metadata from the reader and process it after.
It is crashing as well because it is not able to locate the Microsoft.SqlServer.Types
DLL, when a reader has a column of the type geometry, geography or hierarchy. It will be nice if it gets supported.
It will be nice to have this fixed so we can move to .NET Core.
Would this issue also cover implementing the SqlHierarchyId type for .NET Core, or should I enter a separate issue for that?
@Ansssss: I'm no expert on the subject, but the thing is SqlGeography & SqlGeometry use a native library, which is closed-source and windows-only.
HierarchyId is just a CLR-type, and it probaby does not use native libraries, or at least I couldn't fathom why it possibly would. If that is so, I would create a separate issue for HierarchyId.
I could imagine that the issues with HierarchyId are far easier to solve than those with Geography/Geometry.
When trying to use SqlGeometry (SqlGeograpy or HiearchyId) with the new Microsoft.Data.SqlClient i get the following error:
Unhandled Exception: System.ArgumentException: Specified type is not registered on the target server.Microsoft.SqlServer.Types.SqlGeography, Microsoft.SqlServer.Types, Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91.
even if I can see that I have that library in my SQL Server assemblies (select * from sys.assemblies)
Those types will not work with new client without rebuild against new provider as they use types from old one.
If dotMorten.Microsoft.SqlServer.Types implementation will be enough for your cases, you can rebuild it against new provider or give your vote here to release it for new provider.
Hello.
Almost a year later, any news about spatial data types for .net core ? We are rebuilding a existing project (in .net core) from scratch because the architecture was crap and the question remain. What about spatial data. In the previous version, they used Entity Framework Core but that tool does not support them either... So we had (we maintained that previous version for a while) to use Net Topology Suite.
In the new version, we won't use Entity Framework but we still need spatial data types though...
You can use: https://github.com/dotMorten/Microsoft.SqlServer.Types @arnaudHerontrack
@ErikEJ : I've seen that library but it does not include any spatial operation. Currently, it might be enough but for the future, I can't be sure that we won't need to perform spatial operation in memory. But I just read about .Net 5 coming soon. As it merge .Net Core and .Net Framework, will it solve this problem ?
No, those types are not a part of .net 5
Ok will the librairy Microsoft.SqlServer.Types be usable ? If yes, then it's ok...
Of course it will, it is a netstandrad 2 library
Oh !? I thought I read in this thread that this precise library was not compatible with .Net Standard.
https://www.nuget.org/packages/dotMorten.Microsoft.SqlServer.Types/ is a netstandard2.0 project https://www.nuget.org/packages/Microsoft.SqlServer.Types/14.0.1016.290 is a net40 project and might be usable under several constraint:
System.Data.SqlClient
exactly version 4.8.2
Could not load file or assembly 'System.Data.SqlClient, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
When trying to use SqlGeometry (SqlGeograpy or HiearchyId) with the new Microsoft.Data.SqlClient i get the following error:
Unhandled Exception: System.ArgumentException: Specified type is not registered on the target server.Microsoft.SqlServer.Types.SqlGeography, Microsoft.SqlServer.Types, Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91.
even if I can see that I have that library in my SQL Server assemblies (select * from sys.assemblies)
Have anyone found the solution of this issue ? I am facing the same exception while adding SQLGeography type as command.parameter
command.Parameters.Add(new SqlParameter("@deviceGeolocation", SqlDbType.Udt) { UdtTypeName = "Geography", Value = geo, });
Another issue with dotMorten/Microsoft.SqlServer.Types (aside from the missing implementations of certain spatial operations) is that it is based on System.Data.SqlClient and does not support Microsoft.Data.SqlClient.
This has cost us a huge amount of developer time and we still don't have a good solution. We really need a .Net Standard cross-platform implementation compatible with Microsoft.Data.SqlClient.
@Ozzah: What spatial operations do you need ? I needed area, distance, polygon-union and multipolygon-union. I was able to do distance & area with DotSpatial.Projections, and Unions with NetTopologySuite.
Multipolygons required implementing a Concave-Hull-Algorithm in NetTopologySuite myselfs. https://github.com/ststeiger/OsmPolygon/blob/master/OsmPolygon/Concave/ConcaveHull.cs
I am using EF 6.3 with .NET Core and want to use spatial types on a Linux machine with SQL Server. Is https://github.com/dotMorten/Microsoft.SqlServer.Types my only option right now? I am a little confused about what NetTopologySuite.IO.SqlServerBytes is. Can I use it in my case? I would prefer an official solution.
It's very frustrating that multiple versions of the Framework have been released and there has been no movement on this issue in nearly 3 years; I just need to call FillSchema on a SqlDataAdapter for a table that has a Geography column...
@failwyn
This issue is also out of bounds for us, as commented here: https://github.com/dotnet/SqlClient/issues/322#issuecomment-810516964 | https://github.com/dotnet/SqlClient/issues/322#issuecomment-810577349
All I can say is efforts are in progress to resolve these gaps, but timelines are currently not known.
Thanks @cheenamalhotra, is there a more appropriate place to have this bug logged so that the community can communicate with the proper team? I just find it amazing that such a simple, yet integral piece of functionality, has been left out for so long...
A workaround I am using at the moment is to modify my SQL query and cast it as binary (varchar) like so:
SELECT
geometryColumn.STAsBinary() AS [geometryColumn],
geographyColumn.STAsBinary() AS [geographyColumn]
I then use GeoJSON.Net to parse it from binary representation into usable data structures. For INSERT/UPDATE, I do much the same thing except serialise the GeoJSON object as binary and cast it in back to the spatial type in the query.
Honestly, getting the Microsoft version to work across .Net Framework and Core versions, and getting the dotMorten package to work across both System.Data.SqlClient and Microsoft.Client.SqlClient was such a headache. This workaround works well for me for the time being.
We are also facing similar issue with .Net Core and .Net Standard projects that we have at our end. Can anyone please let me know when the proper package or solution will be provided regarding this?
Just use NetTopologySuite.
Package for reading/writing geometry: https://github.com/NetTopologySuite/NetTopologySuite.IO.SqlServerBytes Works with System.Data.SqlClient and Microsoft.Data.SqlClient.
The suite includes all necessary spatial operations and data conversion packages. For example, if you want to convert geometry to GeoJSON, read it with SqlServerBytesReader, get the Geometry object and write it with GeoJSON serializer: https://github.com/NetTopologySuite/NetTopologySuite.IO.GeoJSON.
Be careful. Some SqlClient methods can produce exceptions with Microsoft.SqlServer.Types.dll if you are trying to access the geometry column. For example, GetSqlValue will throw: Could not load file or assembly Microsoft.SqlServer.Types.
I was using dotMorten/Microsoft.SqlServer.Types for a time, but ran into the issue with it using System.Data.SqlClient. In the pull requests I saw this one Use Microsoft.Data.SqlClient 2.1.0 #58. I was able to pull that down and build it, then statically link the dll. It seems to be working enough that I can pump sqlGeography types into dapper.
https://github.com/ErikEJ/Microsoft.SqlServer.Types/tree/mds-package
Can someone reach out to dotMorten on twitter and ask him to push up the changes to his nuget package?
@cl0ckt0wer @dotMorten FYI!
@cl0ckt0wer Reach out to @dotMorten via the related GitHub issues the PR fixes
I have seen that the SQL Server team now have a preview of a newer version of Microsoft.SqlServer.Types that is now compatible with .NET Standard 2.1 ( https://www.nuget.org/packages/Microsoft.SqlServer.Types/160.900.6-rc0)).
Are there plans to update System.Data.SqlClient or will this only be supported in Microsoft.Data.SqlClient?
@stevetalkscode Not really that great. There's a runtimes folder in there indicating it still only supports Windows x86 and x64. No ARM64 support, nor ios, android, macos or linux support. Don’t really get why they target netstandard2.1. If they only support windows they cut of UWP and they could target net6.0-windows to make it clear that only Windows is supported.
Cannot run Microsoft.SqlServer.Types because \Microsoft.SqlServer.Server\IBinarySerialize.cs is missing in System.Data.
Since no source code is available, and contact owners on nuget yields a HTTP-500, I'm opening an issue here. I'd like to compute a polygon union...
And while you are at it, the version for the full .NET framwork (core also) should also work if SQL-Server is not installed on the machine that Microsoft.SqlServer.Types is executed on...