OData v4.0 - PUT,PATCH,DELETE返回404

时间:2017-08-08 08:26:08

标签: routing odata http-delete http-put http-patch

我们有一个带有以下Nuget软件包的C#.NET Web Api项目,其中包括其他软件包:

  • MVC 5.2.3
  • 用于OData v4.0的Microsoft ASP.NET Web API 2.2(版本6.0.0)
  • Microsoft.AspNet.OData.Versioning(版本2.1.0)

在IIS中,在applicationhost.config文件中为ExtensionlessUrl-Integrated-4.0启用了PUT,PATCH和DELETE谓词。

以下是WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        System.Web.Routing.RouteTable.Routes.Ignore("robots.txt");
        System.Web.Routing.RouteTable.Routes.Ignore("{resource}.axd/{*pathInfo}");
        // http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api
        System.Web.Routing.RouteTable.Routes.MapHttpRoute(
            name: "Error404",
            routeTemplate: "{*url}",
            defaults: new { controller = "Error", action = "Handle404" }
        );

        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

        // NOTE: Method below removed and functionality to replace it not working due to bug https://github.com/OData/WebApi/issues/812
        //config.EnableCaseInsensitive(caseInsensitive: true);

        // http://stackoverflow.com/questions/30987439/elmah-axd-on-webapi-2-2-no-http-resource-was-found
        config.Routes.MapHttpRoute(
            "AXD", "{resource}.axd/{*pathInfo}", null, null,
            new StopRoutingHandler());

        // we will use attribute routing
        config.MapHttpAttributeRoutes();

        // set default page size and total number of rows to return from query
        config.AddODataQueryFilter(new EnableQueryAttribute
        {
            PageSize = ConfigurationWrapper.Singleton.ODataPageSize,
            MaxTop = ConfigurationWrapper.Singleton.ODataMaxTop,
            MaxExpansionDepth = ConfigurationWrapper.Singleton.ODataMaxExpansionDepth
        });

        config.AddApiVersioning(o =>
        {
            o.AssumeDefaultVersionWhenUnspecified = true;
            o.ReportApiVersions = true;
        });

        // http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-routing-conventions
        // Create the default collection of built-in conventions
        IList<IODataRoutingConvention> conventions = ODataRoutingConventions.CreateDefault();

        // Insert the custom convention at the start of the collection; caters for ~/entityset/key/navigation/key
        conventions.Insert(0, new NavigationIndexRoutingConvention());

        config.MapODataServiceRoute(
            routeName: "odata",
            routePrefix: null,
            model: EdmModelBuilder.GetEdmModel(),
            pathHandler: new DefaultODataPathHandler(),
            routingConventions: conventions,
            batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));

        //config.MapVersionedODataRoutes(
        //routeName: "odata",
        //routePrefix: null,
        //models: EdmModelBuilder.GetEdmModels(config),
        //pathHandler: new DefaultODataPathHandler(),
        //routingConventions: GetConventions());

        // EnableDependencyInjection is required if you want to have OData routes and custom routes together in a controller
        config.EnableDependencyInjection();
        config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); //new line

        config.Formatters.Remove(config.Formatters.XmlFormatter);

        // The XML formatter is not well enough supported by OData v4.0 (apparently works with OData v3.0), reverting to JSON only
        config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create());

        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        /* ReferenceLoopHandling.Ignore: Json.NET will ignore objects in reference loops and not serialize them. The first time an object is encountered
         * it will be serialized as usual but if the object is encountered as a child object of itself the serializer will skip serializing it.
         */
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

        config.Filters.AddRange(new List<IFilter>
        {
            new ForfrontAuthenticationAttribute(), // custom
            new RateLimitAttribute(), // custom
            new RequestAuditAttribute(), // custom
            new SuppressResponseCodeSuccessAttribute(), // custom
            new ExceptionHandlingAttribute() // custom
        });

        // http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api
        config.Services.Replace(typeof(IHttpControllerSelector), new HttpNotFoundAwareDefaultHttpControllerSelector(config));
        config.Services.Replace(typeof(IHttpActionSelector), new HttpNotFoundAwareControllerActionSelector());

        config.EnsureInitialized();
    }
}

我想要调用的控制器操作定义为:

[ApiVersion("1.0")]
[ODataRoutePrefix("MicrosoftDynamicsContactFieldMappings")]
[ControllerName("MicrosoftDynamicsContactFieldMappings")]
public class MicrosoftDynamicsContactFieldMappingsController : ForfrontODataController
{
    // DELETE: MicrosoftDynamicsContactFieldMappings(5)
    /// <summary>
    /// We don't really delete records, but update, user doesn't need to know internal workings.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    [AcceptVerbs("DELETE")]
    public IHttpActionResult Delete([FromODataUri] int key)
    {
        // this is not being called
    }
}

fiddler中的REST API请求格式为:

DELETE http://dev2.e-shot.local/MicrosoftDynamicsContactFieldMappings(11) 
HTTP/1.1
Host: dev2.e-shot.local
User-Agent: Fiddler
Authorization: Token [token value goes here]
Accept-Language: en-GB

当发出DELETE,(PATCH或PUT)请求时,返回404。看起来不考虑OData路由。

希望不必调试OData程序集,任何帮助都非常感激。

谢谢, 瑞克

2 个答案:

答案 0 :(得分:1)

更新: 我已经设法通过使用属性路由和避免OData路由约定来使DELETE,PATCH和PUT动词工作。

<div class="three columns bear">
  <h3>Matching Tartan Scarf (£2.50)</h3>
  <label>
    <input type="checkbox" autocomplete="off" name="scarf" id="scarf" value="2.5" />
    <img src="Images/Scarft.png">
  </label>
  <p>Personalise your bear with a matching tartan scarf. It gets cold up here in Scotland, and this is the best way to keep your bear warm.</p>
</div>

<div id="checkoutnecktie"></div>

答案 1 :(得分:0)

就我而言

表名称为:用户

主键字段: IDUser

我必须在EF模型中将 IDUser 列名重命名为 UserId 并运行更新数据库。

在执行以下代码后有效:

    [Route("({key})")]
    [HttpPatch]
    public IActionResult Patch([FromODataUri]int key,
        Delta<mUSER> userPatch)
    {}