OData v4.0 - PUT, PATCH, DELETE возвращает 404

У нас есть проект C # .NET Web Api со следующими пакетами Nuget среди других:

  • MVC 5.2.3
  • Microsoft ASP.NET Web API 2.2 для OData v4.0 (версия 6.0.0)
  • Microsoft.AspNet.OData.Versioning (версия 2.1.0)

В IIS команды PUT, PATCH и DELETE были включены для ExtensionlessUrl-Integrated-4.0 в файле applicationhost.config.

Ниже приведен файл 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
    }
}

Запрос 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

Когда делается запрос на УДАЛИТЬ, (ПАТЧ или ПОСТАВИТЬ), возвращается 404. Похоже, маршрутизация OData не рассматривается.

Надеялся, что не придется отлаживать сборки OData, любая помощь очень ценится.

Спасибо, Рик


person user2146402    schedule 08.08.2017    source источник
comment
Благодарим вас за объявление параметра web.config. В IIS команды PUT, PATCH и DELETE были включены для ExtensionlessUrl-Integrated-4.0 в файле applicationhost.config. Это была моя недостающая часть. Глагол PATCH не был включен. Я добавил, и сработал метод HttpPatch.   -  person Hamit Enes    schedule 04.11.2020


Ответы (2)


ОБНОВЛЕНИЕ: мне удалось заставить работать команды DELETE, PATCH и PUT, используя маршрутизацию атрибутов и избегая соглашения о маршрутизации OData.

[AcceptVerbs("DELETE")]
[Route("MicrosoftDynamicsContactFieldMappings({key})")]
public IHttpActionResult Delete([FromUri] int key)
{
}

[AcceptVerbs("PATCH", "MERGE")]
[Route("MicrosoftDynamicsContactFieldMappings({key})")]
public IHttpActionResult Patch([FromODataUri] int key, 
       Delta<MicrosoftDynamicsContactFieldMapping> item)
{
}
person user2146402    schedule 08.08.2017

В моем случае

Имя таблицы было: Пользователи.

Поле первичного ключа: IDUser

Мне пришлось переименовать имя столбца IDUser в UserId в модели EF и запустить обновление базы данных.

после выполнения этого кода ниже работал:

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