代码之家  ›  专栏  ›  技术社区  ›  Simon

强制将odata格式设置为第二个API终结点

  •  0
  • Simon  · 技术社区  · 3 年前

    问题:如何将odata装饰强制为标准的.net core5 WebAPI端点?

    细节: 我已经有一个控制器,我想添加一个新的Get()EndPoint。
    不,我不想创建一个新的控制器(我已经有很多控制器了)。

    FIRST端点是一个真实的odata端点,带有odata装饰/封装: 所以当我从Postman那里做一个GET()时,我会得到这样的结果:

    { "@odata.context":"ablba",
      "values":[{object},{object},{object}],
      "nextlink":...
       "count":3
    }
    

    在控制器中:

    [HttpGet]
    [EnableQuery()]
    public IQueryable<MyModel> Get()
    {
       return _Dbcontext.MyModels;
    }
    

    Odata将允许过滤和所有类似的东西,以及OdataDecoration。为了拥有完整的oData端点,我似乎被迫在startup.cs中添加实体/控制器绑定:

    private static IEdmModel GetEdmModel()
    { 
       var builder = new ODataConventionModelBuilder();
       builder.EntitySet<MyModel>("NameOfMycontrollers");
       return builder.GetEdmModel();
    }
    

    问题是,我想在同一个控制器中添加第二个端点。所以我创建了我的方法,标记为[HttpGet]和[Enablequery]。新端点将使用$select、$filter等。但不会在ODATA装饰中返回。

    所以它是这样返回的:

    [{object},{object},{object}]
    

    问题是,我现在有两个API端点的“风味”,第二个端点的灵活性较差(没有分页,没有计数)。

    我试着在odacconventionmodelbuilder中添加第二个端点,但我无法工作。

    此外,我真的很感激获得OdataConventionModelBuilder的RID,但这里的文章

    using webapi odata without using ODataConventionModelBuilder (不那么受欢迎),似乎指向了另一个方向。

    苏,就这样

    0 回复  |  直到 3 年前
        1
  •  0
  •   Métoule    3 年前

    可以有多个OData路由,而无需使用 [EnableQuery] 属性,但它有点复杂。

    首先,您需要注册您的路线:

    internal static IServiceCollection AddCustomizedODataRoute(this IServiceCollection services, string routeName, Func<IEdmModel> GetEdmModel)
    {
        services
            .AddMvc()
            .AddOData(opts =>
            {
                opts.AddRouteComponents(routeName, GetEdmModel(), builder =>
                {
                    // customize builder, e.g. custom URI resolver
                    // builder.AddSingleton<ODataUriResolver, CustomODataUriResolver>();
                });
    
                // odata operations allowed on the route
                opts.Filter();
                opts.OrderBy();
            });
    
        return services;
    }
    

    哪里 GetEdmModel 构建您的模型。它可以根据您的需要进行细化,并且仅针对特定的路线创建;其他路线将有自己的模型。

    services.AddCustomizedODataRoute("route1", () => 
    {
        // OData ignores all NotMapped property, so we need to add them manually
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<MyEntity>(nameof(MyEntity));
        return builder.GetEdmModel();
    });
    

    然后,您需要一种基于HTTP查询应用OData查询的方法:

    public static IQueryable<T> ApplyODataQuery<T>(this IQueryable<T> source, string oDataRouteName, HttpContext httpContext)
    {
        if (httpContext == null)
            return source;
    
        // oDataRouteName should match the name used during registration
        httpContext.ODataFeature().RoutePrefix = oDataRouteName;
    
        var container = httpContext.Request.CreateRouteServices(oDataRouteName);
        var model = (IEdmModel)container.GetService(typeof(IEdmModel));
    
        var queryContext = new ODataQueryContext(model, typeof(T), null);
        var queryOptions = new ODataQueryOptions(queryContext, httpContext.Request);
    
        return queryOptions
            .ApplyTo(source, new ODataQuerySettings
            {
                HandleNullPropagation = HandleNullPropagationOption.True
            })
            .Cast<T>();
    }
    

    最后,在控制器中:

    [HttpGet]
    public MyResponseType Get()
    {
      // note that this gives you more flexibility on the return type
      var models = _Dbcontext.MyEntitys.ApplyODataQuery("route1", HttpContext);
    
      // do whatever
      return new MyResponseType();
    }