C # CLR Определяемая пользователем функция SqlBytes - InvalidOperationException - PullRequest
1 голос
/ 31 мая 2011


Я писал 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));
    }



};

1 Ответ

0 голосов
/ 01 июня 2011

Я обнаружил, что те заявления о подражании, которые у меня были там, остались от записи в тесты файловой системы, которые я делал.

Если я уберу приведенные ниже строки кода, тогда все будет работать как положено.

WindowsImpersonationContext newContext = null;

WindowsIdentity newIdentity = SqlContext.WindowsIdentity;

и

if (newIdentity != null) newContext = newIdentity.Impersonate(); 
...