Hello there,
I'm getting pretty frustrated. I have been trying to get my RESTful WCF service to work with the ListView controller. I was reusing the code from the demo (http://demos.kendoui.com/web/listview/editing.html) and adjusting it to my own needs. I have googled for help on how to enable my service to support JSONP, even though in my test bench I execute it locally.
I have a webservice that produces this JSON output:
The webservice looks like this:
[ServiceContract]
public interface IPlanListRESTService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "fillplanlist/{count}")]
List<Plan> FillPlanList(string count);
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "plan")]
bool AddPlan(Plan plan);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "planlist")]
List<Plan> GetPlanList();
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "xml/{id}")]
string XMLData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "json/{id}")]
string JSONData(string id);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PlanListRESTService : IPlanListRESTService
{
List<Plan> planList = new List<Plan>();
static Random rand = new Random();
public List<Plan> FillPlanList(string count)
{
try
{
int noOfPlans= Convert.ToInt32(count);
if ((noOfPlans < 0) || (noOfPlans > 25))
return planList;
planList.Clear();
for (int i = 1; i <= noOfPlans; i++)
{
Plan plan = new Plan();
plan.Id = Guid.NewGuid().ToString();
plan.Name = "Plan " + i.ToString();
plan.Status = PlanStatus.Waiting;
Random random = new Random();
plan.NoOfJobs = random.Next(0, 8);
plan.NextRun = GetRandomDate(new DateTime(2012, 11, 1), new DateTime(2013, 5, 1));
planList.Add(plan);
}
return planList;
}
catch (Exception)
{
return planList;
}
}
public bool AddPlan(Plan plan)
{
plan.Id = Guid.NewGuid().ToString();
planList.Add(plan);
return true;
}
public List<Plan> GetPlanList()
{
return planList;
}
public string XMLData(string id)
{
return "You requested product " + id;
}
public string JSONData(string id)
{
return "You requested product " + id;
}
public string ToJSon(object obj)
{
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
return oSerializer.Serialize(obj);
}
public string GetRandomDate(DateTime dtStart, DateTime dtEnd)
{
int cdayRange = (dtEnd - dtStart).Days;
return dtStart.AddDays(rand.NextDouble() * cdayRange).ToString();
}
}
The web.config for the service looks like this:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="PlanListRESTService.PlanListRESTService" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP"
contract="PlanListRESTService.IPlanListRESTService"
behaviorConfiguration="Web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
And finally here is the Index.cshtml file that should render the listview with my data, but it doesn't :-( :
@{
ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<div id="example" class="k-content">
<div class="k-toolbar k-grid-toolbar">
<a class="k-button k-button-icontext k-add-button" href="#"><span class="k-icon k-add"></span>Add new plan</a>
</div>
<div id="listView"></div>
<div id="pager" class="k-pager-wrap">
</div>
<script type="text/x-kendo-tmpl" id="template">
<div class="plan-view">
<dl>
<dt>Name</dt>
<dd>${Name}</dd>
<dt>No. of jobs</dt>
<dd>${NoOfJobs}</dd>
<dt>Next run:</dt>
<dd>${NextRun}</dd>
<dt>Status</dt>
<dd>${Status}</dd>
</dl>
<div class="edit-buttons">
<a class="k-button k-button-icontext k-edit-button" href="\\#"><span class="k-icon k-edit"></span>Edit</a>
<a class="k-button k-button-icontext k-delete-button" href="\\#"><span class="k-icon k-delete"></span>Delete</a>
</div>
</div>
</script>
<script type="text/x-kendo-tmpl" id="editTemplate">
<div class="plan-view">
<dl>
<dt>Plan Name</dt>
<dd>
<input type="text" data-bind="value:Name" name="Name" required="required" validationMessage="required" />
<span data-for="Name" class="k-invalid-msg"></span>
</dd>
<dt>No. of jobs</dt>
<dd>
<input type="text" data-bind="value:NoOfJobs" data-role="numerictextbox" data-type="number" name="NoOfJobs" required="required" min="0" validationMessage="required" />
<span data-for="NoOfJobs" class="k-invalid-msg"></span>
</dd>
<dt>Status</dt>
<dd>
<input type="text" data-bind="value:Status" name="Status" required="required" data-type="number" min="0" validationMessage="required" />
<span data-for="Status" class="k-invalid-msg"></span>
</dd>
<dt>Next run</dt>
<dd>
<input type="text" data-bind="value:NextRun" name="NextRun" required="required" data-type="number" min="0" validationMessage="required" />
<span data-for="NextRun" class="k-invalid-msg"></span>
</dd>
</dl>
<div class="edit-buttons">
<a class="k-button k-button-icontext k-update-button" href="\\#"><span class="k-icon k-update"></span>Save</a>
<a class="k-button k-button-icontext k-cancel-button" href="\\#"><span class="k-icon k-cancel"></span>Cancel</a>
</div>
</div>
</script>
<script>
$(document).ready(function () {
var crudServiceBaseUrl = "http://localhost:8080/PlanListRESTService",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/fillplanlist/20",
dataType: "jsonp"
},
//update: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
//destroy: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
//create: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 6,
schema: {
model: {
id: "Id",
fields: {
Id: { editable: false, nullable: true },
Name: "Name",
NextRun: "Next run",
NoOfJobs: { type: "number" },
Status: { type: "number" }
}
}
}
});
$("#pager").kendoPager({
dataSource: dataSource
});
var listView = $("#listView").kendoListView({
dataSource: dataSource,
template: kendo.template($("#template").html()),
editTemplate: kendo.template($("#editTemplate").html())
}).data("kendoListView");
$(".k-add-button").click(function(e) {
listView.add();
e.preventDefault();
});
});
</script>
<style scoped>
.plan-view
{
float: left;
width: 300px;
margin: 5px;
padding: 3px;
-moz-box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
-webkit-box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
border-top: 1px solid rgba(0,0,0,0.1);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.plan-view dl
{
margin: 10px 0;
padding: 0;
min-width: 0;
}
.plan-view dt, dd
{
float: left;
margin: 0;
padding: 0;
height: 30px;
line-height: 30px;
}
.plan-view dt
{
clear: left;
padding: 0 5px 0 15px;
text-align: right;
opacity: 0.6;
width: 100px;
}
.k-listview
{
border: 0;
padding: 0;
min-width: 0;
}
.k-listview:after, .plan-view dl:after
{
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.edit-buttons
{
text-align: right;
padding: 5px;
min-width: 100px;
border-top: 1px solid rgba(0,0,0,0.1);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.k-toolbar, #listView, .k-pager-wrap
{
width: 960px;
/*margin: 0 auto;*/
-webkit-border-radius: 11px;
-moz-border-radius: 11px;
border-radius: 11px;
}
#listView
{
width: 960px;
}
span.k-invalid-msg
{
position: absolute;
margin-left: 160px;
margin-top: -26px;
}
</style>
</div>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<p>
To learn more about working with the Kendo UI Complete for ASP.NET MVC, you can visit the folowing resources:
</p>
<ul>
<li><a href="http://demos.kendoui.com/">online demos</a></li>
<li><a href="http://docs.kendoui.com/getting-started/using-kendo-with/aspnet-mvc/introduction">online documentation</a></li>
<li><a href="http://www.kendoui.com/forums.aspx">community forums</a></li>
<li><a href="http://tv.telerik.com/search?FilterByTags=KendoUI">videos on Telerik TV</a></li>
</ul>
Help me please
I'm getting pretty frustrated. I have been trying to get my RESTful WCF service to work with the ListView controller. I was reusing the code from the demo (http://demos.kendoui.com/web/listview/editing.html) and adjusting it to my own needs. I have googled for help on how to enable my service to support JSONP, even though in my test bench I execute it locally.
I have a webservice that produces this JSON output:
[{"Id":"acd34cd2-4500-4e2e-988d-2f71738cb7b6","Name":"Plan 1","NextRun":"06-01-2013 04:43:55","NoOfJobs":7,"Status":0},{"Id":"5431e4ef-943c-4bcb-b747-378416face14","Name":"Plan 2","NextRun":"13-04-2013 03:23:02","NoOfJobs":7,"Status":0},{"Id":"ab9ce9ea-c9d1-4f90-be36-b6aca23c247d","Name":"Plan 3","NextRun":"09-12-2012 13:11:04","NoOfJobs":7,"Status":0},{"Id":"93b4689b-d39c-45fa-979a-93148dd81978","Name":"Plan 4","NextRun":"05-01-2013 18:56:21","NoOfJobs":7,"Status":0},{"Id":"61e89143-e6d6-4d3b-9c06-88509c2c9b55","Name":"Plan 5","NextRun":"06-03-2013 03:03:07","NoOfJobs":7,"Status":0},{"Id":"877244ee-3a63-4733-8f3e-a8154ab5b04c","Name":"Plan 6","NextRun":"05-02-2013 00:17:46","NoOfJobs":7,"Status":0}]
The webservice looks like this:
[ServiceContract]
public interface IPlanListRESTService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "fillplanlist/{count}")]
List<Plan> FillPlanList(string count);
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "plan")]
bool AddPlan(Plan plan);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "planlist")]
List<Plan> GetPlanList();
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "xml/{id}")]
string XMLData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "json/{id}")]
string JSONData(string id);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PlanListRESTService : IPlanListRESTService
{
List<Plan> planList = new List<Plan>();
static Random rand = new Random();
public List<Plan> FillPlanList(string count)
{
try
{
int noOfPlans= Convert.ToInt32(count);
if ((noOfPlans < 0) || (noOfPlans > 25))
return planList;
planList.Clear();
for (int i = 1; i <= noOfPlans; i++)
{
Plan plan = new Plan();
plan.Id = Guid.NewGuid().ToString();
plan.Name = "Plan " + i.ToString();
plan.Status = PlanStatus.Waiting;
Random random = new Random();
plan.NoOfJobs = random.Next(0, 8);
plan.NextRun = GetRandomDate(new DateTime(2012, 11, 1), new DateTime(2013, 5, 1));
planList.Add(plan);
}
return planList;
}
catch (Exception)
{
return planList;
}
}
public bool AddPlan(Plan plan)
{
plan.Id = Guid.NewGuid().ToString();
planList.Add(plan);
return true;
}
public List<Plan> GetPlanList()
{
return planList;
}
public string XMLData(string id)
{
return "You requested product " + id;
}
public string JSONData(string id)
{
return "You requested product " + id;
}
public string ToJSon(object obj)
{
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
return oSerializer.Serialize(obj);
}
public string GetRandomDate(DateTime dtStart, DateTime dtEnd)
{
int cdayRange = (dtEnd - dtStart).Days;
return dtStart.AddDays(rand.NextDouble() * cdayRange).ToString();
}
}
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="PlanListRESTService.PlanListRESTService" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP"
contract="PlanListRESTService.IPlanListRESTService"
behaviorConfiguration="Web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
@{
ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<div id="example" class="k-content">
<div class="k-toolbar k-grid-toolbar">
<a class="k-button k-button-icontext k-add-button" href="#"><span class="k-icon k-add"></span>Add new plan</a>
</div>
<div id="listView"></div>
<div id="pager" class="k-pager-wrap">
</div>
<script type="text/x-kendo-tmpl" id="template">
<div class="plan-view">
<dl>
<dt>Name</dt>
<dd>${Name}</dd>
<dt>No. of jobs</dt>
<dd>${NoOfJobs}</dd>
<dt>Next run:</dt>
<dd>${NextRun}</dd>
<dt>Status</dt>
<dd>${Status}</dd>
</dl>
<div class="edit-buttons">
<a class="k-button k-button-icontext k-edit-button" href="\\#"><span class="k-icon k-edit"></span>Edit</a>
<a class="k-button k-button-icontext k-delete-button" href="\\#"><span class="k-icon k-delete"></span>Delete</a>
</div>
</div>
</script>
<script type="text/x-kendo-tmpl" id="editTemplate">
<div class="plan-view">
<dl>
<dt>Plan Name</dt>
<dd>
<input type="text" data-bind="value:Name" name="Name" required="required" validationMessage="required" />
<span data-for="Name" class="k-invalid-msg"></span>
</dd>
<dt>No. of jobs</dt>
<dd>
<input type="text" data-bind="value:NoOfJobs" data-role="numerictextbox" data-type="number" name="NoOfJobs" required="required" min="0" validationMessage="required" />
<span data-for="NoOfJobs" class="k-invalid-msg"></span>
</dd>
<dt>Status</dt>
<dd>
<input type="text" data-bind="value:Status" name="Status" required="required" data-type="number" min="0" validationMessage="required" />
<span data-for="Status" class="k-invalid-msg"></span>
</dd>
<dt>Next run</dt>
<dd>
<input type="text" data-bind="value:NextRun" name="NextRun" required="required" data-type="number" min="0" validationMessage="required" />
<span data-for="NextRun" class="k-invalid-msg"></span>
</dd>
</dl>
<div class="edit-buttons">
<a class="k-button k-button-icontext k-update-button" href="\\#"><span class="k-icon k-update"></span>Save</a>
<a class="k-button k-button-icontext k-cancel-button" href="\\#"><span class="k-icon k-cancel"></span>Cancel</a>
</div>
</div>
</script>
<script>
$(document).ready(function () {
var crudServiceBaseUrl = "http://localhost:8080/PlanListRESTService",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/fillplanlist/20",
dataType: "jsonp"
},
//update: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
//destroy: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
//create: {
// url: crudServiceBaseUrl + "/fillplanlist/20",
// dataType: "jsonp"
//},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 6,
schema: {
model: {
id: "Id",
fields: {
Id: { editable: false, nullable: true },
Name: "Name",
NextRun: "Next run",
NoOfJobs: { type: "number" },
Status: { type: "number" }
}
}
}
});
$("#pager").kendoPager({
dataSource: dataSource
});
var listView = $("#listView").kendoListView({
dataSource: dataSource,
template: kendo.template($("#template").html()),
editTemplate: kendo.template($("#editTemplate").html())
}).data("kendoListView");
$(".k-add-button").click(function(e) {
listView.add();
e.preventDefault();
});
});
</script>
<style scoped>
.plan-view
{
float: left;
width: 300px;
margin: 5px;
padding: 3px;
-moz-box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
-webkit-box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
box-shadow: inset 0 0 50px rgba(0,0,0,0.1);
border-top: 1px solid rgba(0,0,0,0.1);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.plan-view dl
{
margin: 10px 0;
padding: 0;
min-width: 0;
}
.plan-view dt, dd
{
float: left;
margin: 0;
padding: 0;
height: 30px;
line-height: 30px;
}
.plan-view dt
{
clear: left;
padding: 0 5px 0 15px;
text-align: right;
opacity: 0.6;
width: 100px;
}
.k-listview
{
border: 0;
padding: 0;
min-width: 0;
}
.k-listview:after, .plan-view dl:after
{
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.edit-buttons
{
text-align: right;
padding: 5px;
min-width: 100px;
border-top: 1px solid rgba(0,0,0,0.1);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.k-toolbar, #listView, .k-pager-wrap
{
width: 960px;
/*margin: 0 auto;*/
-webkit-border-radius: 11px;
-moz-border-radius: 11px;
border-radius: 11px;
}
#listView
{
width: 960px;
}
span.k-invalid-msg
{
position: absolute;
margin-left: 160px;
margin-top: -26px;
}
</style>
</div>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<p>
To learn more about working with the Kendo UI Complete for ASP.NET MVC, you can visit the folowing resources:
</p>
<ul>
<li><a href="http://demos.kendoui.com/">online demos</a></li>
<li><a href="http://docs.kendoui.com/getting-started/using-kendo-with/aspnet-mvc/introduction">online documentation</a></li>
<li><a href="http://www.kendoui.com/forums.aspx">community forums</a></li>
<li><a href="http://tv.telerik.com/search?FilterByTags=KendoUI">videos on Telerik TV</a></li>
</ul>