This is another way to return JSON from WCF than I described in the previous article "Returning true JSON from WCF services".
As in that article, this method was discovered using trail-and-error, and some Googling. I have not studied WCF in depth, I just barely learn what I need to, so there may very well be some better way to do it, I just haven't been able to find it yet.
- In a web project, "Add new item.." and choose "Ajax-enabled WCF Service", let's call it "AjaxEnabled.svc"
- This service is made without an interface to specify the methods (i.e. no "IAjaxEnabled.cs" was created as it would have done if you choose to add a new WCF Service like in the previous article), and consists of the single method DoWork().
- Let's create something to return, add the "MyClass" from the other article and replace the method DoWork() from there too.
Add the [WebGet] attribute too, since there doesn't seem to be a $.postJSON-function in jQuery.
You should now have an AjaxEnabled.svc.cs that looks like:
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AjaxEnabled
{
// Add [WebGet] attribute to use HTTP GET
[OperationContract]
[WebGet]
public MyClass DoWork()
{
var returnObject = new MyClass
{
Id = 1,
IHaveNoDataMemberAttribute = "Meaningless",
Name = "Satchmo",
NoPublicGet = "Hello world!",
InternalProperty = 155
};
return returnObject;
}
// Add more operations here and mark them with [OperationContract]
}
}
- Let's try it out, run the project and call the service with adding /DoWork to the AjaxEnabled.svc-url. You should've got:
<MyClass xmlns="http://schemas.datacontract.org/2004/07/Alaz.DotNetDiscoveries.JSONWithWCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Id>1</Id>
<InternalProperty>155</InternalProperty>
<Name>Satchmo</Name>
<NoPublicGet>Hello world!</NoPublicGet>
</MyClass>
Not really what we've wanted, apparently MS Ajax implementation use xml to communicate. Time to fiddle with some settings then: - Add the ResponseFormat-property to WebGet, and set it to Json (default seems to be xml):
[WebGet(ResponseFormat=WebMessageFormat.Json)]
- Run again, inspect the response in notepad, and now we got some Json, but not really in the format we would like to:
{"d":{"__type":"MyClass:#Alaz.DotNetDiscoveries.JSONWithWCF","Id":1,"InternalProperty":155,"Name":"Satchmo","NoPublicGet":"Hello world!"}}
There seem's to be some envelope around it. Let's remove it: - Set the BodyFormat-property to Bare, we do not wan't to have Wrapped messages, only bare Json:
[WebGet(ResponseFormat=WebMessageFormat.Json,BodyStyle = WebMessageBodyStyle.Bare)]
- Run again, and you will get an error:
Server Error in '/' Application.
--------------------------------------------------------------------------------
The body style 'Bare' is not supported by 'WebScriptEnablingBehavior'. Change the body style to be 'WrappedRequest'. - We must change something in the web.config, look at this tag:
<behavior name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior">
<enableWebScript />
</behavior>
- Change "enableWebScript" to "webHttp" like this:
<behavior name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior">
<webHttp />
</behavior>
The behavior is connected to:
<service name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabled">
<endpoint address="" behaviorConfiguration="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior"
binding="webHttpBinding" contract="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabled" />
</service>
- Run again, and now you got the correct Json-string {"Id":1,"InternalProperty":155,"Name":"Satchmo","NoPublicGet":"Hello world!"}.
- One more thing worth mention is the AspNetCompatibilityRequirements-attribute to the service-class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
If you want to access the current HttpContext, using ASP.NET's file/url authorization and that normal ASP.NET-stuff you must use either AspNetCompatibilityRequirementsMode.Allowed as in this example, or AspNetCompatibilityRequirementsMode.Required. My advice is to use Required if you need any of the ASP.NET-features, then the service throws an error if it is not enabled. You must enable this in the web.config (however, the "Add new Ajax-enabled WCF service" seems to add it automagically):
If "Allowed" you can run it even if web.config says "false", and you could have a hard time finding out why HttpContext.Current is null.<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
3 kommentarer:
Thanks! I been looking all over and it turns out all i was missing was the setting.
With WCF configuration will kill you...
Thank you, this solved the issue for me :)
Satchmo, thanks for the post.
One thing to mention: calling the service from javascript ($.ajax, $.getJSON) you may need to add ("Access-Control-Allow-Origin", "*") on the server side:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
public Echo echo(...)
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
Has taken me a while to figure it out... may be helpful for others.
Cheers,
hue
Skicka en kommentar