После установки четвёртого пакета обновлени (Update Rollup 4) внезапно перестали работать клиентские REST-запросы из форм действий: задач, эл. писем, кастомных действий. Каждый вызов REST заканчивался ошибкой Error: 400: Bad Request: "Сервер обнаружил ошибку при обработке запроса. Дополнительные сведения см. в журналах сервера." (The server encountered an error processing the request. See server logs for more details.).

Пример запроса:
http://server/contoso/XRMServices/2011/OrganizationData.svc/AccountSet(guid'3F54544D-0BD7-4FC2-B38E-1E6BC2785DF9')?$select=Address1_PostalCode,Address1_StateOrProvince,Address1_City,Address1_Line1
Причём тот же самый запрос выполненный напрямую из адресной строки браузера отрабатывал успешно.
Трассировка CRM показала наличие управляющих символов в теле запроса: "Указанное значение содержит недопустимые знаки управления. Имя параметра: value".
at ServiceModelTraceRedirector.TraceData(TraceEventCache eventCache, String source, TraceEventType eventType, Int32 id, Object data)
at TraceSource.TraceData(TraceEventType eventType, Int32 id, Object data)
at DiagnosticTrace.TraceEvent(TraceEventType type, Int32 code, String msdnTraceCode, String description, TraceRecord trace, Exception exception, Object source)
at ExceptionUtility.TraceHandledException(Exception exception, TraceEventType eventType)
at MessageRpc.ProcessError(Exception e)
at MessageRpc.Process(Boolean isOperationContextSet)
at ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at ChannelHandler.AsyncMessagePump(IAsyncResult result)
at AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at AsyncResult.Complete(Boolean completedSynchronously)
at AsyncQueueReader.Set(Item item)
at InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
at InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)
at HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
at HostedHttpRequestAsyncResult.HandleRequest()
at HostedHttpRequestAsyncResult.BeginRequest()
at HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
at AspNetPartialTrustHelpers.PartialTrustInvoke(ContextCallback callback, Object state)
at HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(Object state)
at ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
at _IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
><TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error"><TraceIdentifier>http://msdn.microsoft.com/ru-RU/library/System.ServiceModel.Diagnostics....Обработка исключения.</Description><AppDomain>/LM/W3SVC/1/ROOT-1-116635956286758268</AppDomain><Exception><ExceptionType>System.ArgumentException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Указанное значение содержит недопустимые знаки управления.
>Имя параметра: value</Message><StackTrace> в System.Net.WebHeaderCollection.CheckBadChars(String name, Boolean isHeaderValue)
> в System.Net.WebHeaderCollection.Add(String name, String value)
> в System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c)
> в System.ServiceModel.Activation.HostedHttpContext.HostedRequestContainer.System.ServiceModel.Channels.HttpRequestMessageProperty.IHttpHeaderProvider.CopyHeaders(WebHeaderCollection headers)
> в System.ServiceModel.Web.IncomingWebRequestContext.get_Accept()
> в System.Data.Services.DataServiceHostWrapper..ctor(IDataServiceHost host)
> в System.Data.Services.DataService`1.HandleRequest()
> в System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
> в SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
> в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
> в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace><ExceptionString>System.ArgumentException: Указанное значение содержит недопустимые знаки управления.
>Имя параметра: value
> в System.Net.WebHeaderCollection.CheckBadChars(String name, Boolean isHeaderValue)
> в System.Net.WebHeaderCollection.Add(String name, String value)
> в System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c)
> в System.ServiceModel.Activation.HostedHttpContext.HostedRequestContainer.System.ServiceModel.Channels.HttpRequestMessageProperty.IHttpHeaderProvider.CopyHeaders(WebHeaderCollection headers)
> в System.ServiceModel.Web.IncomingWebRequestContext.get_Accept()
> в System.Data.Services.DataServiceHostWrapper..ctor(IDataServiceHost host)
> в System.Data.Services.DataService`1.HandleRequest()
> в System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
> в SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
> в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
> в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
> в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</ExceptionString></Exception></TraceRecord>
Для разъяснениями обращаемся к Fiddler (Fiddler HTTP Debugging Proxy) и видим, что с каждым моим REST-запросом (вызываемым из javascript через XMLHttpRequest объект) отправляется HTTP-заголовок Referer, содержащий ссылку на текущую страницу (URL формы на которой исполняется скрипт).

Обратите внимание, что в заголовке Referer присутствуют GET-параметры значения которых заданы кириллицей (параметры partyname и pName):
http://server/contoso/userdefined/edit.aspx?contactInfo=&etc=4202&id=%7b...Фамилия%20Имя%20Отчество&partytype=2&pId=%7b05F1C96C-7CDE-DE11-A23B-003048712BF7%7d&pName=Фамилия%20Имя%20Отчество&pType=2&sitemappath=Workplace%7cSFA%7cnav_orders#
Вот именно эти кириллические значения и ломают все REST-запросы! Эта догадка подтвердилась проверкой вызова скрипта для клиента с именем на латинице - запрос отработал успешно. Осталось избавиться от этого паразитного заголовка в нашем запросе. Самым простым решением кажется написание HTTP-модуля для IIS, который будет анализировать заголовки и кодировать кириллицу в HTML или обрубать эти значения (поскольку они никак не влияют на основной запрос).
Как оказалось, существует гораздо более удобный способ для фильтрации заголовков в IIS - URL Rewrite Module Version 2.0 for IIS 7. Этот модуль расширяет возможности встроенного URL Rewrite модуля Internet Information Server'а версии 7+.
Итак, скачиваем и устанавливаем URL Rewrite Module (внимание! потребуется перезагрузка сервера). И приступаем к созданию правила:

Создаём правило для входящих запросов:

Сначала задаём маску URL, для которого будет применятся правило (вместо contoso - имя вашей организации в CRM):

Затем дополнительное условие на HTTP-заголовок Referer - обрабатываем только те запросы, в заголовке Referer которых присутствует кириллица:

Для соответствующих правилу запросов заменяем значение HTTP-заголовка Referer (по-сути, конечной точке REST-сервиса он не нужен, поэтому оставляем только имя сервера):

Теперь осталось разрешить серверу обрабатывать нужный нам заголовок, для чего добавляем его в разрешённые серверные переменные:


После активации этого правила клиентские REST-запросы с форм сущностей действий выполняются успешно.
Замечено, что вызывая окно создания/редактирования действий разными путями (из меню "Добавить" основной записи, из меню "Добавить новый элемент типа Действие" связанного представления Действий) ошибка возникает только в первом случае. В предыдущей версии системы (CRM 2011 Rollup 1-3) русские имена записей кодировались для передачи в URL, четвёртый пакет исправлений сломал этот механизм, в пятом это так и не было исправлено.
Дополнительно о модуле URL Rewrite 2.0 можно прочитать по этим ссылкам:
Комментарии
Anton Zubarev (не проверено)
04.02.2012 16:18
Permalink
поправки
Диспетчер служб IIS надо запускать от администратора, иначе всё будет не так
регулярное выражение лучше задать так /XRMServices/2011/OrganizationData\.svc.+$
HTTP_REFERER надо добавить в разрешенные серверные переменные
дополнительное условие на русские буквы задавать не надо
Добавить комментарий