2014-10-29 102 views
13

OData V4规范规定它必须是可能的: https://issues.oasis-open.org/browse/ODATA-636如何在ASP.NET Web API实现中将数组传递给OData函数?

“复杂类型和数组只能通过 参数别名被传递给函数”当我试图用的OData参数别名发生异常传递一个数组。

/TestEntities/NS.TestFunction([email protected])[email protected]=[1,2,3]

结果:

无法转换类型的对象“EdmValidCoreModelPrimitiveType”键入 “Microsoft.OData.Edm.IEdmStructuredType

有趣的是,元数据文件是正确的COM这种情况下提出:

<Function Name="TestFunction" IsBound="true"> 
    <Parameter Name="bindingParameter" Type="Collection(NS.TestEntity)"/> 
    <Parameter Name="ArrayHere" Type="System.Int32[]"/> 
    <ReturnType Type="Collection(NS.TestEntity)"/> 
</Function> 

是否有可能使用ASP.NET MVC Web API 2 OData将数组传递给查询字符串中的OData函数?

UPDATE:

这里是构建EDM模型和控制器的代码。

var builder = new ODataConventionModelBuilder(); 

builder.Namespace = "NS"; 

builder.EntitySet<TestEntity>("TestEntities"); 

builder.EntityType<TestEntity>().Collection 
    .Function("TestFunction") 
    .ReturnsCollectionFromEntitySet<TestEntity>("TestEntities") 
    .Parameter<int[]>("ArrayHere"); 

控制器:

public class TestEntitiesController : ODataController 
{ 
    public IEnumerable<TestEntity> TestFunction(int[] arrayHere) 
    { 
     throw new NotImplementedException(); 
    } 
} 

标记与[FromODataUri]参数不解决问题。

更新2:

这里是堆栈跟踪:

at Microsoft.OData.Core.UriParser.TypePromotionUtils.CanConvertTo(SingleValueNode sourceNodeOrNull, IEdmTypeReference sourceReference, IEdmTypeReference targetReference) 
at Microsoft.OData.Core.UriParser.Parsers.MetadataBindingUtils.ConvertToTypeIfNeeded(SingleValueNode source, IEdmTypeReference targetTypeReference) 
at Microsoft.OData.Core.UriParser.Parsers.FunctionCallBinder.BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection`1 segmentParameterTokens) 
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryBindingParametersAndMatchingOperation(String identifier, String parenthesisExpression, IEdmType bindingType, ODataUriParserConfiguration configuration, ICollection`1& boundParameters, IEdmOperation& matchingOperation) 
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryCreateSegmentForOperation(ODataPathSegment previousSegment, String identifier, String parenthesisExpression) 
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateNextSegment(String text) 
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection`1 segments) 
at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection`1 segments, ODataUriParserConfiguration configuration) 
at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePathImplementation() 
at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize() 
at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath, Boolean enableUriTemplateParsing) 
at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath) 
at System.Web.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection) 
at System.Web.Http.Routing.HttpRoute.ProcessConstraint(HttpRequestMessage request, Object constraint, String parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) 
at System.Web.Http.Routing.HttpRoute.ProcessConstraints(HttpRequestMessage request, HttpRouteValueDictionary values, HttpRouteDirection routeDirection) 
at System.Web.Http.Routing.HttpRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) 
at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext) 
+0

灿你张贴抛出异常的代码? – Pseudonym 2014-10-29 15:45:59

+0

有趣的问题,我真的很高兴看到你用来将函数添加到$元数据和函数实现的代码。 – gdoron 2014-10-29 19:32:16

+0

@gdoron,请参阅已更新的问题 – 2014-10-30 17:24:09

回答

8

我不知道你当前正在使用的OData的版本,但这里是我已经实现了一个解决方案,适用于V4和传递简单的数组到的OData Action方法

在你WebConfig.cs

ODataModelBuilder builder = new ODataConventionModelBuilder(); 
builder.EntitySet<TestEntity>("TestEntities"); 

builder.Namespace = "NS"; 

builder.EntityType<TestEntity>() 
     .Action("TestAction") 
    .CollectionParameter<string>("ArrayHere");  

在这里,你的控制器的方法

[HttpPost] 
public async Task<IHttpActionResult> TestAction([FromODataUri] int key, ODataActionParameters parameters) 
{ 
    // Do your thing here.. 
    var invites = parameters["ArrayHere"] as IEnumerable<string>; 
} 

产生的API端点请求看起来应该像下面这样:

POST http://localhost/odata/TestEntities(1)/NS.TestAction HTTP/1.1 
Content-type: application/json 
Host: localhost:49255 
Content-Length: 37 

{"ArrayHere":["hello", "world"]}  

我去了这方面的问题了几次,并不能使它为OData功能工作。我挖得更深一点,发现了一切方法的CollectionParameter<>()方法。我没有回去尝试用Function,因为我没有真正看到需要。我希望这可以帮助你

+1

感谢您的答案,但问题是关于传递数组到OData函数(作为查询字符串的一部分),而不是Action(作为请求有效载荷),也为我工作。 – 2015-01-22 07:53:38

14

假设你使用的是OData V4,你需要在注册函数时使用CollectionParameter,并且你在arrayHere参数上缺少[FromODataUri]。另外,请使用IEnumerable<int>而不是数组来尝试。

var builder = new ODataConventionModelBuilder(); 

builder.Namespace = "NS"; 

builder.EntitySet<TestEntity>("TestEntities"); 

builder.EntityType<TestEntity>().Collection 
    .Function("TestFunction") 
    .ReturnsCollectionFromEntitySet<TestEntity>("TestEntities") 
    .CollectionParameter<int>("ArrayHere"); 

有了这样的控制器功能...

[HttpGet] 
public async Task<IHttpActionResult> TestFunction([FromODataUri] IEnumerable<int> ArrayHere) 
{ 
    // Do stuff 
} 

现在你可以做出这样的请求......

http://yourRestService/API/TestEntities/NS.TestFunction(ArrayHere=[1,2,3])

作为一个说明,你也可以接受一系列复杂类型。你必须URL编码为阵列JSON和使用参数别名,所以你会像这样结束了......

builder.EntityType<TestEntity>().Collection 
    .Function("TestFunction2") 
    .ReturnsCollectionFromEntitySet<TestEntity>("TestEntities") 
    .CollectionParameter<person>("ArrayHere"); 

[HttpGet] 
public async Task<IHttpActionResult> TestFunction2([FromODataUri] IEnumerable<person> ArrayHere) 
{ 
    // Do stuff 
} 

http://yourRestService/API/TestEntities/NS.TestFunction2([email protected])[email protected]=%5B%7B%22FirstName%22%3A%22Bob%22%2C+%22LastName%22%3A%22Dole%22%7D%2C%7B%22FirstName%22%3A%22Bill%22%2C+%22LastName%22%3A%22Clinton%22%7D%5D

+0

太棒了! CollectionParameter!我试图使用参数()。我想澄清的是,这些参数的值包含在括号中的网址:NS.TestFunction9(IntArrayHere = [11,12,13,14,15]) – Jerther 2015-10-22 12:42:27

+0

嗯,我想知道为什么我得到了对此投票。有任何想法吗? – MHollis 2015-11-20 15:00:13

+0

太棒了... Upvote from .. – 2016-02-22 14:22:57