2017-07-03 2 views
4

Ich habe ein Web-API-Projekt, das seit mehreren Jahren ohne OData-Unterstützung verwendet wird, nur mit Standard-URL-Parametern.Unterstützung von ODataQueryOptions in bestehenden Web-API

Ich möchte nun OData-Unterstützung zu dieser API hinzufügen, aber da die API nicht auf einem abfragbaren Modell aufgebaut ist, ist die Absicht, das ODataQueryOptions<T>-Objekt zu empfangen und an ein Repository weiterzuleiten.

Alles, was ich über die Unterstützung von OData lesen kann, setzt entweder voraus, dass ich ein abfragbares Modell habe, oder es ist zu einfach und sagt mir einfach, wie ich das Objekt ODataQueryOptions verstehen kann. Folglich kann ich keine einfache Methode zum Laufen bringen.

Hier ist, was ich derzeit habe.

[Route("test")] 
[HttpGet] 
[EnableQuery] 
public IHttpActionResult Test(ODataQueryOptions<TestOptions> options) 
{ 
    var settings = new ODataValidationSettings { 
      AllowedFunctions = AllowedFunctions.None, 
      AllowedLogicalOperators = AllowedLogicalOperators.Equal, 
      AllowedArithmeticOperators = AllowedArithmeticOperators.None, 
      AllowedQueryOptions = AllowedQueryOptions.Filter 
     }; 
    try 
    { 
     options.Validate(settings); 
    } 
    catch (ODataException exception) 
    { 
     return BadRequest(exception.Message); 
    } 

    var binaryOperator = options.Filter?.FilterClause?.Expression as BinaryOperatorNode; 
    if (binaryOperator != null) 
    { 
     var property = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode; 
     var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode; 

     if (property?.Property != null && constant?.Value != null) 
     { 
      ; 
     } 
    } 

    return Ok(); 
} 

Die TestOptions-Klasse (im ODataQueryOptions<TestOptions> param) ist derzeit eine leere Klasse:

public class TestOptions 
{ 
} 

ich auch

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // existing code 

     config.AddODataQueryFilter(); 
    } 
} 

jedoch hinzugefügt haben, auf diese von einer REST-API-Aufruf Klient ...

{
"Nachricht": "Ein Fehler ist aufgetreten.",
"ExceptionMessage": "Keine nicht OData HTTP-Route registriert.“,
"Exception": "System.InvalidOperationException",
"Stacktrace": "..."
}

Was habe ich verpasst Ich hätte gedacht, dass ich vielleicht registrieren? OData-fähige Methoden in den global.asax oder ähnlich, aber die Ausnahme bedeutet, dass das Problem mit nicht-OData Methoden ist, aber alle anderen Methoden geben nach wie vor als erwartet (dh ohne OData Beteiligung).

+0

Ich denke, dass die Fehlermeldung hier etwas irreführend ist und dass Sie die OData-Route registrieren müssen. Befolgen Sie die Anweisungen hier sollten Sie beginnen: https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an -odata-v4-endpoint – TomDoesCode

+0

Dieses Beispiel basiert auf einem EF-Modell und wie ich im OP sagte, habe ich kein zugrunde liegendes Modell. Im Beispiel wird der OData-Endpunkt mit bestimmten Details seines Modells registriert: https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-a-odata-v4-Endpunkt # configure-the-odata-Endpunkt – awj

+0

OK, Sie müssen dennoch ein Modell erstellen, auch wenn es nicht über das Entity-Framework erfolgt. Wird Ihr Modell zur Kompilierzeit definiert? Werden sich die Typen und Eigenschaften, die ausgesetzt sind, ändern? – TomDoesCode

Antwort

3

Eigentlich funktioniert das perfekt ohne EntityDate oder andere Modelleinstellungen. Sie brauchen nur eine List<Poco.Language>, die Sie mit .AsQueryable() konvertieren können und los geht's.

[Route(""), HttpGet] 
public IHttpActionResult Get(ODataQueryOptions<Poco.Language> queryOptions) 
{   
    return Ok(queryOptions.ApplyTo(_repository.GetAll().AsQueryable())); 
} 

Above-Controller kann mit allen Arten von OData Abfrageoptionen, normale Routen und ohne Setup im WebApiConfig aufgerufen werden.

Poco.Language ist nur eine einfache C# -POCO-Klasse.

+1

Genau das, was ich gesucht habe! – awj

+0

Falls Sie das Problem immer noch haben, fügen Sie, abhängig von der OData-Bibliotheksversion, auch 'config.EnableDependencyInjection();' in Ihren Webapi-Konfigurationen hinzu. Siehe https://github.com/OData/WebApi/issues/816 – Chandermani

0

Hast du das zu deinem Startup hinzugefügt?

public void Configuration(IAppBuilder appBuilder) 
     { 
      // Set up server configuration 
      var config = new HttpConfiguration(); 
      config.Routes.MapODataRoute(routeName: "OData", routePrefix: "odata", model: GetEdmModel()); 
      appBuilder.UseWebApi(config); 
     } 

     private IEdmModel GetEdmModel() 
     { 
      var modelBuilder = new ODataConventionModelBuilder(); 
      modelBuilder.EntitySet<Customer>("customer"); 
      modelBuilder.EntitySet<Order>("order"); 
      modelBuilder.EntitySet<Customer>("response"); 
      return modelBuilder.GetEdmModel(); 
     } 

Ich versuche, das gleiche zu tun, was Sie sind, aber mit einem .Net Core Web Api. Ich habe die Beispiele von https://github.com/OData/ODataSamples heruntergeladen und er hat ein Arbeitsprojekt, das genau das tut, was wir zu tun versuchen. Sehen Sie sich ODataQueryableSample.csproj an. Es verwendet auch nicht EntityFramework, erstellt nur eine Liste im Speicher.

Auch glaube ich nicht, dass Sie sowohl das [EnableQuery] -Attribut und ODataQueryOptions-Parameter benötigen - das Beispiel gibt ein Beispiel für beide und verwendet sie nicht zusammen.

Ich habe das nicht funktioniert mit meinem Projekt, aber ich habe gesehen, es funktioniert auf meinem PC, so glaube ich, es ist nur eine Konfiguration (zum Beispiel verwendet mein Startup IApplicationBuilder statt IAppBuilder). Sie können auch versuchen, es von einem Browser aus zu treffen, um eine bessere Ausnahmebedingung zu erhalten.