Как устранить ошибку преобразования имени при отправке сообщений MSMQ

Недавно я следил за эта статья о том, как настроить стороннюю систему очередей с помощью MSMQ, в которой издатель, сервер очередей и подписчик находятся в разных системах в домене Active Directory. Мне удалось завершить часть 1 и первую половину части 2. Однако, когда я продолжаю вторую половину части 2 и включаю безопасность транспорта, я получаю следующую ошибку: An error occurred when converting the 'mymsmqservermachine.mydomain.network.ads\private$\Path/To/MyQueuedService.svc' queue path name to the format name: Unrecognized error -1072824300 (0xc00e0014). All operations on the queued channel failed. Ensure that the queue address is valid. MSMQ must be installed with Active Directory integration enabled and access to it is available.

Я проверил следующее:

  1. Интеграция с Active Directory для MSMQ включена на всех компьютерах в сторонней системе согласно это сообщение StackOverflow.
  2. URL-адрес очереди остается точно таким же, каким он был до включения безопасности, которая работала просто отлично, никаких ошибок синтаксического анализа.
  3. Я следовал инструкциям Windows при установке MSMQ здесь.

Соответствующие части трассировки стека, которые я получаю:

at System.ServiceModel.Channels.MsmqFormatName.FromQueuePath(String queuePath)
   at System.ServiceModel.Channels.MsmqUri.ActiveDirectory.UriToFormatName(Uri uri)
   at System.ServiceModel.Channels.MsmqOutputChannel.OpenQueue()
 --- End of inner exception stack trace ---

Server stack trace: 
   at System.ServiceModel.Channels.MsmqOutputChannel.OpenQueue()
   at System.ServiceModel.Channels.MsmqOutputChannel.OnOpenCore(TimeSpan timeout)
   at System.ServiceModel.Channels.MsmqOutputChannel.OnBeginOpen(TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.CommunicationObject.OpenAsyncResult.InvokeOpen()
   at System.ServiceModel.Channels.CommunicationObject.OpenAsyncResult..ctor(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.CommunicationObject.BeginOpen(TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.ServiceChannel.OnBeginOpen(TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.CommunicationObject.OpenAsyncResult.InvokeOpen()
   at System.ServiceModel.Channels.CommunicationObject.OpenAsyncResult..ctor(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.CommunicationObject.BeginOpen(TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.BeginCall(ServiceChannel channel, TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.BeginCallOnce(TimeSpan timeout, CallOnceManager cascade, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.ServiceChannel.BeginEnsureOpened(TimeSpan timeout, AsyncCallback callback, Object state)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.StartEnsureOpen(Boolean completedSynchronously)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.FinishEnsureInteractiveInit(IAsyncResult result, Boolean completedSynchronously)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.StartEnsureInteractiveInit()
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.Begin()
   at System.ServiceModel.Channels.ServiceChannel.BeginCall(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, TimeSpan timeout, AsyncCallback callback, Object asyncState)
   at System.ServiceModel.Channels.ServiceChannel.BeginCall(ServiceChannel channel, ProxyOperationRuntime operation, Object[] ins, AsyncCallback callback, Object asyncState)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2,TArg3](Func`6 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, TArg3 arg3, Object state, TaskCreationOptions creationOptions)
   at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.CreateTask(ServiceChannel channel, ProxyOperationRuntime operation, Object[] inputParameters)
   at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.CreateTask(ServiceChannel channel, IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

Судя по содержимому трассировки стека, ошибка возникает из-за разрешения имени очереди в Active Directory. Я пробовал следующее, чтобы попытаться устранить такой сбой:

  1. Упрощение имени, чтобы оно не содержало точек или косых черт (не сработало)
  2. Использование общедоступной очереди вместо приватной в случае, если этот шаг был пропущен в исходном руководстве на MSDN (это не было, не сработало)

На данный момент у меня нет идей. Кто-нибудь сталкивался с этой ошибкой при использовании WCF с привязками net.msmq раньше и решил свою проблему?

РЕДАКТИРОВАТЬ: при запуске следующего тестового кода с того же компьютера и того же пользователя я могу отлично отправить сообщение в очередь:

Me.TestContext.WriteLine("Executing under user '{0}'", WindowsIdentity.GetCurrent().Name)

Dim msg = New System.Messaging.Message()

msg.Body = "This is a test message"
msg.Label = "Test Message"
msg.Formatter = new ActiveXMessageFormatter()

Dim queue = new MessageQueue("FormatName:DIRECT=OS:mymsmqservermachine.mydomain.network.ads\private$\Path/To/MyQueuedService.svc")

queue.Send(msg)

person Alex Marshall    schedule 29.08.2016    source источник
comment
Вы говорите, что проблема появляется только тогда, когда вы включаете безопасность транспорта, поэтому это должна быть проблема аутентификации/сертификации, а не проблема, связанная с тем, как вы называете очередь. Я понимаю, что 0xc00e0014 означает MQ_ERROR_ILLEGAL_QUEUE_PATHNAME, но это, вероятно, отвлекающий маневр.   -  person John Breakwell    schedule 30.08.2016
comment
Например, это может быть проблема со временем: blogs.msdn.microsoft.com/johnbreakwell/2008/11/18/   -  person John Breakwell    schedule 30.08.2016
comment
@JohnBreakwell Хорошая идея, я не подумал об этом. Я только что исследовал, и моя машина находится в пределах 1 секунды от контроллера домена, они оба синхронизированы по сети.   -  person Alex Marshall    schedule 30.08.2016
comment
Будет ли работать ваш тестовый код, если вы включите опцию «Аутентифицированный» в свойствах очереди? Было бы интересно узнать, получите ли вы в результате 0xC00E002F — MQ_ERROR_NO_INTERNAL_USER_CERT.   -  person John Breakwell    schedule 30.08.2016
comment
@JohnBreakwell Когда я включаю «Аутентифицированный», ничего не происходит: метод «Отправить» не генерирует исключений, и ничего не попадает в очередь. Никакие сообщения не помещаются в очередь, никакие сообщения не заносятся в журнал, и ничего не помещается в системную очередь «Недоставленных сообщений».   -  person Alex Marshall    schedule 31.08.2016
comment
@JohnBreakwell Убедитесь, что, как только я устанавливаю queue.Authenticated = True, я получаю сообщение об ошибке The specified format name does not support the requested operation. For example, a direct queue format name cannot be deleted   -  person Alex Marshall    schedule 01.09.2016


Ответы (1)


По чистой случайности я наткнулся на решение и записал это в свой блог.

Суть решения заключалась в том, что мне пришлось добавить удостоверение DNS для моей привязки конечной точки WCF в моем клиенте:

Dim endpointAddress = New EndpointAddress(queueUri, EndpointIdentity.CreateDnsIdentity(queueUri.Host))

Dim netMsmqBinding = New NetMsmqBinding With
{
    .Durable = true,
    .ExactlyOnce = false,
    .UseActiveDirectory = false,
    .Security = New NetMsmqSecurity With
    {
        .Mode = NetMsmqSecurityMode.Transport
    }
}

Return New ChannelFactory(Of ICwteCentralPublishingServiceChannel)(netMsmqBinding, endpointAddress)

Я извиняюсь перед всем миром за код Visual Basic, это устаревшее приложение, и я его не выбирал.

person Alex Marshall    schedule 31.08.2016