Sql Server CLR load assembly failed - c#

I am trying to deploy an CLR TVF (table value function). In the code I am using JavaScriptSerializer to parse some JSON string, so I reference the System.Web.Extensions dll and my problems start there.
Project builds fine, but when I try to register the dll I receive the following error:
Assembly 'my_assembly_name' references
assembly 'system.web.extensions,
version=4.0.0.0, culture=neutral,
publickeytoken=31bf3856ad364e35.',
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: 2(The system cannot find the
file specified.)). Please load the
referenced assembly into the current
database and retry your request.
I referenced system.web.extensions from:
C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Web.Extensions.dll
I can set copy load to true or manually copy the assembly but then referencing errors go deeper -
Assembly 'my_assembly_name' references
assembly
'system.servicemodel.activation,
version=4.0.0.0, culture=neutral,
publickeytoken=31bf3856ad364e35.',
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: 2(The system cannot find the
file specified.)). Please load the
referenced assembly into the current
database and retry your request.
Everything works fine until I reference the Web.Extensions.dll. Target Framework is .NET 4.
Any ideas/solutions?

Acording to the documentation, any .NET assembly can be referenced but each dependant assembly must also be registered in the database (visible in the "Programmability - Assemblies" node in SQL Server Manager).
Once the SQL Server Database has the dependant assemblies available they will be present in the Add Reference Dialog window in Visual Studio.
This SQL code below works. I had needed the System.Web.dll assembly
(you need the correct version my 2005 SQL is 64 bit)
CREATE ASSEMBLY [System.Web] AUTHORIZATION dbo
FROM 'c:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\System.web.dll'
WITH PERMISSION_SET = UNSAFE
The system will try to automatically register dependent assemblies but can only do it from the same directory as the file you are attempting to register.
In my case it also registered the following assemblies in the database for System.Web to operate correctly...
System.Configuration.Install
System.Design
System.DirectoryServices
System.DirectoryServices.Protocols
System.Drawing
System.Drawing.Design
System.EnterpriseServices
System.Runtime.Remoting
System.Runtime.Serialization.Formatters.Soap
System.ServiceProcess
System.Web.RegularExpressions
System.Windows.Forms
My system is using 3.5 Framework so I cannot test importing System.Web.Extensions.dll for you but it may require other assemblies from another folder to register, and since it is a 4.0 assembly it may be referencing some 2.0 or 3.5 assemblies that are in a different folder.
I suspect you will end up with a rather large list of assemblies imported to get it to work but it is definitly possible to do.
The operation can probably be done more easily by having one folder with all the dependent dlls in it and register from there.

Sadly integration of the .NET Framework CLR with SQL Server 2005 / 2008 is only a limited subset of the framework and the System.Web.Extensions doesn't seem to be a supported assembly / namespace.
For a full list of supported assemblies check out MSDN: http://msdn.microsoft.com/en-us/library/ms403279.aspx

Related

dlls missing after publishing .NET Web

My web project use .NET Framework 4.7.2 and use some references like
System.IO
System.Net
System.Net.Http
System.Net.Http.Formatting
My project works perfectly in local.
However, when I publish my web project on a target directory (for online), and look what it contains in /bin/ :
System.IO is missing
System.Net is present
System.Net.Http is missing
System.Net.Http.Formattingis present
Therefore, when I use my website, I get the obvious error Could not load file or assembly 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
All references have Copy Local = True in Properties but some dll are always ignored. If i copy the dlls from local directory to target directory i get the error Server Error in '/' Application. Cannot load a reference assembly for execution. Exception Details: System.BadImageFormatException: Cannot load a reference assembly for execution. Exactly the same problem as this one.
However the delete/rebuild solution, or adding compilation options solution, doesn't work for me
What do I need to do to get these missing dlls to the destination folder?
Go to Solution Explorer on VS, open references tree, right click on the library(dll) and select properties on the menu. On properties box Copy Local should be True

Troubles creating assembly in MS SQL Server

I had intentions to import the .NET assembly with SQL functions to MS SQL Server.
I've been trying to import it like this:
CREATE ASSEMBLY [AssemblyName]
AUTHORIZATION [dbo]
FROM 0x4D5A9000030...
It was generated by my SQL project in Visual Studio
After that I needed to also create the referenced assemblies, like 'Microsoft.CSharp'
CREATE ASSEMBLY [Microsoft.CSharp]
FROM 'path to dll'
WITH PERMISSION_SET = UNSAFE
And then I've got the error like this:
Assembly 'Microsoft.CSharp' references assembly 'system.dynamic, version=4.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: 2(The system cannot find the file specified.)). Please load the referenced assembly into the current database and retry your request.'
And now I really don't understand. As far as I know, System.Dynamic is not an assembly, but a namespace in System.Core.dll. And the System.Core is supported by MS SQL Server and imported by default. Is there any way to resolve such issue and successfully import such assembly?
That (System.Dynamic.dll) really is an assembly - you can find it in the GAC and on disk; it has lots of the implementation details that C# uses to implement dynamic. You don't normally see it because all the types are internal, but it uses:
[assembly: InternalsVisibleTo("Microsoft.CSharp, PublicKey =002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
so those implementation details are available to Micrsoft.CSharp.dll
The database is 100% correct here.

SQL Server CLR integration with 3rd party SDK: Error on missing assembly System.Drawing

I am developing a solution that will interface with the SDK of a 3rd party application and ultimately create a dataset to migrate data into a destination database on our SQL Server 2014 instance. This interface is via a SQL Server CLR Stored procedure. the following references have been used in creating the CLR assembly on the C# side:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using (3rd party SDK);
using System.Dynamic;
The code builds correctly and all. However, when I attempt to create an assembly using the CREATE ASSEMBLY statement I get the following error:
Assembly 'MyAssembly' references assembly 'system.drawing, version=4.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: 2(The system cannot find the file specified.)). Please load the referenced assembly into the current database and retry your request.
Going further, if I attempt to create an unsafe assembly based on the apparently missing reference, system.drawing (keep in mind I do have trustworthy set to true in the target database), I get the following error:
CREATE ASSEMBLY for assembly 'System.Drawing' failed because assembly 'System.Drawing' failed verification. Check if the referenced assemblies are up-to-date and trusted (for external_access or unsafe) to execute in the database. CLR Verifier error messages if any will follow this message
[ : System.Drawing.Image::Finalize][mdToken=0x600000d][offset 0x00000000] Code size is zero. (etc, etc. same error repeating on different methods in system.drawing)
I already have the .NET frameworks matching between the solution and the target SQL Server database matching to v4.0. I honestly am at a loss here, and this seems soo much harder than it should be. I'm not even directly referencing System.Drawing, yet I need it for some odd reason.
While it might not always behave as expected, you should be able to load System.Drawing into SQL Server. You will need to set the Database to TRUSTWORTHY ON (which it seems that you have), and you need to mark the Assembly as UNSAFE in the CREATE ASSEMBLY statement (i.e. use the WITH PERMISSION_SET = UNSAFE clause).
If you still get an error, make sure you are loading the actual System.Drawing DLL and not one of the reference Assemblies, and make sure you grab the correct 32-bit or 64-bit version.
For CLR version 4.0 (which is used by SQL Server 2012 and newer), the assembly path should be one of following two options, depending on whether you need the 32-bit or 64-bit version:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Drawing.dll
Also, you don't need to worry about the .NET Framework version as long as you are using one that is bound to the proper CLR version, which is 4.0. Meaning, you could just as well be using .NET Framework version 4.5.2 or 4.6, so long as the target server has been updated to that Framework version.

Deploying assembly normally in the GAC with my project?

I built a web application that uses the J# libraries which works fine in my cpu, however, when I deploy it to my shared server. I get an error message: Parser Error Message: Could not load file or assembly 'vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
So basically, the server doesn't have visual j# installed. The problem is they wont install it because it is a shared server.
Is there a way I can deploy the J# assemblies with my project so that it will work on the shared server without it being registered in the GAC?
Thanks for your help!!
Simplest solution: Try to copy the assemblies your application needs into the same folder where your application resides.
The following MSDN article explains How the Runtime Locates Assemblies.
Also, you may find more options (including copying all J# related dlls into a subfolder of the application folder if needed) in the following link when the runtime cannot find the assembly in the GAC: Locating the Assembly through Codebases or Probing
Without knowing anything about J# I can only suggest that you try just distributing the required libraries along with your program (place them in the same directory), I believe if it can't find the library in the GAC it will revert to look in the current directory.

How to prevent a .NET application from loading/referencing an assembly from the GAC?

Can I configure a .NET application in a way (settings in Visual Studio) that it references a "local" assembly (not in GAC) instead of an assembly within the GAC, although both assemblies have the same name and the same version?
If both assemblies are strong-named (signed), the CLR will always load from the GAC.
Here are the steps the runtime uses to resolve assembly references (from How the Runtime Locates Assemblies):
Determines the correct assembly version by examining applicable
configuration files, including the
application configuration file,
publisher policy file, and machine
configuration file. If the
configuration file is located on a
remote machine, the runtime must
locate and download the application
configuration file first.
Checks whether the assembly name has been bound to before and, if so,
uses the previously loaded assembly.
If a previous request to load the
assembly failed, the request fails
immediately without attempting to load
the assembly.
Checks the global assembly cache. If the assembly is found there, the
runtime uses this assembly.
Probes for the assembly (... some material omitted ...)
As stated later in that same article:
There is no version checking for assemblies without strong names, nor does the runtime
check in the global assembly cache for assemblies without strong names.
So if you can afford to remove signing from the local assembly, the application will use it instead of the one in the GAC.
For more detail than you could probably ever want about the runtime-binding mechanisms, see Suzanne Cook's blog.
This blog entry from Scott Hanselman also provides a great overview of the binding process.
If you can change the version number of the local dll, you can use a dll version redirect using the oldVersion attribute. You can use a strong name for the local assembly:
Please look this page:
http://msdn.microsoft.com/en-us/library/7wd6ex19.aspx
Also you should consider that it is possible to modify the version number of a compiled assembly like it is described here:
Change Assembly Version in a compiled .NET assembly
You can use ilmerge and merged the assemblies into a single library to get around it.
To successfully deploy your .NET Framework application, you must understand how the common language runtime locates and binds to the assemblies that make up your application. By default, the runtime attempts to bind with the exact version of an assembly that the application was built with. This default behavior can be overridden by configuration file settings.
You can view binding information in the log file using the Assembly Binding Log Viewer (Fuslogvw.exe), which is included in the Windows Software Development Kit (SDK).

Categories

Resources