WCF makes it very easy to expose JSON data over a RESTful interface, as long as you are aware of a couple of “gotchas” in advance.
This article will explain those to you, so you can focus on your business logic rather than configuration of your WCF services.
We start this example by creating a WCF Service Library project:
Next we need to add a reference to the System.ServiceModel.Web framework. Right click on your project file and select Add Reference…
As this framework is not part of the .Net Framework 4 Client Profile, Visual Studio kindly informs us that it will update our target Framework to the full version of .Net Framework 4. Click Yes to accept this change:
We are now ready to update our code.
Copy and paste the following code into the App.Config file:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WcfJsonRestService.Service1">
<endpoint address="http://localhost:8732/service1"
binding="webHttpBinding"
contract="WcfJsonRestService.IService1"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Notice the binding is set to webHttpBinding as opposed to the normal project template default of wsHttpBinding.
The other important change is the addition of an endpointBehavior for WebHttp.
These two changes are required to enable JSON over REST for WCF.
Copy and paste the following code into the IService1 file:
using System.ServiceModel;
namespace WcfJsonRestService
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Person GetData(string id);
}
}
Notice we are accepting an “In” parameter for id of datatype string. For this example we are returning a custom type of Person.
Copy and paste the following code into the Service1.cs file:
using System;
using System.ServiceModel.Web;
namespace WcfJsonRestService
{
public class Service1 : IService1
{
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "data/{id}")]
public Person GetData(string id)
{
// lookup person with the requested id
return new Person()
{
Id = Convert.ToInt32(id),
Name = "Leo Messi"
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}
The key elements here are the attributes applied to the method. We are enabling the method to be called over HTTP GET, returning the data in Json format and setting the Uri template to ensure we are using a RESTful interface.
To test your brand new service we will pass in the id value of 10 simply by opening your favourite browser and pasting in the following URL:
http://localhost:8732/Service1/data/10
Source code: WcfJsonRestService.zip
Example With Multiple Parameters
using System;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace WcfJsonRestService
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Person GetData(string id);
[OperationContract]
Person GetDataWithTwoParams(string id, string name);
}
public class Service1 : IService1
{
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "data/{id}")]
public Person GetData(string id)
{
// lookup person with the requested id
return new Person()
{
Id = Convert.ToInt32(id),
Name = "Leo Messi"
};
}
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "data/{id}/{name}")]
public Person GetDataWithTwoParams(string id, string name)
{
// create person with the requested id and name
return new Person()
{
Id = Convert.ToInt32(id),
Name = name
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}
great article,
ReplyDeletebut I have some problem,
the error message is "wcf service host cannot find any service metadata". How to solve it???
Hi Rio, the service metadata is only required if an external client wants to interrogate your service. What's happening on your machine is that Visual Studio is attempting to start up the default WcfTestClient tool, which cannot find the metadata (as we have not exposed any). That's fine because we are accessing the service from our browser which doesn't require the metadata. Hope this makes sense, if not let me know and I'll happily share a Skype call to explain.
ReplyDeleteTo turn off the WcfTestClient tool, right click on your project > Properties > Debug then remove the /client:"WcfTestClient.exe" text from the command line arguments.
ReplyDeleteWhen I run the application I get the open / save file download dialog ?
ReplyDeleteHi Goit, the link is for a download of the C# source code. You'd need to save the zip file to your local machine unzip it and open the solution or project file in Visual Studio 2010.
ReplyDeleteSorry, my fault, I didnt explain that very well...
ReplyDeleteThe problem was after I compiled the application and ran it I attempted to browse to http://localhost:8732/Service1/data/10 and then got the open / save file prompt.
I have since found that this would be the standard behaviour in browsers for the json content type.
Great post. Thanks
Great Post. But on Windows Vista - you may need to first enable your process to listen on port 8732. Otherwise you will get an exception error. So do the following command where you replace Sasha-PC by your domain and Sasha by your user name:
ReplyDeletenetsh http add urlacl url=http://+:8732/service1 user=Sasha-PC\Sasha
Aleksandr Yampolskiy (http://yampolskiy.blogspot.com)
Found your posting and liked it very much since I´m a bit new to WCF, it shows some simplicity on creating embedded JSON services. I am running into some problems with security. When I run this as a normal user without elevated trust on the actual computer, it throws an exception when setting up the HttpListener.
ReplyDeleteSystem.Net.HttpListenerException (0x80004005):
What would the workaround be in a normal application?
Nice post, how can i access get method with multiple parameters
ReplyDeleteUday, give this a go and let me know how you get on:
ReplyDeleteusing System;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace WcfJsonRestService
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Person GetData(string id);
[OperationContract]
Person GetDataWithTwoParams(string id, string name);
}
public class Service1 : IService1
{
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "data/{id}")]
public Person GetData(string id)
{
// lookup person with the requested id
return new Person()
{
Id = Convert.ToInt32(id),
Name = "Leo Messi"
};
}
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "data/{id}/{name}")]
public Person GetDataWithTwoParams(string id, string name)
{
// create person with the requested id and name
return new Person()
{
Id = Convert.ToInt32(id),
Name = name
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Uday, you call the new service like this:
ReplyDeletehttp://localhost:8732/Service1/data/99/udaykotta
which would return you a person object with Id = 99 and Name = udaykotta
Hope this helps you out, Steve
Hi there Steven,
ReplyDeleteI've gotten the code to run and working on my local machine, but I'm running into an issue deploying it.
How do I add metadata to this project and how would I go about deploying a service like this on a live server? I've checked around a lot and haven't had any success deploying the service aside from getting it to run on localhost:8732/Service1
I've made sure to change the endpoint address to where it will reside on the deployment server, and I can get to the service page when I browse to the .svc file, but that file is returning a metadata error. Any advice would be great.
Thank you.
Hi JKMach, to add a mex metadata endpoint use the config in the following link. Check this works locally for you first then try on the server. If you're still having problems let me know what error you're having on the server.
Deletehttps://gist.github.com/2783923
I still must be missing something. I've gotten it to load up on my localhost, and I get the metadata loading (thank you, even gives me the wsdl output). But when I try to type in http://localhost/Service1/data/10 It tells me that it is getting File or directory not found. (I've created the folder as an application in IIS already).
DeleteI have changed this line in the app.config to read: add baseAddress="http://localhost/Service1" as well.
DeletePlease see instructions below.
DeleteBear in mind Microsoft also now have http://www.asp.net/web-api
Have a great weekend!
Hi JKMach
ReplyDeleteFor deployment you'll need to configure your machine first. Assuming Windows 7 64 bit (if you're running a different system and can't follow my instructions then please let me know). I've included some screenshots which hopefully will make it easier to follow:
1) Install WCF Activation:
Start > Control Panel > Programs and Features > Turn Windows Features On or Off > Microsoft .NET Framework 3.5.1 > (CHECK) Windows Communication Foundation HTTP Activation
http://stevenhollidge.com/blog-source-code/wcf/1.PNG
2) Configure ASP.NET by opening a command prompt as administrator:
CD C:\Windows\Microsoft.NET\Framework64\v4.0.30319
aspnet_regiis -i
Full instructions here: http://msdn.microsoft.com/en-us/library/k6h9cz8h.aspx
http://stevenhollidge.com/blog-source-code/wcf/2.PNG
Now your machine is configured you need to deploy your service. First we'll deploy using a svc file:
1) Open Visual Studio using "Run as Administrator" (you can do this by holding SHIFT and right clicking on the Visual Studio shortcut and select "Run as Administrator")
2) Right click on the "WcfJsonRestService" project file and select "Publish..."
3)
a) Target location: http://localhost/service1
b) Select "delete all existing files prior to publish
c) Copy: Only files needed to run this application
d) Click Publish
http://stevenhollidge.com/blog-source-code/wcf/3.PNG
4) You'll notice VS automatically creates a WcfJsonRestService.Service1.svc, which only consists of the following text:
<%@ ServiceHost Service="WcfJsonRestService.Service1" %>
5) You should now be able to navigate to your service and execute the method:
a) http://localhost/Service1/WcfJsonRestService.Service1.svc
b) http://localhost/Service1/WcfJsonRestService.Service1.svc/data/10
http://stevenhollidge.com/blog-source-code/wcf/4.PNG
http://stevenhollidge.com/blog-source-code/wcf/5.PNG
Let me know how you get on, here's a couple of good reference links:
Configuring WCF
http://msdn.microsoft.com/en-us/library/aa751792.aspx
Simple REST service without svc or config
http://geekswithblogs.net/michelotti/archive/2010/08/21/restful-wcf-services-with-no-svc-file-and-no-config.aspx
Almost forgot, if you haven't already set up authentication within IIS for the Service1 application, you can enable Anonymous Authentication.
DeleteIIS > {machine} > Sites > Default Web Site > Features View > Authentication > Anonymous Authentication (Enable)
http://stevenhollidge.com/blog-source-code/wcf/6.PNG
Hope this helps!
Got it working on my local IIS. The thing that threw me off was the request URL. In your screenshot and the above instructions, you reference the svc file whereas in the initial code and the stuff that works on the local dev, it wasn't referenced. http://localhost/service1/WcfJSonRestService.Service1.svc/data/10 vs. http://localhost:8732/Service1/data/10
DeleteThank you so much for your help!
Hi steven, great articile it has really helped thankyou. How would i enable JSONP?
ReplyDeleteSteve,
ReplyDeleteThanks for detailed info. Unfortunately I am getting following error in fault xml tag, which no one experienced. Pl guide
The message with To 'http://localhost:8732/Service1/data/10' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree
Steve,
DeleteI fixed it. For reference, this is what I have done
Assigned name to behavior
Added behaviorConfiguration to endPoint
Hello, I have exactly same problem and cannotfix it. Can you provide us with your config file ?
DeleteThanks
Very good article...
ReplyDeleteHello, I have exactly same problem and cannotfix it. Can you provide us with your config file ?
ReplyDeleteThanks.
Hi Anonymous, here is the link to the config
ReplyDeletehttps://gist.github.com/2783923
Always same problem for me : cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree
ReplyDeleteAny idea ?
Hi Gazous, are you trying to run the original code from the download? If not, could you send me a link to your code and I'll take a look for you.
ReplyDeleteHi Steven, I finally fixed the issue by adding in the behavihors.
ReplyDeleteNow I am trying to the the JSON response ?
Do you know a way to do this ?
Thanks for your help !
Hi Gazous, let me know what you are trying to do as the code featured in the blog works without the need to update config files or amendments for a JSON response.
ReplyDeleteHi Steven, I foud a way to do it (ZIP th JSON response sorry for my mistake in my message...) by zipping a JSON string in a JSON response and it works fine ! Now I am trying to have a POST request working but it is not. i always have a "Method not allowed" reponse. Any idea ?
ReplyDelete