如何将多个参数传递给Odata 4动作(Web Api 2.2项目的一部分)

时间:2017-03-10 18:55:23

标签: asp.net asp.net-mvc asp.net-web-api asp.net-web-api2 odata

我正在尝试使用odata-4(在web api 2.2项目中)创建一个odata api端点,我需要在odata控制器中使用我的一个GET动作来接受多个字符串参数(它们是自定义搜索属性,除了我的实体中为其创建odata控制器的属性)。

但是到目前为止我所做的所有试验中,在访问浏览器中的特定操作时,我总是遇到一个或其他错误。 到目前为止,我还没有能够获得流/语法的工作组合,因此在这里共享查询以获得关于如何在odata-4中实现将多个参数传递给odata动作的建议 OR 如何修复了错误。

代码如下:

package.config:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.Mvc" version="5.1.2" targetFramework="net45" />
  <package id="Microsoft.AspNet.OData" version="5.3.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="3.1.2" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.OData" version="5.1.2" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="3.1.2" targetFramework="net45" />
  <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net45" />
  <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net45" />
  <package id="Microsoft.OData.Core" version="6.5.0" targetFramework="net45" />
  <package id="Microsoft.OData.Edm" version="6.5.0" targetFramework="net45" />
</packages>

WebApiConfig:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            ODataModelBuilder builder = new ODataConventionModelBuilder();

            builder.EntitySet<DocumentsModel>("SampleData");

            var function = builder.Function("SampleFunction");
            function.Parameter<string>("catGUIDOrText");
            function.Parameter<string>("type");
            function.Parameter<string>("isAutoCompSearch");
            function.ReturnsCollectionFromEntitySet<DocumentsModel>("SampleData");

            config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

Odata控制器:

[ODataRoutePrefix("SampleData")]
    public class SampleDataController : ODataController
    {
        [EnableQuery]
        [HttpGet]
        [ODataRoute("SampleFunction(catGUIDOrText={catGUIDOrText},type={type},isAutoCompSearch={isAutoCompSearch})")]
        public IEnumerable<DocumentsModel> GetSampleData([FromODataUri] string catGUIDOrText, [FromODataUri] string type, [FromODataUri] string isAutoCompSearch)
        {
            return new List<DocumentsModel>().AsQueryable<DocumentsModel>();
        }
    }

注意: - DocumentsModel是一个包含所有字符串属性的类。

  

错误详情

现在,当通过以下网址在浏览器中访问此操作时,我收到错误:

URL: http://localhost/VirtualDirectoryNameInIIS/odata/SampleData/SampleFunction(catGUIDOrText= '752',类型= '230',isAutoCompSearch = '假')

我得到的错误:

  

路径模板   '的sampleData / SampleFunction(catGUIDOrText = {catGUIDOrText},类型= {}类型,isAutoCompSearch = {isAutoCompSearch})'   在控件'SampleData'中的'GetSampleData'动作不是   有效的OData路径模板。请求URI无效。自从   segment'SampleData'指的是一个集合,这必须是最后一个集合   请求URI中的段,或者必须后跟函数或   可以绑定到它的动作,否则所有中间段   必须引用单一资源。

请帮助我解决您可能遇到的任何输入,无论是代码还是我用来访问给定方法的网址。感谢。

我遵循的一些参考资料用于解决此问题或确保我遵循正确的方向/语法:

  1. Web API and OData- Pass Multiple Parameters

  2. https://damienbod.com/2014/06/13/web-api-and-odata-v4-queries-functions-and-attribute-routing-part-2/

3 个答案:

答案 0 :(得分:4)

编辑添加显式名称空间的WebApiConfig.cs

        builder.Namespace = "MyNamespace";
  • 如果你没有明确它,默认命名空间是“默认”:)

编辑WebApiConfig.cs,更改功能声明

        FunctionConfiguration function = builder.EntityType<DocumentsModel>().Collection.Function("SampleFunction");
        function.Parameter<string>("catGUIDOrText");
        function.Parameter<string>("type");
        function.Parameter<string>("isAutoCompSearch");
        function.ReturnsCollectionFromEntitySet<DocumentsModel>("SampleData");
  • 使用“.EntityType()”,您将目标指向实体DocumentsModel的控制器,您已将其命名为“SampleData”
  • 以“.Collection”为目标实体的集合;否则,如果省略,则定位单个实体

更改Odata控制器

//[ODataRoutePrefix("SampleData")]
public class SampleDataController : ODataController
{
    //[ODataRoute("SampleData/MyNamespace.SampleFunction(catGUIDOrText={catGUIDOrText},type={type},isAutoCompSearch={isAutoCompSearch})")]
    [EnableQuery]
    [HttpGet]
    public IHttpActionResult SampleFunction(string catGUIDOrText, string type, string isAutoCompSearch)
    {
        return new List<DocumentsModel>().AsQueryable<DocumentsModel>();
    }
}
  • 您可以发表评论[ODataRoutePrefix(“SampleData”)]:命名约定的路由是 entitySetName Controller,您可以使用“builder.EntitySet(”SampleData“)”
  • 返回类型不能是IEnumerable;如果你使用IHttpActionResult,你将永远不会有问题。
  • 如果使用命名约定,则可以评论ODataRoute

更改添加odata名称空间的网址

http://localhost/VirtualDirectoryNameInIIS/odata/SampleData/MyNamespace.SampleFunction(catGUIDOrText='752',type='230',isAutoCompSearch='false')

在您的代码中,您声明了一个未绑定函数,但您调用的是绑定函数

您可以在此tutorial

中找到所需的信息

答案 1 :(得分:0)

我正在尝试实现类似的目的,但是我直接使用ODataQueryOptions,所以我的控制器是这样的:

[HttpGet]
public ODataList<DTO> Get(ODataQueryOptions<POCO> options) {
    using (var db = new Entities()) {
        var param = options.Request.RequestUri.ParseQueryString().Get("CompanyCode");
        return _oData.Query<POCO, DTO>(options, db.POCO.AsQueryable());
    }
}

如果我尝试在签名中添加其他参数,则会出错,因此试图寻找一种方法来传递CompanyCode和所有OData参数,并且仍然具有所有分页/过滤/排序功能。

这对我来说就像是一种魅力-我只是在请求中添加额外的参数,例如:

api / DTO?CompanyCode = blah&$ skip = 50&$ top = 50

.NET OData东西似乎忽略了我的额外参数,并且没有问题-我只是手动解析该参数,而不是将其放入函数签名中。对我来说足够好!

答案 2 :(得分:0)

我可以通过以下方式解决此问题:-

  1. 将以下代码添加到startup.cs

    gapi.load('gapi.iframes', function() {
       var options = {
         'url': 'https://play.google.com/work/embedded/search?token=web_token&mode=SELECT',
         'where': document.getElementById('container'),
         'attributes': { style: 'width: 600px; height:1000px', scrolling: 'yes'}
       }
    
       var iframe = gapi.iframes.getContext().openChild(options);
    });
    
  2. 在控制器中

    public void ConfigureServices(IServiceCollection services)
     {
        // your code
       services.AddMvc();
       services.AddOData();
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
     {
      // your code
      app.UseRouting();
       app.UseEndpoints(endpoints =>
        {
    
    endpoints.Select().Filter().OrderBy().Expand().Count().MaxTop(50);
            endpoints.MapODataRoute("api", "api", GetEdmModel());
        });
    }
    
    private IEdmModel GetEdmModel()
    {
        var edmBuilder = new ODataConventionModelBuilder();
        edmBuilder.EntitySet<Student>("Students");  
    
        var pullRequestsByProjectByContributor = edmBuilder.EntityType<Student>().Collection
    .Function("GetStudents")
    .ReturnsCollectionFromEntitySet<Student>("Students");
        pullRequestsByProjectByContributor.Parameter<int>("id").Required();
        pullRequestsByProjectByContributor.Parameter<int>("classId").Required();
    
    
        return edmBuilder.GetEdmModel();
    }