It took me a while to get this working. I am using the online template "AJAX-Enabled WCF Service" be sure to download and install that into Visual Studio 2010. When you create one of these in your Visual Studio solution, make sure your new services are set up like this:
Code:
using System;using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
namespace MyNameSpace
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[WebInvoke(
Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest
)]
public Message MyGetMethod()
{
IDictionary<string, string> queryString = HttpUtil.GetQueryString();
string id;
queryString.TryGetValue("id", out id);
// your code here
string json = JsonHelper.Serialize(<some object>);
return WebOperationContext.Current.CreateTextResponse(json, "application/json; charset=utf-8", Encoding.UTF8);
}
}
}
And use this pattern in your web.config:
Code:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="MyNameSpace.MyServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
.... more behaviors...one for each service
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<bindings>
<webHttpBinding>
<binding name="AjaxBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="MyNameSpace.MyService">
<endpoint address="" behaviorConfiguration="MyNameSpace.MyServiceAspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="AjaxBinding"
contract="MyNameSpace.MyService" />
</service>
... more services
</services>
</system.serviceModel>
In addition, I created some helper methods for extracting HTTP query parameters:
Code:
using System.Collections.Generic;using System.ServiceModel;
using System.ServiceModel.Channels;
namespace MyNameSpace.Util
{
public class HttpUtil
{
/**
* This is used for HTTP GET
*/
public static IDictionary<string, string> GetQueryString()
{
MessageProperties message = OperationContext.Current.IncomingMessageProperties;
object value;
message.TryGetValue("httpRequest", out value);
HttpRequestMessageProperty httpRequestMessageProperty = (HttpRequestMessageProperty)value;
string[] queryStringParameters = httpRequestMessageProperty.QueryString.Split('&');
Dictionary<string, string> queryStringDictionary = new Dictionary<string, string>();
// this IF will catch URL calls are missing query string parameters
if (queryStringParameters.Length > 1)
{
for (int i = 0; i < queryStringParameters.Length; i++)
{
string[] parameter = queryStringParameters[i].Split('=');
queryStringDictionary.Add(parameter[0], parameter[1]);
}
}
return queryStringDictionary;
}
}
And serializing/deserializing JSON:
Code:
namespace MyNameSpace.Util{
public class JsonHelper
{
public static string Serialize<T>(T obj, int total = 1)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, obj);
string retVal = Encoding.Default.GetString(ms.ToArray());
// wrap object in brackets (a json array) even if it's just one element
if (!retVal.StartsWith("["))
{
retVal = "[" + retVal + "]";
}
ms.Dispose();
int returnTotal = total;
if (total > 1)
{
returnTotal = total;
}
else if (obj.GetType().FullName.Contains("List"))
{
returnTotal = ((IList)obj).Count;
}
string json = "{" + "\"Success\":true" + "," + "\"Total\":" + returnTotal + "," + "\"Message\":\"\"" + "," + "\"Results\":" + retVal + "}";
return json;
}
public static T Deserialize<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T)serializer.ReadObject(ms);
ms.Close();
ms.Dispose();
return obj;
}
}
So in ExtJS you can call like this:
Code:
Ext.Ajax.request({ method:'GET',
url: 'MyService.svc/MyGetMethod',
params: {
param1: 0,
param2: 'test'
},
success: function (response) {
var obj = Ext.decode(response.responseText);
},
failure: function (response) {
var obj = Ext.decode(response.responseText);
Ext.Msg.show({
title: 'Error',
msg: 'An error has occurred:\n\n' + obj.Message,
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
});
Incidentally, once I complete this project I'm working on, I"m going to go back and replace all this Ext.Ajax.request stuff with ExtDirectMVC. It's a much cleaner way of passing data between client and server. I've done a test projects and had excellent results.