4

I have a WPF application that exposes a REST WCF service (via WebServiceHost) with a contract that looks something like this (simplified):

[ServiceContract]
public interface IItemServiceContract
{
    [WebGet(UriTemplate = "Items/{id}")]
    Item GetItem(string id);

    [WebGet(UriTemplate = "Items")]
    IEnumerable<Item> GetItems();

    [WebInvoke(UriTemplate = "Items", Method = "PUT")]
    IEnumerable<Item> CreateItems(IEnumerable<Item> list);
}

When I navigate to http://localhost:8070/Contoso/Services/Items/ItemService/Items with a browser, I get a response that looks something like this:

<ArrayOfItem xmlns="http://schemas.datacontract.org/2004/07/Contodo.Services.Items" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <ItemState>
      <Comment i:nil="true"/>
      <DeactivationTime>0001-01-01T00:00:00</DeactivationTime>
      <Id>18f1a5e4-a94a-4f37-a533-3a75a10e7373</Id>
      <IsSpecial>false</IsSpecial>
    </ItemState>
    <ItemTypeId>10</ItemTypeId>
    <HelpInfo/>
    <Identity>Ident1</Identity>
    <AdditionalInfo>
      &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
      &lt;Content&gt;
        &lt;SpecialContent /&gt;
      &lt;/Content&gt;</AdditionalInfo>
    <TextParameter>kjhdfsjh kj dkfjg kj</TextParameter>
    <UserName i:nil="true"/>
  </Item>
</ArrayOfItem>

What would be an easy and friction-free approach to consume this service with JavaScript? How can a client quickly build the http requests and the appropriate XML for it?

I am fairly in the Html5/javaScript world but in a C# I would have an API in place that is centered around the Item object that gets serialized to XML. But is that the way to go for here?

Update:

Based on the first comments and answers, it seems that XML is not the ideal format for a JavaScript/webbrowser consumer but I can't just change the format to JSON because that would probably break existing clients that already rely on this XML format. So ideally I would do REST content type negotiation and put/get JSON or XML. But can this be done with WCF REST services?

bitbonk
  • 48,890
  • 37
  • 186
  • 278
  • [jQuery AJAX calls to a WCF REST Service](http://www.west-wind.com/weblog/posts/2008/Apr/21/jQuery-AJAX-calls-to-a-WCF-REST-Service) – Andreas May 03 '13 at 21:40
  • That example describes how to do it in JSON, but I have the XML problem. – bitbonk May 03 '13 at 21:43
  • It looks like you can change the source of the webservice. So why don't you add the JSON response to it as it is done in the tutorial I've linked (`WebInvoke(Method="POST",ResponseFormat=WebMessageFormat.Json`)? – Andreas May 03 '13 at 21:49
  • That would break existing clients. I either need to find a way to do content type negotiation or I guess I'd have to add new URLs for JSON. – bitbonk May 06 '13 at 07:50
  • @bitbonk: You don't commented [my answer](http://stackoverflow.com/a/16442415/315935). Do you use .NET 4.0/4.5? Do you tried to use `automaticFormatSelectionEnabled` setting? Do you have success or some problems in usage of WCF RESTful service which provides both XML and JSON depend on client requests? Do you need additional help? – Oleg May 13 '13 at 08:14

5 Answers5

4

I suppose that you use ASP.NET 4.X.

WCF 4 supports automatic format selection based on HTTP "Accept" and "Content-Type" headers of requests. One specify automaticFormatSelectionEnabled="true" attribute in web.config file:

<configuration>
  <system.serviceModel>
    <standardEndpoints>
      <webHttpEndpoint>
        <!-- the "" standard endpoint is used for auto creating a web endpoint. -->
        <standardEndpoint name=""
                          helpEnabled="true"
                          automaticFormatSelectionEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>
</configuration>

See "Message Format Selection" part of the article and the article for more information. You can combine automaticFormatSelectionEnabled attribute with defaultOutgoingResponseFormat (which you can set to "xml" or "json", default is already "xml"). You can specify the attributes only for one specific endpoint instead of usage standardEndpoint as in the example above.

So your existing WCF service will just provide JSON data for JavaScript requests and still returns XML data for other client if you would use the corresponding WCF configuration.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • That worked like a charm. Content type negotiation with WCF! Since I am using self hosting (`WebServiceHost`) I had to configure `AutomaticFormatSelectionEnabled` in the following way: `WebHttpBehavior whb = endPoint.Behaviors.Find(); if (whb != null) { whb.AutomaticFormatSelectionEnabled = true; } else { var webBehavior = new WebHttpBehavior { AutomaticFormatSelectionEnabled = true }; endPoint.Behaviors.Add(webBehavior); }` – bitbonk May 13 '13 at 08:27
  • @bitbonk: I'm glad that the problem is solved. Self hosting service use the same way. I personally prefer to use more slim [Web API](http://nuget.org/packages/Microsoft.AspNet.WebApi) instead of WCF inside of self hosting RESTfull services. You don't need SOAP. So it could be perfect for you. Inside of `CreateAndConfigure` of your `HttpSelfHostConfiguration` implementation you can customize formatters, encoding and so on. So I recommend you examine whether Web API would be the best choice for you. – Oleg May 13 '13 at 09:29
  • Yes, Web API is definitely preferred over WCF for RESTful APIs that are based on HTTP – bitbonk May 13 '13 at 11:36
  • @bitbonk: One can easy implement some "advanced scenarios" like compressing of the HTTP traffic (see [here](http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx) or [here](http://forums.asp.net/post/4841854.aspx)), use `HttpClientCredentialType.Windows` or `HttpClientCredentialType.Ntlm` authentication (see [here](http://pastebin.com/MtGW9xrV)) by overwriting `OnConfigureBinding` etc. As I wrote I like Web API personally. – Oleg May 13 '13 at 11:50
1

Try this

For Json Type result

In InterFace

         [WebInvoke(Method = "POST", UriTemplate = "/ItemGetItem?id={id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        void  ItemGetItem(string id);

In Script

self.GetItem= function () {

         try {

             $.ajax({
                 type: "POST",
                 url: "Your Url",
                 contentType: 'application/json',
                 async: false,
                 dataType: 'json',
                 cache: false,
                 success: function (response) {




                 },
                 error: function (ErrorResponse) {


                 }

             });

         }

         catch (error) {


         }

     }

put endpoint of client application to consume this service

Sagar Hirapara
  • 1,677
  • 13
  • 24
  • I know how to change the whole webservice to JSON and consume it as JSON with JavaScript. My question is how can I **keep** the XML format and still have an easy way to consume the service from JavaScript. So I either need to consume the XML in JavaScript or have an **additional** content type JSON. For the latter approach, I'd need to do content type negotiation which doesn't seem to be that easy with WCF REST services. – bitbonk May 06 '13 at 09:15
  • this link may help you http://www.codeproject.com/Articles/59551/Consuming-a-WCF-ASMX-REST-Service-using-jQuery – Sagar Hirapara May 06 '13 at 09:31
  • or also see this http://www.codeproject.com/Articles/255684/Create-and-Consume-RESTFul-Service-in-NET-Framewor – Sagar Hirapara May 06 '13 at 09:48
  • I don't see how any of those two links answer my question. – bitbonk May 06 '13 at 10:53
1

Check out WcfRestContrib. Also this answer might help you.

Community
  • 1
  • 1
k0stya
  • 4,267
  • 32
  • 41
  • I am aware of the concept of content (type) negotiation, I explicitly mention this in my question. My question is do I do content negotiation with *WCF REST services*. – bitbonk May 06 '13 at 09:10
  • Check out WCfRestContrib. There is an example in their documentation that should help you. https://github.com/mikeobrien/WcfRestContrib/wiki/De-serialization-Overview – k0stya May 06 '13 at 09:41
  • The WcRestContrib project in you modified answer looks interesting. – bitbonk May 06 '13 at 12:57
0

Fist of all did you look at http://www.codeproject.com/Articles/33234/A-beginner-s-guide-for-consuming-a-WCF-service-in

But the easiest way in my opinion is to change format to Json. There is also a good article on code project:http://www.codeproject.com/Articles/327420/WCF-REST-Service-with-JSON

Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116
  • Is there a way to do content negotiation with WCF REST services (via WebServiceHost) so that when JSON is request I get/put JSON and when XML is requested I get/put XML? Also please note that I can't use the `AJAX-Enabled WCF Service Item Template` as described in your beginners guide since I host the webservice directly in a WPF application. – bitbonk May 03 '13 at 22:25
0

If you are using jQuery, you can use the $.get function (http://api.jquery.com/jQuery.get/) and specify "xml" as datatype:

$.get('http://.../', params, function(data) {
 //process data
}, 'xml');

If not, you need to use xmlHttpRequest directly (from http://www.w3schools.com/xml/xml_parser.asp) :

  if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
  }
  else
  {// code for IE6, IE5
     xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.open("GET",url,false);
  xmlhttp.send();
  xmlDoc=xmlhttp.responseXML;

Then traversing the xml node is fairly easy using the native javascript xml parser.

But JSON would be more appropriate. You could add a route for http://localhost:8070/Contoso/Services/Items/ItemService/Items.json which would return the result in JSON format. Or also add a parameter in the url. Both method will return JSON only if you explicitly ask for it. So the existing code which is using the xml response will still work fine.

Antoine
  • 2,785
  • 1
  • 16
  • 23