2

My SQL CLR procedure depends on log4net, it depends on System.Web.dll.

When I upload this System.Web.dll :

create assembly [System.Web]
from 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.dll'
with permission_set = unsafe;
go

I see that yet 20 other assemblies added. Ok. How can I script this/these assemblies and upload them from binary in script?

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
ZedZip
  • 5,794
  • 15
  • 66
  • 119

1 Answers1

1

Good News (mostly)

If you have already loaded these assemblies into SQL Server, then you have two options. First, if you are using SSMS, you might be able to script out the assemblies. Just:

  1. right-click on the database name in Object Explorer, go to "Tasks ⏵", and select "Generate Scripts...".
  2. Choose "Select specific database objects" and choose the desires assemblies to script under "SQL Assemblies".
  3. Click the "Next >" button
  4. Select "Save as script file" and enter in the "File name:"
  5. Click the "Next >" button
  6. Click the "Next >" button

The scripted out objects might be in dependency order, in which case the CREATE ASSEMBLY statements don't need to be reordered.

If you get an error, you might need to save the report if you want the actual details. It could be:

SmoException: Cyclic dependencies found.

which is what I ran into when scripting out some .NET Framework libraries that I had loaded. Sooo....

The second option is to simply construct the CREATE ASSEMBLY statements by SELECTing their contents from the system catalog views:

SELECT N'CREATE ASSEMBLY ' + QUOTENAME(asm.[name]) + NCHAR(0x0A)
         + N' FROM ' + CONVERT(NVARCHAR(MAX), [content], 1) + NCHAR(0x0A)
         + N' WITH PERMISSION_SET = '
         + CASE asm.[permission_set]
                WHEN 3 THEN N'UNSAFE'
                ELSE asm.[permission_set_desc] COLLATE DATABASE_DEFAULT
           END
FROM   sys.assemblies asm
INNER JOIN sys.assembly_files asf
        ON asf.[assembly_id] = asm.[assembly_id]
WHERE  asf.[file_id] = 1
AND    asm.is_user_defined = 1
--AND    asm.[name] = N'{{assembly_name}}'
FOR XML AUTO, ELEMENTS;

Warning: Do NOT left-click on the returned XML value that should appear as a link and will open a new tab with what should be a formatted XML document if you do left-click on it. The returned value will most likely be too large for SSMS to handle (it certainly was on my system using SSMS 18.10) and it will just hang forever and you will need to forcibly kill the process (and I was just trying an assembly that was 4 MB). You likely have several assemblies that got loaded as dependencies and those sizes can add up quickly.

You will need to save the results by right-clicking anywhere in the "Results" tab and selecting "Save Results As...". I'm not sure if the "Save as type" matters as they are all text and there is only one value, but I usually select "All files (*.*)".

If the file is too big to open in a text editor or SSMS, you can uncomment the WHERE predicate filtering on [name] and do one at a time, or make it an IN list and do several at a time.

Also keep in mind that:

  1. You will need to remove the <asm> and </asm> tags.
  2. The values are not necessarily returned in an order that can be loaded, so you will have to test and might need to adjust the order of the CREATE ASSEMBLY statements.

Not-so-good News (potentially)

SQL Server checks the GAC for assemblies of the same name that are being referenced in SQL Server. If it finds any, it will check the version number and they must be the same (i.e. between the assembly in SQL Server and the one in the GAC). You will get an error if the version within SQL Server is different. This means, that if any of the .NET Framework assemblies that you are loading into SQL Server get updated via Windows Update (or even manual update of .NET), then you will probably need to drop these assemblies and reload them with what will then be the current version(s).

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • Honestly saying and after reading your notes: I do not want to load all these assemblies to SQL Server, especially System.Web. I am trying to find any other solution what to do in tis case. – ZedZip Jan 11 '22 at 07:16
  • Hi Solomon, by the way: what frameworks does SQL Server 2017 use? Is it 4.5 or fresher? I.e. I create SQLCLR function for SQL Server >=2017 : what NET should it use? – ZedZip Jan 11 '22 at 07:19
  • @ZedZip Given that you are using **log4net**, which depends on **System.Web**, which depends on all of the other libraries that got imported automatically when you loaded **System.Web**, your choices are: 1) load these assemblies as I have described, 2) load **System.Web** from disk (not from hex bytes) and have it automatically import the others, or 3) don't use **log4net**. As far as Framework versions is concerned, SQL Server 2012+ will use the highest Framework 4.x version loaded on the server. – Solomon Rutzky Jan 11 '22 at 16:29
  • Thank you, alles klar. My choice is (3) :-) – ZedZip Jan 12 '22 at 06:33
  • Hi Solomon, please look at this link, there is my another question about SQLCLR. I hope on your recommendation: https://stackoverflow.com/questions/70677325/sqlclr-how-to-load-these-dlls-to-sql-server-2017 Thank you – ZedZip Jan 12 '22 at 06:45