"Cannot load dynamically generated serialization assembly." error when executing a clr function that calls a web service in SQL server 2008 R2.
I have a database project in Visual Studio 2017 which includes a clr function that calls a web service.
The project properties include the following:
Project Settings Target Platform = SQL Server 2008
SQLCLR Target framework = .Net Framework 3.5
SQLCLR Build Generate serialization assembly = On
The serialization assembly is created in the database by a post-deployment script when the database is published.
When I publish the databse to a SQL Server 2008R2 instance on my Windows 10 PC, executing the clr function results in the "Cannot load dynamically generated serialization assembly" error, however, when the database is published to a SQL2016 instance on my PC, it runs OK
Post deployment script to register serialization assembly:
CREATE ASSEMBLY [CifasEdit.XmlSerializers] FROM 'C:\tfs\CIFAS\Source\Database\Hub\CifasEdit\CifasEdit\bin\Release\CifasEdit.XmlSerializers.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS;
GO
The full error is here
A .NET Framework error occurred during execution of user-defined routine or aggregate "xxx":
System.InvalidOperationException: Cannot load dynamically generated serialization assembly. In some hosting environments assembly load functionality is restricted, consider using pre-generated serializer. Please see inner exception for more information. ---> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host.
System.IO.FileLoadException:
at System.Reflection.Assembly.nLoadImage(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence evidence, StackCrawlMark& stackMark, Boolean fIntrospection)
at System.Reflection.Assembly.Load(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence securityEvidence)
at Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
at Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources)
at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.
...
System.InvalidOperationException:
at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
at System.Xml.Serialization.XmlSerializer.GetSerializersFromCache(XmlMapping[] mappings, Type type)
at System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[] mappings, Type type)
at System.Web.Services.Protocols.SoapClientType..ctor(Type type)
at System.Web.Services.Protocols.SoapHttpClientProtocol..ctor()
So it appears that the serialization assembly generated automatically by VS2017 does not play nice with SQL Server 2008 R2 although it works fine with SQL2016.
To get the CLR function working in 2008R2 I moved the CLR code to a separate project and generated the serialization assembly manually using sgen.exe, then registered both dlls.
Be sure to use a version of sgen for clr2.0, on my PC this was located in
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin
The command to generate the serialization assembly is
sgen.exe c:\YourDir\YourAssembly.dll
This will create an assembly called YourAssembly.XmlSerializers.dll
Register both assemblies with SQL Server:
CREATE ASSEMBLY [YourAssembly] FROM 'c:\YourDir\YourAssembly.dll' WITH PERMISSION_SET = EXTERNAL_ACCESS
CREATE ASSEMBLY [YourAssembly.XmlSerializers] FROM 'c:\YourDir\YourAssembly.XmlSerializers.dll' WITH PERMISSION_SET = SAFE
Related
I have a F# DLL (.NET Framework 4.5.1, F# 4.1, FSharp.Core 4.4.3.0). The only NuGet added reference is to FSharp.Data.SqlProvider 1.1.41.
The code is in one file only
module DB
open FSharp.Data.Sql
[<Literal>]
let private dbVendor = Common.DatabaseProviderTypes.MSSQLSERVER
Build goes without errors
Import the built dll in SQL server as assembly
CREATE ASSEMBLY [Library2] FROM '<path>\Library2.dll' WITH PERMISSION_SET = UNSAFE
Operation fails with error
Assembly 'Library2' references assembly 'fsharp.core, version=4.3.1.0,
culture=neutral, publickeytoken=b03f5f7f11d50a3a.', which is not
present in the current database. SQL Server attempted to locate and
automatically load the referenced assembly from the same location
where referring assembly came from, but that operation has failed
(reason: version, culture or public key mismatch). Please load the
referenced assembly into the current database and retry your request
Now comment the last two rows in the code
//[<Literal>]
//let private dbVendor = Common.DatabaseProviderTypes.MSSQLSERVER
With this the SQL assembly creation succeeds, the assembly is correctly created in SQL server
Finally, if I downgrade the project to F# 3.1 (FSharp.Core 4.3.1.0), then no error in both cases
SQL Server 14.0.1000
Windows 10 Pro
Please note that an issue has already been raised in the project GitHub repo: Issue #541
Questions
Does anyone see something wrong in what I am doing?
Has anyone incurred in such an issue and solved it? If yes, how?
F# is not a natively supported SQLCLR language. I believe only C#, VB.NET, and Visual C++ are (and of course, IL if you are into writing it directly and not using a silly compiler ;).
So, as the error message states, you need to manually load that F# DLL, marking it as UNSAFE.
Please see the following answer of mine, also on S.O., for additional details on using F# in SQLCLR:
F# with sqlclr in a reasonably safe way and scripted assembly
I've published from Visual Studio the same CLR database function to both the Staging and Live db instances, they both live on the same MS SQL Server which is version 11.0.2100.60.
They both install fine however when I run a same function on the Live, I get the following error message:
Msg 6522, Level 16, State 1, Line 1
A .NET Framework error occurred during execution of user-defined routine or aggregate "RankWords":
System.IO.FileLoadException: Could not load file or assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) ---> System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
System.IO.FileLoadException:
System.IO.FileLoadException:
at net.johnhenry.lib.search.SearchAndRankingHelper.RankWords(String original_text, String words_being_searched, Int32 min_search_words_length, Boolean is_default_behaviour_and, Boolean is_partial_match)
at SqlClrExtension.UserDefinedFunctions.RankWords(String original_text, String words_being_searched, Int32 min_search_words_length, Boolean is_default_behaviour_and).
Any advice?
I eventually managed to solve the problem after having spent the entire day searching the most esoteric sites on the topic! :)
I kept republishing on top of the existing Assembly, just tweaking little bits of the settings but when doing this Visual Studio does not generate the entire SQL script to install the CLR code like if a fresh install but only the SQL script for what VS thinks it has changed.
The solution has been to drop the assembly and all its dependencies and republish afresh!
Visual Studio's Publish function will generate the entire SQL script needed to install the CLR code which resolved what I suspect was a badly registered library.
.
I encountered the following problem. When I try to add the assembly to SQL Server 2012 I get the following error:
Assembly "iAnywhere.Data.SQLAnywhere.v4.0" refers to an assembly "system.data.entity, version = 4.0.0.0, culture = neutral, publickeytoken = b77a5c561934e089.", Which is not in the current database. SQL Server attempted to locate and automatically load the specified assembly from the same location, where the referencing assembly, but the operation failed (reason: 2 (can not find the file specified.)). Load the specified assembly into the current database and try the request again.
After that I tried to add the assembly specified in the description and got the following:
Assembly "system.runtime.serialization, version = 4.0.0.0, culture = neutral, publickeytoken = b77a5c561934e089." not found in the catalog SQL.
Attention! Detectable object structures assembly Microsoft. NET Framework "system.data.entity, version = 4.0.0.0, culture = neutral, publickeytoken = b77a5c561934e089, processorarchitecture = msil." not been fully tested in an environment running SQL Server. In the future, if you upgrade or service this assembly or the. NET Framework subroutine CLR integration may stop working. For more information, see the documentation for SQL Server. (. Net SqlClient Data Provider)
So I tried google it and found this related connect article:
https://connect.microsoft.com/SQLServer/feedback/details/744584/unable-to-load-system-identitymodel-dll-assembly-into-sql-server-2012#details
Is it possible to do something about my problem?
This has been dogging me for 2 days now. I have a CLR sp that needs EXTERNAL_ACCESS. I can deploy it via VS2010 on my dev box by setting TRUSTWORTHY ON but we don't want to do that to the production server. We purchased an AuthentiCode compatible cert and I tried to sign my assembly with that but it failed due to chaining so I followed the instructions detailed here to strip out chaining from the cert.
Next I tried signing the assembly in VS but got the error "An attempt was made to reference a token that does not exist."
So went to the commandline and signed the assembly with the de-chained cert using SignTool.exe as several bloggers have recommended. The utility reports that signing succeeded.
Now to import the assembly into SQL Server (express 2008R2) on my dev box. First Set TRUSTWORTHY off as this procedure will have to be applied to the production server. Then I run
CREATE ASSEMBLY SqlClrProcedures from 'c:\<snip>\SqlClrProcedures.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS
This gets the following error: *CREATE ASSEMBLY for assembly 'SqlClrProcedures' failed because assembly 'SqlClrProcedures' is not authorized for PERMISSION_SET = EXTERNAL_ACCESS. The assembly is authorized when either of the following is true: the database owner (DBO) has EXTERNAL ACCESS ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with EXTERNAL ACCESS ASSEMBLY permission.*
I was logged in as sa. Ok so I create a user, assign him ownership of the db and grant him EXTERNAL ACCESS:
GRANT EXTERNAL ACCESS Assembly to ClrLogin
Then try
CREATE ASSEMBLY SqlClrProcedures AUTHORIZATION ClrLogin from 'c:\<snip>\SqlClrProcedures.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS
which produces the same error above.
The dbo has been granted EXTERNAL ACCESS ASSEMBLY and the assembly is signed, but I don't understand the part about the corresponding login, do I need a login for the cert?
If set TRUSTWORTHY ON just to get past the CREATE ASSEMBLY the assembly is imported fine but when I run the sp I get this error:
An error occurred in the Microsoft .NET Framework while trying to load assembly id 65573. The server may be running out of resources, or the assembly may not be trusted with PERMISSION_SET = EXTERNAL_ACCESS or UNSAFE. Run the query again, or check documentation to see how to solve the assembly trust issues. For more information about this error:
System.IO.FileLoadException: Could not load file or assembly 'sqlclrprocedures, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An error relating to security occurred. (Exception from HRESULT: 0x8013150A)
System.IO.FileLoadException:
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.Load(String assemblyString)
so it appears the cert is not getting recognized. Can someone please tell what I am doing wrong?
Kent Tegels has a step-by-step example showing the security process for signing a clr assembly with a certificate, then loading the certificate into the server so that the assembly is considered trusted.
Correct, TRUSTWORTHY should be set to OFF. For more info, please see my post: PLEASE, Please, please Stop Using Impersonation, TRUSTWORTHY, and Cross-DB Ownership Chaining
Signing an Assembly in Visual Studio means applying a Strong Name Key; it does not allow for signing with a Certificate (quite unfortunately).
Since you are going to use a signed Assembly, you do not need to worry about the database owner (dbo) being linked to a Login that has been granted either the EXTERNAL ACCESS ASSEMBLY or UNSAFE ASSEMBLY permission (the error message indicates that the dbo's permission only matter when TRUSTWORTHY is ON). When using a signed assembly, it is the Login created from the Asymmetric Key or Certificate (that was used to sign the Assembly) that will be granted either the EXTERNAL ACCESS ASSEMBLY or UNSAFE ASSEMBLY permission.
You don't need the AUTHORIZATION ClrLogin part
What you need (or needed) to do is:
Create a Certificate in the master Database. You can create the Certificate in a few different ways:
An already loaded SAFE Assembly (this would be the FROM ASSEMBLY option). HOWEVER, thanks to changes introduced in SQL Server 2017, this is no longer an option.
The .cer file (i.e. the public key) from the file system (this would be the FROM FILE option)
The .dll file from the file system (this would be the FROM EXECUTABLE FILE option)
The .cer file directly from a VARBINARY literal (this would be the FROM BINARY option). To easily convert that file into a hex bytes string (i.e. 0x12AB00003D...), you can use the open source BinaryFormatter command-line utility that I wrote that can be used in automation / Continuous Integration (by transforming it into a file to be imported / included), or used for manually scripting the CREATE CERTIFICATE statement (by transforming it directly to the clipboard to be pasted into a script).
Create a Login from that Certificate
Grant that Login either the EXTERNAL ACCESS ASSEMBLY or UNSAFE ASSEMBLY permission (starting in SQL Server 2017, just the UNSAFE ASSEMBLY permission).
Regarding SQL Server 2017
SQL Server 2017 introduced a new security feature ("CLR strict security", an advanced option) that is enabled by default and requires that ALL Assemblies, even those marked as SAFE, be signed with either an Asymmetric Key (i.e. strong name) or Certificate and have a Login (based on whatever was used to sign the Assembly) that has the UNSAFE ASSEMBLY permission. For details on how to make this work, with or without Visual Studio / SSDT, please see the following two posts of mine:
SQLCLR vs. SQL Server 2017, Part 2: “CLR strict security” – Solution 1
SQLCLR vs. SQL Server 2017, Part 3: “CLR strict security” – Solution 2
Please avoid the new Trusted Assemblies "feature" as it has many more flaws than benefits, not to mention it being entirely unnecessary in the first place given that existing functionality already handled the situation "Trusted Assemblies" was meant to address. For full details on that and a demo of the proper way to handle existing, unsigned Assemblies, please see: SQLCLR vs. SQL Server 2017, Part 4: “Trusted Assemblies” – The Disappointment.
Running this command:
CREATE ASSEMBLY
[System.Web] from
'C:\Windows\Microsoft.NET\Framework\v2.0.50727\system.web.dll'
with permission_set = UNSAFE
Gives me this error:
Msg 10300, Level 16, State 2, Line 1
Assembly 'System.Web' references assembly 'system.web, version=2.0.0.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a.', which is not present in the current database. SQL Server attempted to locate and automatically load the referenced assembly from the same location where referring assembly came from, but that operation has failed (reason: version, culture or public key mismatch). Please load the referenced assembly into the current database and retry your request.
... this sounds a little silly. It seems like SQL Server thinks that the System.Web assembly is referencing it's self. How can I fix this?
Try with Framework64 assemblies (64 bit sql server 2008)
CREATE ASSEMBLY
[System.Web] from
'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Web.dll'
with permission_set = UNSAFE
GO
It sounds like you need to install the .Net 2.0 framework on your database server.
Also, I wouldn't directly add a reference to System.Web.dll. Your other custom CLR code should reference that. (Or, if you don't have custom .Net code, you should create a custom .Net project to interface into the System.Web assembly.)
Turns out System.web.dll isn't supported for this. In fact, it turned out that loading DLLs into SQL Server like this (for CLR) was a bad idea on many levels (one of which was 64/32-bit support between deployments).