sqlFileStream System.ComponentModel.Win32Exception:不支持该请求

发布于 2024-12-04 18:12:42 字数 3835 浏览 0 评论 0 原文

我在 Windows 7(版本 6.1 Build 7601:Service Pack 1)和 Visual Studio 2010 上有 SQL Server Express 2008 SP1。

我尝试使用以下代码创建一个存储过程 CLR,用于将文件插入到文件流中。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Security.Principal;

public partial class StoredProcedures
{
     [Microsoft.SqlServer.Server.SqlProcedure]
     public static void sp_fileController(String friendlyName, String filePath)
{
    SqlParameter fDataParam = new System.Data.SqlClient.SqlParameter("@fData", SqlDbType.VarBinary, -1);
    SqlParameter fNameParam = new System.Data.SqlClient.SqlParameter("@fName", SqlDbType.NVarChar, 300);

    WindowsIdentity newId = SqlContext.WindowsIdentity;
    WindowsImpersonationContext impersonatedUser = newId.Impersonate();

    try
    {
        string cs = @"Server=[myservername];Integrated Security=true";
        using (SqlConnection con = new SqlConnection(cs))
        {
            con.Open();
            SqlTransaction objSqlTran = con.BeginTransaction();

            //string sql = "INSERT INTO fileStreamTest VALUES ((Cast('' As varbinary(Max))), @fName, default); Select fData.PathName() As Path From fileStreamTest Where fId = SCOPE_IDENTITY()";//OUTPUT inserted.fid 
            SqlCommand insertFileCommand = con.CreateCommand();

            insertFileCommand.Transaction = objSqlTran;

            insertFileCommand.CommandText = "INSERT INTO fileStreamTest.dbo.fileStreamTest (RowGuid, fData) VALUES (@FileID, CAST ('' as varbinary(max)))";

            Guid newFileID = Guid.NewGuid();

            insertFileCommand.Parameters.Add("@FileID", SqlDbType.UniqueIdentifier).Value = newFileID;

            insertFileCommand.ExecuteNonQuery();

            SqlCommand getPathAndTokenCommand = con.CreateCommand();

            getPathAndTokenCommand.Transaction = objSqlTran;

            getPathAndTokenCommand.CommandText =
                "SELECT fData.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() " +
                "FROM   fileStreamTest.dbo.fileStreamTest " +
                "WHERE  rowGuid = @FileID";

            getPathAndTokenCommand.Parameters.Add("@FileID", SqlDbType.UniqueIdentifier).Value = newFileID;

            SqlDataReader tokenReader = getPathAndTokenCommand.ExecuteReader(CommandBehavior.SingleRow);

            tokenReader.Read();

            SqlString filePathName = tokenReader.GetSqlString(0);

            SqlBinary fileToken = tokenReader.GetSqlBinary(1);

            tokenReader.Close();

            SqlFileStream sqlFile = new SqlFileStream(filePathName.Value, fileToken.Value, System.IO.FileAccess.ReadWrite);
            sqlFile.Close();

            objSqlTran.Rollback();
            //objSqlTran.Commit();
            con.Close();

        }
    }
    finally
    {
        impersonatedUser.Undo();
    }
}
};

但是,当它到达该行时:

SqlFileStream sqlFile = new SqlFileStream(filePathName.Value, fileToken.Value, System.IO.FileAccess.ReadWrite);

我得到:

执行用户定义的例程或聚合“sp_fileController”期间发生.NET Framework错误:

System.ComponentModel.Win32Exception: The request is not supported
System.ComponentModel.Win32Exception: 
   at System.Data.SqlTypes.SqlFileStream.OpenSqlFileStream(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
   at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
   at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access)
   at StoredProcedures.sp_fileController(String friendlyName, String filePath)

任何人都可以告诉我如何解决此问题吗?仅仅是因为我无法使用 sql 2008 Express 版本以这种方式执行代码吗?

I have SQL server express 2008 SP1 on windows 7 (Version 6.1 Build 7601: Service Pack 1) and visual studio 2010.

I am attempting to create a Stored Procedure CLR for inserting a file into a file stream using the following code.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Security.Principal;

public partial class StoredProcedures
{
     [Microsoft.SqlServer.Server.SqlProcedure]
     public static void sp_fileController(String friendlyName, String filePath)
{
    SqlParameter fDataParam = new System.Data.SqlClient.SqlParameter("@fData", SqlDbType.VarBinary, -1);
    SqlParameter fNameParam = new System.Data.SqlClient.SqlParameter("@fName", SqlDbType.NVarChar, 300);

    WindowsIdentity newId = SqlContext.WindowsIdentity;
    WindowsImpersonationContext impersonatedUser = newId.Impersonate();

    try
    {
        string cs = @"Server=[myservername];Integrated Security=true";
        using (SqlConnection con = new SqlConnection(cs))
        {
            con.Open();
            SqlTransaction objSqlTran = con.BeginTransaction();

            //string sql = "INSERT INTO fileStreamTest VALUES ((Cast('' As varbinary(Max))), @fName, default); Select fData.PathName() As Path From fileStreamTest Where fId = SCOPE_IDENTITY()";//OUTPUT inserted.fid 
            SqlCommand insertFileCommand = con.CreateCommand();

            insertFileCommand.Transaction = objSqlTran;

            insertFileCommand.CommandText = "INSERT INTO fileStreamTest.dbo.fileStreamTest (RowGuid, fData) VALUES (@FileID, CAST ('' as varbinary(max)))";

            Guid newFileID = Guid.NewGuid();

            insertFileCommand.Parameters.Add("@FileID", SqlDbType.UniqueIdentifier).Value = newFileID;

            insertFileCommand.ExecuteNonQuery();

            SqlCommand getPathAndTokenCommand = con.CreateCommand();

            getPathAndTokenCommand.Transaction = objSqlTran;

            getPathAndTokenCommand.CommandText =
                "SELECT fData.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() " +
                "FROM   fileStreamTest.dbo.fileStreamTest " +
                "WHERE  rowGuid = @FileID";

            getPathAndTokenCommand.Parameters.Add("@FileID", SqlDbType.UniqueIdentifier).Value = newFileID;

            SqlDataReader tokenReader = getPathAndTokenCommand.ExecuteReader(CommandBehavior.SingleRow);

            tokenReader.Read();

            SqlString filePathName = tokenReader.GetSqlString(0);

            SqlBinary fileToken = tokenReader.GetSqlBinary(1);

            tokenReader.Close();

            SqlFileStream sqlFile = new SqlFileStream(filePathName.Value, fileToken.Value, System.IO.FileAccess.ReadWrite);
            sqlFile.Close();

            objSqlTran.Rollback();
            //objSqlTran.Commit();
            con.Close();

        }
    }
    finally
    {
        impersonatedUser.Undo();
    }
}
};

However when it gets to the line:

SqlFileStream sqlFile = new SqlFileStream(filePathName.Value, fileToken.Value, System.IO.FileAccess.ReadWrite);

I get:

A .NET Framework error occurred during execution of user-defined routine or aggregate "sp_fileController":

System.ComponentModel.Win32Exception: The request is not supported
System.ComponentModel.Win32Exception: 
   at System.Data.SqlTypes.SqlFileStream.OpenSqlFileStream(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
   at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access, FileOptions options, Int64 allocationSize)
   at System.Data.SqlTypes.SqlFileStream..ctor(String path, Byte[] transactionContext, FileAccess access)
   at StoredProcedures.sp_fileController(String friendlyName, String filePath)

Can anyone tell me how to fix this issue? Is simply that I cannot execute the code in this manner with sql 2008 express edition?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱桃奶球 2024-12-11 18:12:42

我想我在这里找到了工作解决方案:

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/f49def09-3b47-4e54-8a53-2dd47762821e/filestream-on-windows-server-2012-the-request-is-not -supported?forum=sqldatabaseengine

总结:添加注册表项解决了 SQL Server 上的问题11.0.7001:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\FsctlAllowlist]
"FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT"=dword:0x00092560

I think I have found working solution here:

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/f49def09-3b47-4e54-8a53-2dd47762821e/filestream-on-windows-server-2012-the-request-is-not-supported?forum=sqldatabaseengine

To sum up: Adding registry key solved the problem on SQL Server 11.0.7001:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\FsctlAllowlist]
"FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT"=dword:0x00092560
还给你自由 2024-12-11 18:12:42

听起来很奇怪,微软故意阻止在 SQL CLR 程序集中使用 SqlFileStream 类用法(即使您授予 EXTERNAL_ACCESS 或声明程序集作为UNSAFE),正如您可以在Microsoft Connect 问题 768308< /a>.

但是,您可以通过 SqlBytes 类型将 FILESTREAM 作为流进行访问(在 博客文章)..至少对于只读用途,我从未尝试过写作。

我复制了代码,以防博客消失(在稍微改进的版本中,正确处理对象):

using System;
using System.IO;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Cryptography;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, SystemDataAccess = SystemDataAccessKind.None)]
    public static SqlBinary Hash(SqlBytes source, SqlString hashAlgorithmName)
    {
        if (Source.IsNull) 
        {
            return null;
        }

        using (HashAlgorithm ha = GetHashAlgotithm(hashAlgorithmName.Value)) 
        using (Stream stream = Source.Stream) 
        {
            return new SqlBinary(ha.ComputeHash(source.Stream));
        }
    }
}

我可以确认这绝对适用于只读访问。我从未尝试过写入访问(我正在从外部 C# Windows 服务或 Web 应用程序写入 FILESTREAM 数据)。

As odd as it sounds Microsoft intentionally blocked the use of the SqlFileStream class usages inside SQL CLR assemblies (even if you grant EXTERNAL_ACCESS or declare the assembly as UNSAFE) as you can read in Microsoft Connect issue 768308.

However you can access the FILESTREAM as a stream by the means of the SqlBytes type (a really nice tip found on a blog post).. at least for read-only use, I've never tried writing.

I copy-past the code in case the blog disappears (in a slightly improved version with proper disposal of objects):

using System;
using System.IO;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Cryptography;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, SystemDataAccess = SystemDataAccessKind.None)]
    public static SqlBinary Hash(SqlBytes source, SqlString hashAlgorithmName)
    {
        if (Source.IsNull) 
        {
            return null;
        }

        using (HashAlgorithm ha = GetHashAlgotithm(hashAlgorithmName.Value)) 
        using (Stream stream = Source.Stream) 
        {
            return new SqlBinary(ha.ComputeHash(source.Stream));
        }
    }
}

I can confirm this definitely works for read-only access. I've never tried for write access (I'm writing FILESTREAM data from an external C# Windows Service or Web Application).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文