Я писал sql clr udf, который вызывается из хранимой процедуры, чтобы сохранить неизвестный тип файла (jpg, doc, pdf и т. Д.) В файловой системе. UFD принимает параметр типа SqlBytes, которому передается переменная varbinary (max) из вызывающего хранимого процесса (это файловый BLOB-объект). Проблема заключается в том, что в контексте пользовательской функции CLR я не могу получить доступ к свойству значения или даже к методу чтения параметра файла SqlBytes, так как он возвращает ошибку недопустимого исключения ниже.
Я сократил свой UDF, чтобы просто подчеркнуть упомянутую проблему. Любая помощь будет высоко ценится.
Заранее спасибо.
ERROR
Доступ к данным в этом контексте не разрешен. Либо контекст представляет собой функцию или метод, не помеченный 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 CODE
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");
}
};
Так что просто для завершения этой цепочки - вот основной код POC для пользовательской функции CLR, которая принимает файловый BLOB-объект (max), имя файла, расширение файла и путь для записи, а затем сохраняет его в определенной файловой системе. местоположение (при условии, что оно имеет соответствующие разрешения файловой системы). Надеюсь, это кому-нибудь поможет: -)
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));
}
};