web-dev-qa-db-ja.com

ASP.NET Web API実装で配列をOData関数に渡す方法は?

OData V4の仕様では、可能でなければならないと規定されています: https://issues.oasis-open.org/browse/ODATA-636

「複雑な型と配列は、パラメーターエイリアスを介してのみ関数に渡すことができます」

ODataパラメータエイリアスを使用して配列を渡そうとすると、例外が発生します。

/TestEntities/NS.TestFunction(ArrayHere=@p)?@p=[1,2,3]

結果:

タイプ 'EdmValidCoreModelPrimitiveType'のオブジェクトをタイプ 'Microsoft.OData.Edm.IEdmStructuredTypeにキャストできません

興味深いのは、メタデータドキュメントがこのような場合に正しく構成されていることです。

<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関数に渡すことは可能ですか?

更新:

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)
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])

注意として、複合型の配列も受け入れることができます。配列のjsonをURLエンコードし、パラメーターエイリアスを使用する必要があるため、次のようになります...

_ 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(ArrayHere=@ArrayData)?@ArrayData=%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

16
MHollis

現在使用している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で試してみませんでした。これがお役に立てば幸いです

8