Как я могу вручную создать тип тела WCF OperationContract? - PullRequest
2 голосов
/ 12 марта 2009

Я пытаюсь кодировать клиента веб-службы в Silverlight для RESTful-службы WCF, которую я разработал. В Silverlight я создаю тело WebRequest с использованием экземпляра DataContractSerializer.

Этот подход прекрасно работает, если для OperationContract есть единственный аргумент. Это не так хорошо работает, если в OperationContract определены несколько аргументов. Я полагаю, что это потому, что WCF создает динамический тип, который назван в честь OperationContract, а члены этого типа названы в честь параметров, определенных для операции. Назначение динамического типа состоит в том, чтобы обеспечить наличие единственного элемента XML в теле сообщения, передаваемого службе WCF ... имеет смысл. Вопрос в том, как мне самому построить этот динамический тип, чтобы я мог сам отправить его в DataContractSerializer.

Первый пример - это рабочий пример, который определяет один параметр. Второй пример - сценарий, который я пытаюсь решить (несколько параметров).


Пример 1:

[OperationContract,
WebInvoke(Method = HttpMethodType.Post,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate = "UnregisterProvider"),
WebHelp(Comment = "Unregistered the provider type with the specified URI.")]
void UnregisterProvider(RdfUri providerUri);

Код, используемый для сериализации тела сообщения:

StringBuilder msgBody = new StringBuilder(250);
using (XmlWriter xw = XmlWriter.Create(msgBody))
{
    var serializer = new DataContractSerializer(typeof(RdfUri));
    serializer.WriteObject(xw, providerUri);
}

Результирующее тело:

<RdfUri xmlns="http://schemas.datacontract.org/2004/07/Intellidimension.Rdf">esp:semanticserver</RdfUri>

Пример 2:

[OperationContract,
WebInvoke(Method = HttpMethodType.Post,
    BodyStyle = WebMessageBodyStyle.WrappedRequest,  /* WrappedRequest must somehow signal WCF to create the anonymous type as it is required for multiple parameter OperationContracts */
    UriTemplate = "RegisterProvider"),
WebHelp(Comment = "Registered a provider type with the specified URI.")]
void RegisterProvider(PoolableEntityServiceProviderDescriptor descriptor, RdfUri providerUri);

Код, используемый для сериализации тела сообщения:

//?????

Результирующее тело:

<RegisterProvider xmlns="http://tempuri.org/">
  <descriptor i:type="a:SemanticServerProviderDescriptor" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:a="http://schemas.datacontract.org/2004/07/Intellidimension.RdfEntity.Service.DataContracts">
    <a:ConnectionString>Data Source=.\sqlexpress;Initial Catalog=RdfTest1;Persist Security Info=True;User ID=sa;Password=password</a:ConnectionString>
    <a:ProviderGraphUri>http://entitystore/graph-provider</a:ProviderGraphUri>
  </descriptor>
  <providerUri>esp:semanticserver</providerUri>
</RegisterProvider>

Обновление 1 :

Вот парень на форумах MSDN, задающий аналогичный вопрос: Могу ли я использовать DataContractSerializerOperationFormatter для форматирования списка параметров от клиента к серверу?

DataContractSerializerOperationFormatter является внутренним классом. Похоже, мне пришлось реализовать это поведение для моего клиента.

Обновление 2 :

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

Аналогов для WebHttpBinding, предоставляемых в WCF, нет. Для доступа к чистым службам HTTP, REST, RSS / Atom или AJAX из Silverlight 2 используйте методы, описанные в разделе «Прямой доступ к службам на основе HTTP», такие как класс WebClient. Чтобы получить доступ к службам ASP.NET AJAX, см. Доступ к службам ASP.NET AJAX.

Ответы [ 2 ]

1 голос
/ 15 июня 2012

Я на самом деле не пробовал это, но эта статья может иметь то, что вы хотите. Он создал завернутое сообщение, выполнив это:

    private void ConsumeWcfRest()
    {
        string url = "http://something/MyWebsite/tagservice";

        Tag tag1 = new Tag() { ID = 1, TagName = "test1" };
        Tag tag2 = new Tag() { ID = 2, TagName = "test2" };

        HttpWebRequest req = HttpWebRequest.Create(url + "/tags/wrapped/1") as HttpWebRequest;
        req.Method = "POST";
        string content = "<DoSomethingWrapped xmlns='http://mytagservice'>";
        content = content + DoSerialize(tag1, "tag1");
        content = content + DoSerialize(tag2, "tag2");
        content = content + "</DoSomethingWrapped>";

        // .....
    }

    private string DoSerialize(object obj, string rootName)
    {
        System.Runtime.Serialization.DataContractSerializer se;
        if (string.IsNullOrEmpty(rootName))
            se = new System.Runtime.Serialization.DataContractSerializer(obj.GetType());
        else
            se = new System.Runtime.Serialization.DataContractSerializer(obj.GetType(), rootName, "");

        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        se.WriteObject(ms, obj);
        ms.Position = 0;
        byte[] arr = new byte[ms.Length];
        ms.Read(arr, 0, Convert.ToInt32(ms.Length));
        return new System.Text.UTF8Encoding().GetString(arr);
    }

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

Возможно, вы захотите начать декомпиляцию библиотек WCF и посмотреть, сможете ли вы узнать, как WCF это делает в первую очередь.

0 голосов
/ 12 марта 2009

Позвольте мне задать вам вопрос назад. Допустим, вы можете заставить это работать. Каков тип содержимого тела запроса POST?

Вы злоупотребляете HTTP, пытаясь притвориться, что POST может отправить две вещи. Если вы хотите делать то, что делаете, то почему бы не использовать обычные сервисные контракты WCF. С ними легко отправить несколько параметров.

Проблема с System.ServiceModel.Web заключается в том, что он только на 90% отделяет клиента от WCF. Поэтому, чтобы все работало правильно, вам нужен WCF на стороне клиента. На этом этапе почему бы не придерживаться регулярных контрактов на обслуживание WCF.

Если вы действительно хотите использовать HTTP так, как было задумано, используйте технологию, которая поможет, а не мешает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...