【发布时间】:2011-09-05 04:28:48
【问题描述】:
我一直在编写一个从存储过程调用的 sql clr udf,以将未知文件类型(jpg、doc、pdf 等)保存到文件系统。 UFD 接受一个 SqlBytes 类型的参数,该参数从调用存储过程(这是文件 blob)传递一个 varbinary(max)。问题是在 CLR UDF 的上下文中,我无法访问 value 属性,甚至无法访问 SqlBytes 文件参数的读取方法,因为它返回以下无效异常错误。
我已经缩短了我的 UDF 以突出提到的问题。任何帮助将不胜感激。
提前致谢。
错误
在此上下文中不允许数据访问。上下文要么是未标记DataAccessKind.Read 或SystemDataAccessKind.Read 的函数或方法,要么是从表值函数的FillRow 方法获取数据的回调,要么是UDT 验证方法。
堆栈跟踪
at System.Data.SqlServer.Internal.ClrLevelContext.CheckSqlAccessReturnCode(SqlAccessApiReturnCode eRc)
at System.Data.SqlServer.Internal.ClrLevelContext.XvarProxyRead(CClrXvarProxy* pXvarProxy, UInt64 iPosition, Byte* pbBuffer, UInt32 cbCount)
at System.Data.SqlServer.Internal.ClrLevelContext.System.Data.SqlServer.Internal.IXvarProxyAccessor.XvarProxyRead(CClrXvarProxy* , UInt64 , Byte* , UInt32 )
at System.Data.SqlServer.Internal.StreamOnBlobHandle.Read(Byte* pbBuffer, UInt64 offset, UInt32 count)
at System.Data.SqlServer.Internal.XvarBlobStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.BufferedStream.Read(Byte[] array, Int32 offset, Int32 count)
at System.Data.SqlTypes.SqlBytes.Read(Int64 offset, Byte[] buffer, Int32 offsetInBuffer, Int32 count)
at UserDefinedFunctions.SaveFileToFS(SqlBytes file, String fileName, String fileExtension, String path)
CLR 代码
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read, SystemDataAccess = SystemDataAccessKind.Read)]
public static SqlString SaveFileToFS(SqlBytes file)
{
WindowsImpersonationContext newContext = null;
WindowsIdentity newIdentity = SqlContext.WindowsIdentity;
try
{
if (newIdentity != null) newContext = newIdentity.Impersonate();
byte[] buffer = new byte[8040 * 4];
long offset = 0;
long read = 0;
//This file.Read will throw an error
read = file.Read(offset, buffer, 0, buffer.Length);
//this line will throw the same error
buffer = (byte[])file.Value;
catch (System.Exception ex1)
{
throw ex1;
}
finally
{
if (newContext != null) newContext.Undo();
}
return new SqlString("Success");
}
};
所以只是为了完成这个线程 - 这是 CLR UDF 的基本 POC 代码,它接受 varbinary(max) 文件 blob、文件名、文件扩展名和要写入的路径,然后将其保存到定义的文件系统位置(前提是它具有适当的文件系统权限)。希望它可以帮助某人:-)
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read , SystemDataAccess = SystemDataAccessKind.Read )]
public static SqlString SaveFileToFS(SqlBytes file, string fileName, string fileExtension, string path)
{
WindowsImpersonationContext newContext = null;
WindowsIdentity newIdentity = SqlContext.WindowsIdentity;
try
{
long length = file.Length ;
byte[] buffer = file.Value;
long offset = 0;
long read = 0;
int times = 0;
if (newIdentity != null) newContext = newIdentity.Impersonate();
FileStream fs = new FileStream(path + fileName + fileExtension, System.IO.FileMode.Create, System.IO.FileAccess.Write);
while (length > 1000)
{
fs.Write(buffer, 1000 * times, 1000);
length -= 1000;
times++;
}
fs.Write(buffer, 1000 * times, (int)length);
fs.Close();
}
catch (System.Exception ex1)
{
throw ex1;
}
finally
{
if (newContext != null) newContext.Undo();
}
return new SqlString(string.Format("Saved file: {0}{1} to path: {2}", fileName, fileExtension, path));
}
};
【问题讨论】:
-
我发现这是我在里面的假冒声明。如果我删除 'WindowsImpersonationContext newContext = null;'和'WindowsIdentity newIdentity = SqlContext.WindowsIdentity;'和'如果(newIdentity!= null)newContext = newIdentity.Impersonate();'它有效
标签: c# sql-server-2008 clr filestream invalidoperationexception