As you probably know some of our controls support web service load on demand (a.k.a. client-side databinding). Also in ASP.NET MVC we can call controller actions via Ajax. In this blog post I will show you how to populate RadComboBox and RadTreeView on demand by using a controller action which returns JsonResult. Let's start with RadComboBox:
I have added the RadComboBox control to the default Index.aspx view and configured it like this:
<telerik:RadComboBox runat="server" ID="RadComboBox1" EnableLoadOnDemand="true"
ShowMoreResultsBox="true" EmptyMessage="Type here ..." Height="200px">
<WebServiceSettings Path="Home" Method="LoadItems" />
</telerik:RadComboBox>
The important thing here is that RadComboBox is configured as if it were using a web service - it will call the Home controller's LoadItems method. Internally RadComboBox us using ASP.NET Ajax to call the specified URL and populate from the returned JSON.
RadComboBox is passing a RadComboBoxContext object to web service methods. This object is used by the developer for various reasons - filtering, paging etc. Consider the following method:
[WebMethod]
public RadComboBoxData LoadItems(RadComboBoxContext context)
{
}
In a regular web service the context parameter would be automatically deserialized from the JSON passed by RadComboBox. In ASP.NET MVC you should deserialize the JSON parameter yourself. I did it by using a custom ActionFilter. Here is the implementation of the filter:
public class JsonParamFilter : ActionFilterAttribute
{
public string Param { get; set; }
public Type TargetType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string contentType = filterContext.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType))
return;
if (!contentType.Contains("application/json"))
return;
string paramValue;
using (var reader = new StreamReader(filterContext.HttpContext.Request.InputStream))
paramValue = reader.ReadToEnd();
var serializer = new JavaScriptSerializer();
var rawResult = (IDictionary<string, object>) serializer.DeserializeObject(paramValue);
var deserializeMethod = serializer.GetType()
.GetMethod("ConvertToType")
.MakeGenericMethod(TargetType);
filterContext.ActionParameters[Param] =
deserializeMethod.Invoke(serializer, new[] {rawResult[Param]});
}
}
Here is how to use it:
[JsonParamFilter(Param = "context", TargetType=typeof(RadComboBoxContext))]
public JsonResult LoadItems(RadComboBoxContext context)
{
}
There is only one thing left - to implement the method and return a RadComboBoxData object in JSON format. There is a tricky part though - ASP.NET Ajax expects a web service to return a JSON in this format: {d:{}}. This is easily done by returning an anonymous object with a single "d" property containing the desired result:
[JsonParamFilter(Param = "context", TargetType = typeof (RadComboBoxContext))]
public JsonResult LoadItems(RadComboBoxContext context)
{
RadComboBoxData result = new RadComboBoxData();
//fill the result return Json(new {d = result});
}
And that's it. RadComboBox has been successfully tricked that it is populated from a web service!
The implementation is exactly the same:
<telerik:RadTreeView runat="server" ID="RadTreeView1">
<WebServiceSettings Path="Home" Method="LoadNodes" />
<Nodes>
<telerik:RadTreeNode Text="Fuller" ExpandMode="WebService" />
</Nodes>
</telerik:RadTreeView>
[JsonParamFilter(Param = "node", TargetType = typeof (RadTreeNodeData))]
public JsonResult LoadNodes(RadTreeNodeData node)
{
}
[JsonParamFilter(Param = "node", TargetType = typeof (RadTreeNodeData))]
public JsonResult LoadNodes(RadTreeNodeData node)
{
List<RadTreeNodeData> result = new List<RadTreeNodeData>();
//fill the result return Json(new {d = result.ToArray()});
}