sqlFileStream System.ComponentModel.Win32Exception: запрос не поддерживается - PullRequest
4 голосов
/ 15 сентября 2011

У меня SQL Server Express 2008 с пакетом обновления 1 (SP1) в Windows 7 (версия 6.1, сборка 7601: пакет обновления 1) и Visual Studio 2010.

Я пытаюсь создать 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);

Я получаю:

Ошибка .NET Framework во время выполненияпользовательская подпрограмма или агрегат 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)

Может кто-нибудь сказать мне, как решить эту проблему?Это просто, что я не могу выполнить код таким образом с SQL 2008 Express Edition?

Ответы [ 2 ]

1 голос
/ 11 мая 2018

Я думаю, что нашел рабочее решение здесь:

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
0 голосов
/ 17 сентября 2014

Как ни странно, но Microsoft намеренно заблокировал использование класса SqlFileStream в сборках SQL CLR (даже если вы предоставляете EXTERNAL_ACCESS или объявляете сборку как UNSAFE), как можете читать в выпуск Microsoft Connect 768308 .

Однако вы можете получить доступ к FILESTREAM в виде потока с помощью типа SqlBytes (очень хороший совет, найденный в сообщении в блоге ) .. по крайней мере для использования только для чтения, я никогда пробовал писать.

Я копирую код в случае исчезновения блога (в слегка улучшенной версии с правильным удалением объектов):

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));
        }
    }
}

Я могу подтвердить, что это определенно работает только для чтения. Я никогда не пытался получить доступ для записи (я пишу данные FILESTREAM из внешней службы C # Windows или веб-приложения).

...