Объединение FILESTREAM + API потоковой передачи (SqlFileStream) + Группы доступности (HADR) выдает "Неверное имя целевой учетной записи"
Я развертываю решение SQL Server с FILESTREAM и группами доступности, и после исчерпывающих усилий я не могу устранить эту ошибку:
Неверное имя целевой учетной записи
Приложение использует потоковый API (класс SqlFileStream в C#) в среде HADR, и это, кажется, токсичная комбинация. Так как:
1) Нет ошибок в среде без HADR, использующей T-SQL или потоковый API для доступа к данным FILESTREAM
2) Ошибка не возникает в среде HADR, использующей T-SQL для доступа к данным FILESTREAM
3) Ошибка возникает только в среде HADR, использующей потоковый API для доступа к данным FILESTREAM
Я создал минимальное приложение, чтобы воспроизвести проблему. Он делает ту же попытку записи с использованием потокового API для двух версий одной и той же базы данных с поддержкой FILESTREAM; один не в HADR (этот преуспевает), а другой в среде HADR (этот сбой).
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Transactions;
namespace TestFileStream
{
class Program
{
private const string ConnStrNoHadr =
"Data Source=pvsqledi01;Integrated Security=True;Initial Catalog=FileStreamTestNoHadr";
private const string ConnStrHadr =
"Data Source=pvsqledi01;Integrated Security=True;Initial Catalog=FileStreamTestHadr";
static void Main(string[] args)
{
Console.WriteLine($"Running as {Environment.UserDomainName}\\{Environment.UserName}");
Console.WriteLine("Press a key to start");
Console.ReadKey();
try
{
Run(ConnStrNoHadr, "NO HADR");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
Run(ConnStrHadr, "HADR");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("Done");
Console.ReadKey();
}
private static void Run(string connStr, string caption)
{
const string TSql = @"
INSERT INTO PhotoAlbum(PhotoDescription, Photo)
OUTPUT inserted.Photo.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT()
SELECT @PhotoDescription, 0x
";
Console.WriteLine();
Console.WriteLine($"*** {caption} ***");
using (var conn = new SqlConnection(connStr))
{
using (var cmd = new SqlCommand(TSql, conn))
{
using (var ts = new TransactionScope())
{
Console.WriteLine($"Open connection");
conn.Open();
cmd.Parameters.AddWithValue("@PhotoDescription", "Desc");
var serverPathName = default(string);
var serverTxnContext = default(byte[]);
Console.WriteLine($"Execute INSERT");
using (var rdr = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
rdr.Read();
serverPathName = rdr.GetSqlString(0).Value;
serverTxnContext = rdr.GetSqlBinary(1).Value;
rdr.Close();
}
conn.Close();
Console.WriteLine($"Path: {serverPathName}");
Console.WriteLine($"Open local FileStream for read");
using (var source = new FileStream(@"C:\Users\c1159\Desktop\CapLoad Local\Member\CacheTest\MyBlob.dat", FileMode.Open, FileAccess.Read))
{
Console.WriteLine($"Open SqlFileStream for write");
using (var dest = new SqlFileStream(serverPathName, serverTxnContext, FileAccess.Write))
{
Console.WriteLine($"Write BLOB");
source.CopyTo(dest, 1024 * 1024);
dest.Close();
}
source.Close();
}
Console.WriteLine($"BLOB has been saved successfully with SqlFileStream");
ts.Complete();
}
}
}
}
}
}
Вот вывод:
Запуск от имени IEHP\pedimssvc Нажмите клавишу, чтобы начать *** НЕТ ХАДР *** Открытое соединение Выполнить INSERT Путь: \\PVSQLEDI01\MSSQLSERVER\v02-A60EC2F8-2B24-11DF-9CC3-AF2E56D89593\FileStreamTestNoHadr\dbo\PhotoAlbum\Photo\EF638D14-A012-E811-80C1-005056B83DAB\ HardVoluTVVH Volume5 VolumeTmeVmeHD5 Откройте локальный FileStream для чтения Откройте SqlFileStream для записи Написать BLOB BLOB был успешно сохранен с SqlFileStream *** Хадр *** Открытое соединение Выполнить INSERT Путь: \\PVLISEDI01\SQLFILESTREAM\v02-A60EC2F8-2B24-11DF-9CC3-AF2E56D89593\FileStreamTestHadr\dbo\PhotoAlbum\Photo\F0638D14-A012-E811-80C1-005056B83DAB\VolumeHint5 Откройте локальный FileStream для чтения Откройте SqlFileStream для записи Неверное имя целевой учетной записи Готово
Ошибка возникает в строке, которая пытается открыть экземпляр SqlFileStream для записи:
using (var dest = new SqlFileStream(serverPathName, serverTxnContext, FileAccess.Write))
Я уже проверил следующее:
- Учетная запись пользователя Windows IEHP\pedimssvc является учетной записью службы приложения.
- Он имеет необходимые разрешения для SqlFileStream, о чем свидетельствует успешный результат в среде без HADR.
- В качестве проверки работоспособности я также попытался использовать ту же учетную запись службы, под которой работает сам SQL Server, и получил те же результаты; работает в среде без HADR, не работает в HADR.
- Я видел статью в https://docs.microsoft.com/en-us/sql/database-engine/availability-groups/windows/filestream-and-filetable-with-always-on-availability-groups-sql-server. Как объясняется в статье, имя компьютера (PVSQLEDI01) заменяется именем виртуальной сети (PVLISEDI01) в среде HADR. Вывод показывает, что.PathName() возвращает имя компьютера для базы данных, отличной от HADR, и возвращает VNN для базы данных HADR, чего я и ожидал. Также кажется, что имя общего ресурса изменилось с MSSQLSERVER для базы данных не-HADR на SQLFILESTREAM для базы данных HADR, и я не знаю почему. В отчаянии я попытался заменить имя общего ресурса обратно на MSSQLSERVER для базы данных HADR, но это не имело никакого значения.
- Напомним, что FILESTREAM работает в среде HADR с использованием T-SQL; например, INSERT... VALUES(0xF4E0239A...). И FILESTREAM работает в среде без HADR, используя потоковый API. Проблема возникает только при объединении потокового API со средой HADR.
Это критически важная система; и нам абсолютно необходимо, чтобы эта база данных была частью среды HADR. Так что любая помощь в решении проблемы очень ценится, спасибо!