УСПОКОИТЕЛЬНЫЙ Сервис WCF возвращает 400 кодов при отправке “необработанного” XML

Я ударял по голове стены в течение двух дней с этим так, надо надеяться, кто-то может дать мне руку. То, что я имею, является УСПОКОИТЕЛЬНЫМ веб-сервисом, что я записал использованию WCF; ничто к нему действительно всего два метода, которые принимают отдельный строковый параметр и также возвращают строку. И значение параметра и возвращаемое значение являются прямым XML.

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebGet(UriTemplate = "/method1/{data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]
    string Method1(string data);

    [OperationContract]
    [WebGet(UriTemplate = "/method2/{data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]
    string Method2(string data);

}

Ради аргумента позволяет, говорят, что реализация обоих из этих методов похожа на это:

public string Method1(string data)
{
    return string.Format("You entered: {0}", data);
}

Если я goto http://myuri.com/service.svc/method1/foo следующее, записал в браузер:

  <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You 
    entered: foo</string> 

Это работает отлично, но если я изменяю URL на: http://myuri.com/service.svc/method1 / <нечто> я получаю 400 (Плохой Запрос). Таким образом, я позволил некоторым трассировщикам видеть то, что шло с помощью следующего кода:

<system.diagnostics>
<sources>
  <source name="System.ServiceModel"
          switchValue="All">
    <listeners>
      <add name="traceListener"
          type="System.Diagnostics.XmlWriterTraceListener"
          initializeData= "c:\Traces.svclog" />
    </listeners>
  </source>
</sources>

Поскольку Вы видите, что я использую значение переключателя 'Все' для получения каждого события, которое происходит во время казни этого сервиса. Я отбежал посредством несколько раз использования Формата ссылки, который работает, чтобы проверить, что трассировщики работали, и они были. Я затем перешел к URL, который содержал нечто XML-тэга и получил 400 ошибок как ожидалось, но когда я вернулся к файлу журнала не было никакой дополнительной информации appened в конец его. Это приводит меня полагать, что 400 ошибок отображаются, прежде чем сервис WCF когда-либо вызывается.

Наконец, я переключился, методы от 'ПОЛУЧАЮТ' методы к методам 'POST', записал небольшому количеству использования кода WebRequest / WebResponse с тем же результатом. Теперь я прочитал некоторые сообщения, говорящие об использовании XmlSerializer на стороне клиента, чтобы отправить данные службе, но это побеждает цель этого сервиса. В то время как я использую.NET для записи сервиса, вероятно, что PHP или классические сценарии ASP будут соединяться с этим сервисом, и у них, очевидно, нет доступа к XmlSerializer.

Таким образом, мой самый трудный вопрос - это: действительно ли возможно отправить 'необработанный' запрос XML к УСПОКОИТЕЛЬНОМУ веб-сервису, разработанному в WCF и, если так, как?

P.S. вход XML и выход из сервиса не основаны ни на каком материальном объекте, это - просто структура, которую я создал для использования с этим сервисом. Входящий XML анализируется через XPath, значения помещаются в большую строку XML и передаются внешнему API. Результаты, что API обрабатывается и затем возвращается моим УСПОКОИТЕЛЬНЫМ сервисом.

Любая справка значительно ценилась бы!!

7
задан dparsons 6 January 2010 в 21:51
поделиться

4 ответа

Бретт, спасибо за код. К сожалению, я нашел его в этом потоке: WCF Rest parameters including complex types и пытался это сделать до этого постинга.

В любом случае, я решил эту проблему. Сейчас я хотел бы сказать, что у меня был полный момент "Эврики" и все просто сложилось, но дело в том, что я только начал бросать акронимы в Google и одна из SERP-ов привела меня по этой ссылке: http://blogs.msdn.com/pedram/archive/2008/04/21/how-to-consume-rest-services-with-wcf.aspx

Ссылка сама по себе не является непосредственным ответом на рассматриваемый вопрос, но она заставила меня по-другому подумать о том, как я собирал свои шаблоны URI. Я прочитал эту MSDN статью http://msdn.microsoft.com/en-us/library/dd203052.aspx о том, как составлять RESTful сервис. В примере автор предоставляет несколько различных шаблоновL некоторые из которых используют типичный шаблон Querystring parameter-esque, а некоторые нет. По какой-то причине я выбираю шаблон, который не имеет типичного параметра querystring, как видно из моей первоначальной заметки. Поэтому я немного изменил свой код и придумал следующее:

[OperationContract] 
[WebGet(UriTemplate = "/method1/?xml={data}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] 
string Method2(string data); 

Обратите внимание, что шаблон URI - единственное, что изменилось; изменение с "/method1/{data}" на "/method1/?xml={data}. Затем я перешел на http://myuri.com/service.svc/method1/?xml= и альт, все сработало прекрасно!

Это тоже было проблемой с POST. По какой бы то ни было причине передача XML в тело контента, даже в виде пары ключ/значение, приводила к ошибке 400. Используя точно такой же шаблон URI, показанный выше, я открыл Fiddler, выполнил POST, и результат был 200 OK.

Спасибо всем за помощь.

3
ответ дан 7 December 2019 в 05:23
поделиться

Я не верю, что вы сможете передать сырой XML в URL, но вы можете сделать это в коде. Я написал клиентов для RESTful веб-сервисов, которые работают на Compact Framework и не имеют проблем с десериализацией объектов на сырой XML и отправкой его в службу через HttpWebRequest и HttpWebResponse.

Если вы делаете GET, вы просто создаете URL в коде. Если вы делаете POST, вы можете прикрепить XML в виде массива байтов (код ниже .Net, но, конечно, вы можете сделать что-нибудь подобное в PHP).

private HttpWebRequest DoInvokeRequest<T>(string uri, string method, T requestBody)
{
    string destinationUrl = _baseUrl + uri;
var invokeRequest = WebRequest.Create(destinationUrl) as HttpWebRequest;
if (invokeRequest == null)
    return null;

invokeRequest.Method = method;
invokeRequest.ContentType = "text/xml";

byte[] requestBodyBytes = ToByteArray(requestBody);
invokeRequest.ContentLength = requestBodyBytes.Length;
AddRequestHeaders(invokeRequest);

using (Stream postStream = invokeRequest.GetRequestStream())
    postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);


invokeRequest.Timeout = 60000;
return invokeRequest;
}

private static byte[] ToByteArray<T>(T requestBody)
{
    byte[] bytes;
using (var s = new MemoryStream())
{
    var serializer = new XmlSerializer(typeof (T));
    serializer.Serialize(s, requestBody);
    bytes = s.ToArray();
}
return bytes;
}
1
ответ дан 7 December 2019 в 05:23
поделиться

Как вы их высмеиваете пользователей?

Инициализируют django.contrib.auth.models.user объект. user.Objects.create_user делает это легко.

Как вы запрашиваете запросы?

Инициализируют django.http.httprequest объект.

Конечно, есть ярлыки в зависимости от того, что вы хотите сделать. Если вам просто нужен объект с атрибутом , который указывает на пользователя, просто создайте что-нибудь (что-нибудь) и дайте ему этот атрибут.

-121--913371-

Одной из основных причин, по которым исходный код не работал, был, потому что какие-либо строковые данные XML должны быть закодированы URL, если их передан в пути URL или строка запроса.

Однако, однако, если вы хотите, чтобы клиент отправил вам данные как XML в вашем методе обслуживания, то он должен быть выполнен . URL имеет неопределенную максимальную длину, в зависимости от браузера, версии IIS, а также любых веб-прокси, которые сидят между клиентом на сервере.

Это означает отправку данных в тело запроса, что означает глагол, отличный от получения. Так что давайте будем использовать пост.

Объявите параметр «Данные» как до подписи метода, но возьмите параметр из мочи и сделайте его WebInvoke (Verb по умолчанию - это сообщение, как вы знаете).

[WebInvoke(UriTemplate = "/method1", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]  
string Method2(string data);

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

<data><![CDATA[data xml goes in here]]></data>

Почему раздел CDATA? Подумайте о типе целевого параметра - String. Вы хотите пройти XML в этой строке. Следовательно, вам необходимо убедиться, что сериализатор WCF не думает о данных как сложных данных, которые следует читать напрямую. То же самое было бы правдой, если ваш формат запроса был JSON, и вы хотите отправить json String на службу.

3
ответ дан 7 December 2019 в 05:23
поделиться

По моему мнению, услуги WCF, предоставляющие RESTful API, не допускают большой полезной нагрузки. На самом деле, по умолчанию службы WCF предназначены для отправки небольших сообщений туда и обратно.

На машине, которую я тестировал, я не смог получить обратно полезную нагрузку в формате XML (XML-файл) от службы WCF, открытую через веб-конечную точку REST-ful, которая была больше, чем 2,7 МБ .

Из раскопок и охоты через LOTS документации WCF я пришел к окончательному выводу, что WCF предназначен для небольших сообщений, когда в режиме буферизации . При переключении в режим потокового большие сообщения могут передаваться туда и обратно.

Однако, если вы подвергаете службы WCF через IIS в режиме RESTful, то вы не сможете получить потоковый ответ, так как это не поддерживается. Или, по крайней мере, я никогда не смогу это выяснить.

Хотел бы я иметь для вас отличный образец кода, но из того, что я смог обнаружить в результате собственных экспериментов, было то, что не существует способа вернуть большую полезную нагрузку в формате XML из службы WCF, открытую через конечную точку IIS .

Мой вывод заключается в том, что WCF - это действительно сетевое решение, которое переоснащается (плохо) в IIS, чтобы попытаться предоставить веб-сервисы. Я бы рекомендовал использовать ASP .NET MVC вместо этого для создания RESTful webservices без использования WCF вообще.

1
ответ дан 7 December 2019 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: