来自EntitySetController中的PATCH请求的406(NotAcceptable)响应。 Web API 2.1。的OData

时间:2014-04-19 06:10:08

标签: c# asp.net-web-api odata

我非常困惑,希望有人能说清楚。升级到最新版本的Web API(从Microsoft.AspNet.WebApi.xxx 5.0.0。到Microsoft.AspNet.WebApi.xxx 5.1.2)后,OData的EntitySetController停止处理PATCH谓词并返回406(不可接受)代码。

实施没有改变:

public class ODataAnnouncementController : EntitySetController<TEntity, TKey> where TEntity : class
{
    (...)

    protected override Announcement PatchEntity(Guid key, Delta<Announcement> patch)
    {
        var announcement = getEntityByKeyOrThrowException(key);
        patch.Patch(announcement);
        AnnouncementManager.Instance.Save(announcement, true);
        return announcement;
    }
}

请求也没有改变:

  

接受:application / json

     

Content-Type:application / json;字符集= UTF-8

     

PATCH:http:// {url} / odata / Announcement(guid'62E34FB3-A37E-413F-9843-642D95BA580A')

     

{“描述”:“单元测试中的修补描述”}

方法中的断点未被击中,好像“Delta&lt; Announcement&gt;&gt; patch”从未反序列化。它实际上确实触及方法内部断点的唯一条件是当请求BODY为空时导致补丁对象当然为空。

所有其他动词(GET,POST,PUT,DELETE)都可以正常工作。

之前曾经工作过。有人知道有关PATCH的Web API 2.1有任何重大变化吗?我怎么能排除故障呢?

非常感谢

比尔

更新

这是C#模型:

[Serializable]
[DataContract]
public class Announcement
{                       
    private Guid _announcementID;
    private string _description;
    private bool _isPrivate;
    private DateTime _createdTime;
    private Nullable<Guid> _membershipID;

    [DataMember]
    public Guid AnnouncementID
    {
        get { return this._announcementID; }
        set { this._announcementID = value; }
    }
    [DataMember]
    public string Description
    {
        get { return this._description; }
        set { this._description = value; }
    }       
    [DataMember]
    public bool IsPrivate
    {
        get { return this._isPrivate; }
        set { this._isPrivate = value; }
    }
    [DataMember]
    public DateTime CreatedTime
    {
        get { return this._createdTime; }
        set { this._createdTime = value; }
    }
    [DataMember]
    public Nullable<Guid> MembershipID
    {
        get { return this._membershipID; }
        set { this._membershipID = value; }
    }
}

我使用显式数据模型:

var routingConventions = ODataRoutingConventions.CreateDefault();
config.Routes.MapODataRoute(
            routeName: "ODataRoute",
            routePrefix: "odata",
            model: BuildExplicitODataModel(),
            pathHandler: new DefaultODataPathHandler(),
            routingConventions: routingConventions  
        );

public static IEdmModel BuildExplicitODataModel()
{
ODataModelBuilder modelBuilder = new ODataModelBuilder();
var announcementSet = buildAnnouncementModel(modelBuilder);
return modelBuilder.GetEdmModel();
}

private static EntitySetConfiguration<Announcement> buildAnnouncementModel(ODataModelBuilder modelBuilder)
{
        var announcementSet = modelBuilder.EntitySet<Announcement>("Announcement");
        announcementSet.HasEditLink(
            entityContext => entityContext.Url.ODataLink(
                new EntitySetPathSegment(entityContext.EntitySet.Name),
                new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.AnnouncementID, ODataVersion.V3))),
            followsConventions: true);

        announcementSet.HasIdLink(
            entityContext => entityContext.Url.ODataLink(
                new EntitySetPathSegment(entityContext.EntitySet.Name),
                new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.AnnouncementID, ODataVersion.V3))),
                followsConventions: true);

        var announcement = announcementSet.EntityType;
        announcement.HasKey(p => p.AnnouncementID);
        announcement.Property(p => p.Description);
        announcement.Property(p => p.IsPrivate);
        announcement.Property(p => p.CreatedTime);
        announcement.Property(p => p.MembershipID);
        return announcementSet;
}

这是请求有效负载:

  

PATCH http:// {url} / odata / Announcement(guid'62E34FB3-A37E-413F-9843-642D95BA580A')
  接受:application / json
  Content-Type:application / json;字符集= UTF-8

BODY:

  

{“描述”:“单元测试中的修补描述”}

1 个答案:

答案 0 :(得分:0)

检查完最新文件EntityRoutingConvention.cs后, 我发现actionName只能是Patch或PatchAnnouncement。

永远不会调用PatchEntity。

您可以尝试使用Patch或PatchAnnouncement重命名方法吗?


<强>更新

然而,它在我的repro项目中工作正常。 你能比较你的参考版本,WebApiConfig.cs,AnnouncementsController.cs和我的请求。

我注意到一些不同之处:

  1. 控制器名称是ODataAnnouncementController,你使用&#34; ODataAnnouncement&#34;作为模型构建器中的权利名称?
  2. 在您的PATCH请求中,为什么要使用&#34;公告&#34;而不是&#34;公告&#34;?
  3. <强>参考

    Microsoft.AspNet.WebApi 5.1.2 targetFramework =&#34; net45&#34;

    <强> WebApiConfig.cs

    using System.Web.Http;
    using System.Web.Http.OData.Builder;
    using ReproPatchNotWork.Models;
    
    namespace ReproPatchNotWork
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                config.MapHttpAttributeRoutes();
    
                ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
                builder.EntitySet<Announcement>("Announcements");
                config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
            }
        }
    }
    

    <强> AnnouncementsController.cs

    using System;
    using System.Web.Http.OData;
    
    namespace ReproPatchNotWork.Models
    {
        public class AnnouncementsController : EntitySetController<Announcement, Guid>
        {
            protected override Announcement PatchEntity(Guid key, Delta<Announcement> patch)
            {
                Announcement announcement = new Announcement();
                patch.Patch(announcement);
                return announcement;
            }
        }
    }
    

    请求

    PATCH http:// {url} / odata / Announcements(guid&#39; 62E34FB3-A37E-413F-9843-642D95BA580A&#39;)

    接受:application / json

    Content-Type:application / json;字符集= UTF-8

    正文:{&#34;描述&#34;:&#34;来自单元测试和#34的补丁描述;}