unable to deploy sql clr stored procedure (unable to verify metadata) - c#

I am trying to run the CREATE ASSEMBLY command for a SQL CLR (.Net 3.5) assembly on SQL Server 2008. It returns a cryptic error message:
An error occurred while gathering metadata from assembly 'My.Awesome.Assembly' with HRESULT 0x80004005.
Why is it doing this, and how can I fix it without deploying it as UNSAFE?
steps I have done:
Followed all rules in http://msdn.microsoft.com/en-us/library/ms403273.aspx
Used no static fields
Have created 2 other SQL CLR assemblies that deploy just fine

This is what solved the problem for me; for future reference to anyone out there, SQL CLR stuff is very, very picky.
I had a constructor like this:
public MyObject(IEnumerable<T> items)
{
_innerItems = items.ToDictionary(i => i.Key);
}
I changed it to this:
public MyObject(IEnumerable<T> items)
{
_innerItems = new Dictionary<int, T>();
foreach (var item in items)
{
_innerItems.Add(item.Key, item);
}
}
And it was then able to deploy. I then proceeded to pound my head against my desk. Two methods, functionally equivalent; one works, and one has a cryptic deployment error message.

Related

Code working unexpectedly after hosting in IIS

Below is the code to build a cache which stores (typeName,type) found in the assemblies loaded in the current app domain.
I am facing this weird issue when trying to load types from one particular assembly say assemblyK. The assemblyK has around 954 types. Logs are in sync and it works all well when locally hosted in Visual Studio. Also, when I deploy the website in IIS it works well in when the buildCache is called for the first time.
However when the application pool is restarted/ after calling it later, it runs the nested loop for only for 5 types and goes on to execute the next function i.e. it does not throw any exception and moves forward.
private static void BuildCache()
{
Assembly[] assemblies= AppDomain.CurrentDomain.GetAssemblies();
foreach(Assembly assembly in assemblies){
if(assembly.GlobalAssemblyCache){
if(assemblly.ToString().Contains("assemblyK"))
Logger.Log("GAC");
continue;
}
try
{
if(assembly.ToString().Contains("AssemblyK"))
{
string allTypes = string.Join(",",assembly.GetTypes().Select(x => x.ToString()).ToArray())
Logger.Log("All types :{0}",allTypes);
}
foreach(Type type in assembly.GetTypes())
{
if(assembly.ToString().Contains("AssemblyK"))
{
Logger.Log("Type parsed :{0}",type);
}
if(!typeCache.ContainsKey(type.FullName))
{
if(assembly.ToString().Contains("AssemblyK"))
{
Logger.Log("Adding to cache :{0}",type);
}
typeCache.Add(type.FullName,type);
}
}
catch(Exception ex)
{
Logger.Log("Exception Caught : {0}",ex.ToString());
}
}
}
Notably, The AssemblyK.dll build in Visual Studio 2008 in .Net 3.5 version works all well and when complied in Visual Studio 2019 causing the issue. Application Pool is 2.0. And the assemblyK is loaded in the "assemblies" always. Please Help.
P.S.: I copied the logs for allTypes received in both the cases(when it works and doesnt) in two files and did a file compare using cmd, with fc file1 file2.
Both contained the identical data i.e.954 types. So my question is how can the foreach run randomly? What could be the issue here?
Update : The logs read:
1) In Working case :
All Types : Type1,Type2,Type3,..Type954
Type Parsed 954 times
Adding to cache 954 times
2) In Not Working case :
All Types : Type1,Type2,Type3,..Type954.
Type Pased 4 Times.
typeCache is a private static readonly Dictionary

Runtime casting of COM objects in C#

I am working on a application which needs to communicate via COM interface with multiple CAD applications (not in the same time). I want to have nice and reusable code, but I came across problems with type casting of COM objects when I made generic application handle getter method.
What I tried so far:
This is the attempt I would like the most if it worked.
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
//Here under Dynamic View/Message there is already an error
// Message = "Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))"
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = (TCadAppType)Marshal.GetActiveObject(cadVersion.Value);
//Following 2 lines of code are for testing purposes only, i am testing with Solidworks API
AssemblyDoc Assembly;
//The exception is thrown when I try to access some method from the Solidworks API
Assembly = (AssemblyDoc)cadApp.OpenDoc6("some parametras...");
}
Attempt using Convert class
// Another attempt using Convert class
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = Marshal.GetActiveObject(cadVersion.Value);
cadApp = Convert.ChangeType(cadApp, typeof(SldWorks.SldWorks));
// Exception is thrown with the following message:
// Message = "Object must implement IConvertible."
}
I really thought that I am on the right track, since there is an article on Microsoft Docs website explaining how dynamic can help you with com interopt: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic#com-interop
Any ideas how I can do this runtime casting a keep my code as reusable as possible?
My software setup:
Win 10
Project is targeted for .NET 4.7.2
First Tests are with Solidworks 2019
Turns out that the my coding attempt 1 was valid c# code indeed.
I tried it using with Autodesk Inventor, and it works.
So the only thing left for me is to conclude that this is some bug from Solidworks and their COM interfacing.
Thank you Optional Option for your interest in the topic.

Cannot Debug CLR User Defined Type

I'm trying to debug a CLR User Defined Type in SQL Server 2014 / Visual Studio 2013. I can deploy my UDT to the database and execute the script that calls that UDT in the debugger from within visual studio but it throws an error and doesn't hit my breakpoint. The error happens in the static Parse method on the type.
My DBA thought it might be a permissions issue (preventing me from debugging, not the underlying error) but didn't have time to look into it. Any suggestions on what I need to do to debug my UDT?
The SQL Server is a local instance
Per request, the code of Parse:
public static SqlQueryDescriptor Parse(SqlString s)
{
if (s.IsNull)
return Null;
var queryDescriptor = new JsonSerializer().Deserialize<QueryDescriptor>(s.Value);
//var queryDescriptor = new QueryDescriptor();
SortContext sort = new SortContext();
if (queryDescriptor.Sorts != null)
{
foreach (var sortDescriptor in queryDescriptor.Sorts)
{
sort.AddSort(sortDescriptor.Property, sortDescriptor.Direction);
}
}
return new SqlQueryDescriptor(sort, queryDescriptor.Filters, queryDescriptor.Page);
}
The error is a NRE in the Json deserialization library, I need to debug to figure out why that is happening as I didn't write that library and imported it from the web. Although the break point still doesn't hit even if I don't use the deserializer (commented out line)

Context.CurrentMiningModel returns null in UDF

I migrated Mining Structures from a 2008 server to a 2012 server. When I try my CLR UDF (which is working fine on SQL server 2008) in a DMX query on the 2012 server, I am getting this error:
Exception has been thrown by the target of an invocation. Object reference not set to an instance of an object.
My original goal was to get the GetNodeDescription(...) method running. While debugging the problem, I could isolate the problem to this UDF which fails on my SQL server 2012
[SafeToPrepare(true)]
public static string test()
{
return Context.CurrentMiningModel.Name;
}
My guess is that CurrentMiningModel is null because the following code works fine
[SafeToPrepare(true)]
public static string testUser()
{
return Context.CurrentConnection.User.Name;
}
Any Idea on how to solve this?
Is somebody out there who can reproduce this?
Thanks.
Jan
UPDATE:
A contact at Microsoft confirmed this behaviour as desired due to a "Metadata-Refactoring" (whatever this means...). However, the website still pends to be updated appropiately.
This is not the ultimate answer but it's a workaround to get Microsoft's GetNodeDescription working (by explicitly providing the mining model):
[SafeToPrepare(true)]
public static string GetNodeDescription(string MiningModel, string nodeUniqueName)
{
if (Context.ExecuteForPrepare)
{
return string.Empty;
}
return Context.MiningModels[MiningModel].GetNodeFromUniqueName(nodeUniqueName).Descript‌​ion;
}

How do I use the Mono.CSharp interpreter in Microsoft.NET

I was under the impression Mono's compiler was usable in Microsoft.NET
edit: updated blog posting here that I originally missed that explains some of it (is consistent with Justin's answers)
I created a simple class to try to use it
[TestFixture]
class Class1
{
[Test]
public void EXPR()
{
Evaluator.Run("using System;");
int sum = (int)Evaluator.Evaluate("1+2");
}
}
And a project in Visual Studio 2010 that references C:\Program Files (x86)\Mono-2.10.1\lib\mono\4.0\Mono.CSharp.dll.
However when I try to run this task I get the following exception, thrown at the Evaluator.Run call:
System.TypeInitializationException was unhandled by user code
Message=The type initializer for 'Mono.CSharp.Evaluator' threw an exception.
Source=Mono.CSharp
TypeName=Mono.CSharp.Evaluator
StackTrace:
at Mono.CSharp.Evaluator.Run(String statement)
at Experiments.Class1.EXPR() in W:\Experiments\Class1.cs:line 16
InnerException: System.TypeLoadException
Message=Method 'Mono.CSharp.Location.ToString()' is security transparent, but is a member of a security critical type.
Source=Mono.CSharp
TypeName=Mono.CSharp.Location.ToString()
StackTrace:
at Mono.CSharp.Evaluator..cctor()
InnerException:
A google confirms one other person asking this question but no answer. I tried to start reading the microsoft article on security transparent code but got confused quite quickly. Would someone be able to suggest a quick workaround to allow me to use this? And possibly summarise the security implications, if any, to me (in the context of my situation - in the future I hope to package it with a thick client application, to be used both internally and by end-users)
It has worked under .NET since April of last year.
Small point but I notice you are missing a semi-colon in your expression for sum.
int sum = (int)Evaluator.Evaluate("1+2;");
I only have Mono 2.11 (from git) at the moment and they have changed to using a multi-instance version of the compiler instead of the static version. So, my code looks a little different:
using System;
using Mono.CSharp;
namespace REPLtest
{
class MainClass
{
public static void Main (string[] args)
{
var r = new Report (new ConsoleReportPrinter ());
var cmd = new CommandLineParser (r);
var settings = cmd.ParseArguments (args);
if (settings == null || r.Errors > 0)
Environment.Exit (1);
var evaluator = new Evaluator (settings, r);
evaluator.Run("using System;");
int sum = (int) evaluator.Evaluate("1+2;");
Console.WriteLine ("The sum of 1 + 2 is {0}", sum);
}
}
}
EDIT: I guess I should confirm that I did in fact successfully execute this on .NET 4 (using Visual C# Express 2010 on Windows XP)
EDIT AGAIN: If you have Visual Studio, you can download the latest version of Mono.CSharp and compile it yourself. There is a .sln (solution file) included with the source so you can build it on Windows without Mono. The resulting assembly would run the code above. Miguel has a post explaining the new Mono.CSharp here.
FINAL EDIT: I uploaded the compiled Mono.CSharp.dll assembly that I actually used here. Include it as a reference to compile the code above.
It looks like this is a bug in Mono.
.NET 4 abandoned Code Access Security but kept the concept of Security Transparent Code. In a nutshell, low-level code that does stuff, like call unmanaged code, must be "security critical". Application level code is marked "transparent". "Transparent" code cannot call into "security critical" code.
It sounds like Mono.CSharp.Location.ToString() needs to be marked with the [SecuritySafeCritical] attribute if you want the Mono 2.10 code to work with .NET 4. Maybe even better would be marking all of Mono.CSharp as SecuritySafeCritical.
http://msdn.microsoft.com/en-us/library/system.security.securitycriticalattribute.aspx
PS. Sorry to have multiple answers for one question. After I realized that 2.11 would work, I became more curious about what the error with 2.10 meant. I cannot really combine this answer with the others.
I decided I should have kept the code more like the question but I did not want to overwrite my previous answer:
The code below works with version 2.11 of Mono.CSharp (available here including a solution file for building with Visual Studio/.NET). It was tested with .NET 4 on Windows XP. I do not have access to Mono 2.10 at the moment.
[TestFixture]
class Class1
{
private Evaluator evaluator;
public Class1()
{
var report = new Report(new ConsoleReportPrinter());
evaluator = new Evaluator(new CompilerSettings(), report);
}
[Test]
public void EXPR()
{
evaluator.Run("using System;");
int sum = (int)evaluator.Evaluate("1+2;");
}
}
EDIT: I uploaded the Mono.CSharp.dll assembly that I actually used here. Include it as a reference to compile the code above.

Categories