除非标记为不安全,否则C#CLR引发安全异常
我在SQL Server 2012中有一个C#CLR(.NET 4.5)存储过程,它是从事务中调用的。CLR调用需要TLS 1.2的Web服务 如果我使用“创建具有权限集的程序集”=不安全,则一切正常,但我确实希望避免这种情况,而是使用外部访问。然而,事实证明这是一个真正的挑战 使用外部访问时存在两个问题:除非标记为不安全,否则C#CLR引发安全异常,c#,.net,sql-server,clr,sqlclr,C#,.net,Sql Server,Clr,Sqlclr,我在SQL Server 2012中有一个C#CLR(.NET 4.5)存储过程,它是从事务中调用的。CLR调用需要TLS 1.2的Web服务 如果我使用“创建具有权限集的程序集”=不安全,则一切正常,但我确实希望避免这种情况,而是使用外部访问。然而,事实证明这是一个真正的挑战 使用外部访问时存在两个问题: private static readonly object Locker = new object(); public static string LogMessage(string me
private static readonly object Locker = new object();
public static string LogMessage(string message)
{
message = String.Format("{0}: {1}" + Environment.NewLine, DateTime.Now, message);
lock (Locker)
{
var file = new FileStream(GetConfigValue("LogFile"), FileMode.Append, FileAccess.Write);
var sw = new StreamWriter(file);
sw.Write(message);
sw.Flush();
sw.Close();
}
return message;
}
1) 我从CLR写入一个日志文件(用于维护和调试),该文件不起作用,因为不允许使用锁:
private static readonly object Locker = new object();
public static string LogMessage(string message)
{
message = String.Format("{0}: {1}" + Environment.NewLine, DateTime.Now, message);
lock (Locker)
{
var file = new FileStream(GetConfigValue("LogFile"), FileMode.Append, FileAccess.Write);
var sw = new StreamWriter(file);
sw.Write(message);
sw.Flush();
sw.Close();
}
return message;
}
错误消息:
System.Security.HostProtectionException:试图执行CLR主机禁止的操作
受保护的资源(仅在完全信任的情况下可用)是:所有需要的资源是:同步、外部线程
我可以改为登录到数据库表,但由于对CLR的调用来自事务中,因此错误将导致回滚,这也将回滚日志记录。我可以使用事件日志,但如果可能的话,我真的不想这样做
2) 我调用的web服务需要TLS 1.2,但不允许设置ServerCertificateValidationCallback
:
ServicePointManager.ServerCertificateValidationCallback = AcceptAllCertifications;
错误消息:
System.Security.SecurityException:请求“System.Security.Permissions.SecurityPermission,mscorlib,版本=4.0.0.0,区域性=neutral,PublicKeyToken=b77a5c561934e089”类型的权限失败。System.Security.SecurityException:
在System.Security.CodeAccessSecurityEngine.Check(对象请求、堆栈爬网标记和堆栈标记、布尔isPermSet) 在System.Security.CodeAccessPermission.Demand()中 位于System.Net.ServicePointManager.set_服务器CertificateValidationCallback(RemoteCertificateValidationCallback值) 在AcmeClr.StoredProcedures.ProcessPayment(SqlMoney金额、SqlString票证号、SqlString和resultCode、SqlString和resultText) 这个问题有没有解决方法?有没有一种方法可以在不使用不安全的情况下工作?对于问题1(使用锁来管理同时写入同一日志文件的多个线程/会话),除了在
不安全
模式下使用锁之外,没有其他方法。然而,好消息是,您可能一开始就不需要使用锁。锁真正要做的就是确保同时发生的两个LogMessage()
调用不会发生冲突,其中一个会出错。这应该可以通过使用另一个允许传入选项/enum的重载来解决。您应该能够传入FileShare.ReadWrite
以防止出现错误。您已经在将DateTime.Now
连接到message
中,因此,如果先一条消息在后一条消息之后写入,这将有助于解决序列问题
但在这个特定争用之外,即使使用锁,您仍然会遇到两个会话在执行SQLCLR WebService存储过程的同时交错消息的问题。你如何区分这些信息?我建议在存储过程开始时创建一个新的Guid
,并将其连接到每条消息中,以便您可以将特定调用的消息关联到存储过程(我假设您的代码有多个调用LogMessage()
)的位置,并将这些消息与其他调用区分开来(不论是否同时进行)
如果出于任何原因,上面的两个部分(FileShare.ReadWrite
和将Guid连接到消息中
)不能防止错误发生,那么您可以忘记FileShare
选项(尽管我仍然更喜欢将其设置为Read
,以便在写入文件时可以轻松地检查文件)而不是将Guid连接到消息中
,而是将其附加到GetConfigValue(“日志文件”)的末尾
value,就在文件扩展名之前。然后,特定调用的消息会自动相互关联,并与其他并发调用区分开来。这只意味着您有一堆日志文件
关于这一点,还有三个想法:
日志消息()中设置锁
)
method,实际上您正在增加阻塞,因为跨不同会话对该方法的并发调用将必须等待锁所有者释放锁。毕竟,这是锁的第一点,对吗?除非在处理事务时,您真的不想延长它们超过绝对长度非常必要,通过SQLCLR进行Web服务调用的本质是,您已经在使事务依赖于网络延迟和外部系统的响应(即使是内部系统)Enlist
关键字,或者确实指定了Enlist=true;
,则使用常规/外部连接也是真的。但是,如果指定Enlist=false;
,则应该是独立/断开连接的事务,而不是如果调用存储过程的事务回滚,et将回滚