考虑到ODataController的PUT method的以下典型实现,我如何使完全相同的方法也可以作为POST使用?
我正在开发一个OData端点,该端点将从无法控制的外部系统调用。似乎该系统通过发送带有uri键而不是使用PUT的POST错误地实现了Update语义(以告诉我的系统更新实体)。
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
我的第一个猜测是用[AcceptVerbs(“ PUT”,“ POST”)]注释该方法,以使相同的确切方法实现可用作POST,但这是行不通的。可能是ODataConventionModelBuilder默认设置对此一无所知...
理想情况下,我想保留基于标准的PUT和用于插入的常规POST,但要添加一个与put相同但仅在动词上有所不同的特殊帖子。
谢谢
答案 0 :(得分:1)
在关于外部数据源/外部对象的odata端点实现中找到一些不太明显的documentation on salesforce.com之后,对我来说很明显,salesforce.com尝试在外部对象上调用POST进行更新语义,但是还添加了X-HTTP-METHOD设置为PATCH。
因此,解决方案是实现以下类:
public class MethodOverrideHandler : DelegatingHandler
{
readonly string[] _methods = { "DELETE", "HEAD", "PUT", "PATCH", "MERGE" };
const string _header1 = "X-HTTP-Method-Override";
const string _header2 = "X-HTTP-Method";//salesforce special behavior???
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Check for HTTP POST with the X-HTTP-Method-Override header.
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header1))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header1).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
else if (request.Method == HttpMethod.Post && request.Headers.Contains(_header2))
{
// Check if the header value is in our methods list.
var method = request.Headers.GetValues(_header2).FirstOrDefault();
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
{
// Change the request method.
request.Method = new HttpMethod(method);
}
}
return base.SendAsync(request, cancellationToken);
}
}
并按如下方式在WebApiConfig.Register(HttpConfiguration config)
中注册:
config.MessageHandlers.Add(new MethodOverrideHandler());
现在,用于外部对象上Salesforce更新操作的不符合odata的POST将委派给我最初发布的PUT方法的符合标准的odata实施(在ODataController中)。
我希望这对以后的人有帮助...
答案 1 :(得分:0)
我的方法是使用while (y < 768 )
将更多的逻辑放入该方法中,以检查并查看数据库中是否已存在记录,然后检查数据是否为空。
update.Id
EDIT 刚刚注意到ProductExists方法...我会将其从catch块中取出并投入尝试
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//might have to get rid of this condition for the sake of new entries
//if (key != update.Id)
//{
//return BadRequest();
//}
try
{
//not sure what the name of your table is so I'm going to call it ProductTable
var foo = db.ProductTable.Where(p => p.Id == update.Id).FirstOrDefault();
if(foo == null)
{
db.Entry(update).State = EntityState.Added;
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.Accepted);
}
else
{
db.Entry(update).State = EntityState.Modified;
await db.SaveChangesAsync();
return Updated(update);
}
}
catch (DbUpdateConcurrencyException ex)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw new DbUpdateConcurrencyException(ex.Message);
}
}
}