Kendo ui Web API+;OData-修补程序请求400错误
我有一个连接到WebApi 2 OData控制器的KendoUI数据源,在更新操作方面遇到问题。我可以很好地创建和删除 在进行任何更新后,当我调用将数据源同步到服务器时,我会收到一个400错误:Kendo ui Web API+;OData-修补程序请求400错误,kendo-ui,odata,http-status-code-400,asp.net-web-api2,httpverbs,Kendo Ui,Odata,Http Status Code 400,Asp.net Web Api2,Httpverbs,我有一个连接到WebApi 2 OData控制器的KendoUI数据源,在更新操作方面遇到问题。我可以很好地创建和删除 在进行任何更新后,当我调用将数据源同步到服务器时,我会收到一个400错误: { "odata.error":{ "code":"","message":{ "lang":"en-US","value":"The request is invalid." },"innererror":{ "message":"patch : Inval
{
"odata.error":{
"code":"","message":{
"lang":"en-US","value":"The request is invalid."
},"innererror":{
"message":"patch : Invalid JSON. A token was not recognized in the JSON content.\r\n","type":"","stacktrace":""
}
}
}
VisualStudio中的调试显示,正在向修补程序函数传递Id,而不是公司对象。Firebug显示修补程序请求如下所示:
models=%7B%22Id%22%3A1026%2C%22Title%22%3A%22Test+Company+test%22%7D
我有一种预感,这里面有一些服务器不明白的地方
模型很简单,我将控制器作为VS为我生成的任何对象:
型号:
public class Company {
public Company() { }
public Company(Company company) {
this.Id = company.Id;
this.Title = company.Title;
this.Projects = company.Projects;
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
上市公司{
上市公司(){}
上市公司(公司){
this.Id=company.Id;
this.Title=company.Title;
this.Projects=company.Projects;
}
公共int Id{get;set;}
公共字符串标题{get;set;}
公共虚拟ICollection项目{get;set;}
}
控制器:
public class CompanyController : ODataController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET odata/Company
[Queryable]
public IQueryable<Company> GetCompany()
{
return db.Companies;
}
// GET odata/Company(5)
[Queryable]
public SingleResult<Company> GetCompany([FromODataUri] int key)
{
return SingleResult.Create(db.Companies.Where(company => company.Id == key));
}
// PUT odata/Company(5)
public async Task<IHttpActionResult> Put([FromODataUri] int key, Company company)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != company.Id)
{
return BadRequest();
}
db.Entry(company).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CompanyExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(company);
}
// POST odata/Company
public async Task<IHttpActionResult> Post(Company company)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Companies.Add(company);
await db.SaveChangesAsync();
return Created(company);
}
// PATCH odata/Company(5)
[AcceptVerbs("PATCH", "MERGE")]
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Company> patch)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Company company = await db.Companies.FindAsync(key);
if (company == null)
{
return NotFound();
}
patch.Patch(company);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CompanyExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(company);
}
// DELETE odata/Company(5)
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
Company company = await db.Companies.FindAsync(key);
if (company == null)
{
return NotFound();
}
db.Companies.Remove(company);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
// GET odata/Company(5)/Projects
[Queryable]
public IQueryable<Project> GetProjects([FromODataUri] int key)
{
return db.Companies.Where(m => m.Id == key).SelectMany(m => m.Projects);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool CompanyExists(int key)
{
return db.Companies.Count(e => e.Id == key) > 0;
}
}
公共类公司控制器:ODataController
{
私有ApplicationDbContext db=新ApplicationDbContext();
//获得odata/公司
[可查询]
公共IQueryable GetCompany()
{
返回数据库公司;
}
//获取odata/公司(5)
[可查询]
public SingleResult GetCompany([FromODataUri]int key)
{
返回SingleResult.Create(db.companys.Where(company=>company.Id==key));
}
//PUT odata/公司(5)
公共异步任务Put([FromODataUri]int-key,公司)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
if(key!=company.Id)
{
返回请求();
}
db.Entry(company.State=EntityState.Modified;
尝试
{
等待db.saveChangesSync();
}
catch(DbUpdateConcurrencyException)
{
如果(!CompanyExists(key))
{
返回NotFound();
}
其他的
{
投掷;
}
}
更新申报表(公司);
}
//后奥达塔/公司
公共异步任务岗(公司)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
db.companys.Add(公司);
等待db.saveChangesSync();
创建的回报(公司);
}
//补丁odata/公司(5)
[接受动词(“补丁”、“合并”)]
公共异步任务修补程序([FromODataUri]int-key,增量修补程序)
{
如果(!ModelState.IsValid)
{
返回请求(ModelState);
}
Company Company=wait db.companys.FindAsync(键);
如果(公司==null)
{
返回NotFound();
}
patch.patch(公司);
尝试
{
等待db.saveChangesSync();
}
catch(DbUpdateConcurrencyException)
{
如果(!CompanyExists(key))
{
返回NotFound();
}
其他的
{
投掷;
}
}
更新申报表(公司);
}
//删除odata/公司(5)
公共异步任务删除([FromODataUri]int-key)
{
Company Company=wait db.companys.FindAsync(键);
如果(公司==null)
{
返回NotFound();
}
db.companys.Remove(公司);
等待db.saveChangesSync();
返回状态码(HttpStatusCode.NoContent);
}
//获取odata/公司(5)/项目
[可查询]
公共IQueryable GetProjects([FromODataUri]int-key)
{
返回db.companys.Where(m=>m.Id==key),选择many(m=>m.Projects);
}
受保护的覆盖无效处置(布尔处置)
{
如果(处置)
{
db.Dispose();
}
基地。处置(处置);
}
私有布尔公司存在(整数密钥)
{
返回db.companys.Count(e=>e.Id==key)>0;
}
}
最后,KendoUI,HTML/Javascript是:
<h2>Company List</h2>
<div id="company-data">
<div class="col-md-3 col-sm-5 col-xs-5">
<div id="company-list" style="padding: 0px; height: 500px; overflow: auto" data-role="listview" data-template="list-template" data-bind="source: companies, events: {change: OnSelect}" data-selectable="true"></div>
<div>
<button class="btn btn-success btn-sm" id="btn-add-company"><span class="glyphicon glyphicon-plus"></span> Add</button>
<button class="btn btn-danger btn-sm" id="btn-delete-company" data-bind="visible: hasSelection, click: deleteSelection"><span class="glyphicon glyphicon-remove"></span> Delete</button>
<button class="btn btn-default btn-sm" id="btn-clear-company" data-bind="visible: hasSelection, click: clearSelection"><span class="glyphicon glyphicon-ban-circle"></span> Clear</button>
<button class="btn btn-primary btn-sm btn-block" id="btn-save" data-bind="visible: hasChanges, click: saveChanges"><span class="glyphicon glyphicon-cloud-upload"></span> Save All</button>
</div>
</div>
<div class="col-md-9 col-sm-7 col-xs-7" data-bind="visible: hasSelection">
<label for="company-title">Title:</label><br />
<input id="company-title" data-bind="value: selectedItem.Title" ><br />
</div>
</div>
<script type="text/x-kendo-template" id="list-template">
<div class="company" style="cursor: pointer">
<span data-bind="text: Title"></span>
</div>
</script>
<script>
$(function () {
var firstSync = true;
var companyVM = new kendo.observable({
// Data Source.
companies: new kendo.data.DataSource({
type: 'odata',
transport: {
create: {
url: '/odata/Company',
dataType: 'json',
type: 'POST'
},
read: {
url: '/odata/Company',
dataType: 'json'
},
update: {
url: function (data) {
return '/odata/Company(' + data.Id + ')';
},
dataType: 'json',
type: 'PATCH'
},
destroy: {
url: function (data) {
return '/odata/Company(' + data.Id + ')';
},
dataType: 'json',
type: 'DELETE'
},
parameterMap: function (options, operation) {
if (operation !== "read" && options) {
console.log(operation + '*: ' + kendo.stringify(options));
return {
models: kendo.stringify(options)
};
}
console.log(operation + ': ' + kendo.stringify(options));
return options;
}
},
schema: {
data: function (data) {
return data['value'];
},
total: function (data) {
return data['odata.count'];
},
model: {
id: 'Id',
fields: {
Title: { type: 'string' }
}
}
},
change: function () {
// We don't want to fire the first time the data loads because that counts as changed.
if (!firstSync)
companyVM.set('hasChanges', true);
else
firstSync = false;
}
}),
// Properties.
selectedItem: null,
hasSelection: function () {
return this.get('selectedItem') != null;
},
hasChanges: false,
// Functions.
clearSelection: function() {
this.set('selectedItem', null);
$('#company-list').getKendoListView().clearSelection();
},
saveChanges: function() {
this.companies.sync();
this.set('hasChanges', false);
},
deleteSelection: function () {
if (confirm('Warning, deletion is permanent! Are you sure you wish to delete this item?')) {
this.companies.remove(this.selectedItem);
this.set('hasChanges', true);
this.clearSelection();
}
},
// Events.
OnSelect: function (e) {
var list = $(e.sender.element).getKendoListView();
var row = list.select();
var item = list.dataSource.getByUid(row.data('uid'));
this.set('selectedItem', item);
}
});
kendo.bind($('#company-data'), companyVM);
});
</script>
公司名单
添加
删除
清楚的
拯救一切
标题:
$(函数(){
var firstSync=true;
var companyVM=新剑道。可观察({
//数据源。
公司:新建kendo.data.DataSource({
类型:'odata',
运输:{
创建:{
url:“/odata/Company”,
数据类型:“json”,
类型:“POST”
},
阅读:{
url:“/odata/Company”,
数据类型:“json”
},
更新:{
url:函数(数据){
返回'/odata/Company('+data.Id+');
},
数据类型:“json”,
类型:“补丁”
},
销毁:{
url:函数(数据){
返回'/odata/Company('+data.Id+');
},
数据类型:“json”,
键入:“删除”
},
parameterMap:功能(选项、操作){
如果(操作!=“读取”&&options){
log(操作+'*:'+kendo.stringify(选项));
返回{
模型:剑道.字符串化(选项)
};
}
log(操作+':'+kendo.stringify(选项));
返回选项;
}
},
s
parameterMap: function (data, operation) {
return JSON.stringify(data);
}