簡體   English   中英

C# CLR 用戶定義 Function SqlBytes - InvalidOperationException

[英]C# CLR User Defined Function SqlBytes - InvalidOperationException


我一直在編寫從存儲過程調用的 sql clr udf 以將未知文件類型(jpg、doc、pdf 等)保存到文件系統。 UFD 接受一個 SqlBytes 類型的參數,該參數從調用存儲過程(這是文件 blob)傳遞一個 varbinary(max)。 問題是,在 CLR UDF 的上下文中,我無法訪問 value 屬性,甚至無法訪問 SqlBytes 文件參數的 read 方法,因為它返回以下無效異常錯誤。

我縮短了我的 UDF 以突出提到的問題。 任何幫助將非常感激。

提前致謝。


錯誤

在這種情況下不允許數據訪問。 上下文是 function 或未使用DataAccessKind.ReadSystemDataAccessKind.Read標記的方法,是從表值 Function 的 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;

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM