C# 如何防止odata控制器中自定义操作的HTTP 404?

C# 如何防止odata控制器中自定义操作的HTTP 404?,c#,asp.net,asp.net-mvc,asp.net-web-api2,odata,C#,Asp.net,Asp.net Mvc,Asp.net Web Api2,Odata,我有一个ASP.NetWebApi2项目托管了odataApiController和ODataController 我想在ODataController中添加一个自定义操作 我看到,这似乎可以通过在所需操作上添加[HttpPost]属性来实现,或者在使用时使用特定的配置来实现 为了区分odata路由和webapi路由,我们使用以下方案: 小田: webapi: 我尝试了这两种解决方案,但都没有成功,都得到了HTTP404的结果 我的自定义操作定义如下: public class SomeMo

我有一个
ASP.Net
WebApi2
项目托管了odata
ApiController
ODataController

我想在
ODataController
中添加一个自定义操作

我看到,这似乎可以通过在所需操作上添加
[HttpPost]
属性来实现,或者在使用时使用特定的配置来实现

为了区分odata路由和webapi路由,我们使用以下方案:

  • 小田:
  • webapi:
我尝试了这两种解决方案,但都没有成功,都得到了HTTP404的结果

我的自定义操作定义如下:

public class SomeModelsController : ODataController
{
    //...

    [EnableQuery]
    public IHttpActionResult Get()
    {
        //...
        return Ok(data);
    }

    public IHttpActionResult MyCustomAction(int parameterA, int parameterB)
    {
        //...
        return Json(data);
    }

    //...
}
因此,正如您所猜测的,控制器上的Get调用与odata完美配合。但是,正确设置MyCustomAction有点困难

以下是我尝试过的:

  • 在MyCustomAction上设置[HttpPost]属性

    [HttpPost]
    public IHttpActionResult MyCustomAction(int parameterA, int parameterB)
    {
        //...
        return Json(data);
    }
    
    我还尝试用
    [EnableQuery]
    属性装饰MyCustomAction。
    此外,我还尝试在方法上添加
    [AcceptVerbs(“GET”、“POST”)]
    属性,没有任何更改

  • 配置ODataConventionModelBuilder

      private static IEdmModel GetEdmModel()
      {
          var builder = new ODataConventionModelBuilder
          {
              Namespace = "MyApp",
              ContainerName = "DefaultContainer"
          };
          // List of entities exposed and their controller name
          // ...
          FunctionConfiguration function = builder.Function("MyCustomAction ").ReturnsFromEntitySet<MyModel>("SomeModels");
          function.Parameter<int>("parameterA");
          function.Parameter<int>("parameterB");
          function.Returns<MyModel>();
    
          return builder.GetEdmModel();
      }
    
    private静态IEdmModel GetedModel()
    {
    var builder=新ODataConventionModelBuilder
    {
    Namespace=“MyApp”,
    ContainerName=“DefaultContainer”
    };
    //公开的实体及其控制器名称的列表
    // ...
    FunctionConfiguration function=builder.function(“MyCustomAction”).ReturnsFromEntitySet(“SomeModels”);
    函数参数(“参数”);
    函数参数(“参数B”);
    函数返回();
    返回builder.GetEdmModel();
    }
    
    还尝试使用
    [EnableQuery]
    HttpPost
    [AcceptVerbs(“GET”、“POST”)]
    属性装饰MyCustomAction

  • 我仍然得到HTTP404结果

    我的查询url如下:
    http://localhost:9292/myProject/odata/SomeModels/MyCustomAction?parameterA=123¶meterB=123

    我还试着将参数发布到
    http://localhost:9292/myProject/odata/SomeModels/MyCustomAction
    具有相同的结果。实际上,无论有无参数,我都会获得HTTP 404的状态。

    我已经用Visual Studio 2017从头开始创建了一个工作示例。 如果您想了解更多信息,可以阅读本教程:

    • 创建新的ASP.Net Web应用程序(无.Net核心)

    • 选择WebApi模板

    • 从NuGet安装软件包Microsoft.AspNet.OData(我使用的是6.0.0版)

    • 在模型文件夹中创建一个简单的模型类

    TestModel.cs

    namespace DemoOdataFunction.Models
    {
        public class TestModel
        {
            public int Id { get; set; }
    
            public int MyProperty { get; set; }
    
            public string MyString { get; set; }
        }
    }
    
    • 配置WebApiConfig
    WebApiConfig.cs

    using DemoOdataFunction.Models;
    using System.Web.Http;
    using System.Web.OData.Builder;
    using System.Web.OData.Extensions;
    
    
    namespace DemoOdataFunction
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                ODataModelBuilder builder = new ODataConventionModelBuilder();
                builder.Namespace = "MyNamespace";
    
                builder.EntitySet<TestModel>("TestModels");
    
                ActionConfiguration myAction = builder.EntityType<TestModel>().Action("MyAction");
                myAction.Parameter<string>("stringPar");
    
    
                FunctionConfiguration myFunction = builder.EntityType<TestModel>().Collection.Function("MyFunction");
                myFunction.Parameter<int>("parA");
                myFunction.Parameter<int>("parB");
                myFunction.ReturnsFromEntitySet<TestModel>("TestModels");
    
    
                config.MapODataServiceRoute(
                    routeName: "ODataRoute",
                    routePrefix: "odata",
                    model: builder.GetEdmModel()
                    );
            }
        }
    }
    
    这是对MyFunction的请求:

    GET
    http://localhost:xxxx/odata/TestModels/MyNamespace.MyFunction(parA=1,parB=2)
    

    我在控制器上使用HTTP POST和路由功能,如下所示:

            [HttpPost]
            [Route("{application}/{envName}/date/{offset}")]
            [ResponseType(typeof(DateInfo))]
            public async Task<IHttpActionResult> SetDateOffsetForEnvironmentName(string application, string envName, string offset)
            {
            }
    
    [HttpPost]
    [路由(“{application}/{envName}/date/{offset}”)]
    [响应类型(类型(日期信息))]
    公共异步任务setDateOffsetForenEnvironmentName(字符串应用程序、字符串环境名称、字符串偏移量)
    {
    }
    
    您是否可以尝试在函数上设置路由,然后对其调用post方法,如下所示:

    POST/status/ENVICES/ATONLINE/PTH/date/0


    还可以尝试通过Fiddler捕获请求,并查看传递的内容

    请求URL是什么?是这样吗?@FrancescoBozzi,我编辑了我的问题以添加查询url(在末尾)。我无法让它工作。我在URL中尝试了使用和不使用名称空间,您是否仍然得到HTTP 404结果?是的,仍然是HTTP 404您是否尝试了带有[HttpGet]修饰的函数的get请求?如果这对自定义OData函数很有效,似乎将
    Web.config
    文件中的
    System.Web.Handlers.TransferRequestHandler
    的路径设置为
    /*
    ,而不是
    *。
    会阻止访问WebApiController,如果你有任何想法,这将是很大的帮助!
    POST
    http://localhost:xxxx/odata/TestModels(1)/MyNamespace.MyAction
    {
      "stringPar":"hello"
    }
    
    GET
    http://localhost:xxxx/odata/TestModels/MyNamespace.MyFunction(parA=1,parB=2)
    
            [HttpPost]
            [Route("{application}/{envName}/date/{offset}")]
            [ResponseType(typeof(DateInfo))]
            public async Task<IHttpActionResult> SetDateOffsetForEnvironmentName(string application, string envName, string offset)
            {
            }