Ответ 1
Глядя на исходный источник Microsoft, я мог видеть, что настройка свойства ReadMode
просто вызывает функцию win32 SetNamedPipeHandleState
для выполнения операции, при этом ошибки этого вызова возникают как исключения. В соответствии с документацией Функция SetNamedPipeHandleState в ней указывается о дескрипторе канала, чтобы вызвать эту функцию
дескриптор должен иметь доступ GENERIC_WRITE к именованному каналу для только для записи или чтения/записи, или он должен иметь GENERIC_READ и FILE_WRITE_ATTRIBUTES доступ для канала только для чтения.
В этом и заключается проблема.
Если мы посмотрим на конструкторы для NamedPipeClientStream, которые принимают параметр PipeDirection
, мы видим, что они запрашивают только GENERIC_READ
доступ для PipeDirection.In
и GENERIC_WRITE
доступ для PipeDirection.Out
(или оба для InOut
). Это означает, что любая труба, открытая в режиме Out
или InOut
, будет работать, поскольку для этих случаев достаточно доступа GENERIC_WRITE
, но нам нужны как GENERIC_READ
, так и FILE_WRITE_ATTRIBUTES
для канала только для чтения, который NamedPipeClientStream
класс никогда не запрашивает. Это дефект в классе и должен быть исправлен Microsoft.
Я отправил отчет об ошибке в Microsoft Connect здесь:
https://connect.microsoft.com/VisualStudio/feedback/details/1825187
Пожалуйста, проголосуйте, если вы столкнетесь с этой проблемой самостоятельно, это может помочь ускорить исправление.
До исправления (ни один из 3/2017) эту проблему можно обойти полностью, используя другой конструктор для NamedPipeClientStream
.
Вместо этого существует одна перегрузка конструктора, который принимает вместо перечисления PipeDirection
перечисление PipeAccessRights
, где вы можете указать конкретную комбинацию прав доступа, которые вы хотите получить для дескриптора. Затем конструктор выводит направление канала из комбинации указанных прав доступа (In
, если указан ReadData
, Out
", если указан WriteData
, InOut
, если они оба указаны).
Это означает, что вы можете решить эту проблему, не делая ваши дуплексные дуги, просто меняя конструкторную строку следующим образом:
var pipeIn = new NamedPipeClientStream("<ServerName>", "<PipeName>", PipeDirection.In);
:
var pipeIn =
new NamedPipeClientStream("<ServerName>",
"<PipeName>",
PipeAccessRights.ReadData | PipeAccessRights.WriteAttributes,
PipeOptions.None,
System.Security.Principal.TokenImpersonationLevel.None,
System.IO.HandleInheritability.None);
Если вы используете этот альтернативный конструктор в качестве предлагаемого обходного пути, результат будет идентичным и неотличимым от результата, который вы получите из первой формы конструктора, за исключением того, что это дополнительное право доступа будет получено, чтобы сообщение режим может быть включен.