4

Windows 7 (バージョン 6.1 ビルド 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エクスプレスエディションでこの方法でコードを実行できないということですか?

4

2 に答える 2

0

奇妙に聞こえるかもしれませんが、 Microsoft Connect issue 768308で読むことができるように、 Microsoft はSQL CLR アセンブリ内でのクラスの使用を意図的にブロックしました (アセンブリを付与または宣言したとしても) 。SqlFileStreamEXTERNAL_ACCESSUNSAFE

ただし、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 データを書き込んでいます)。

于 2014-09-17T14:41:18.923 に答える