From 2d75cbb43ca56876b8977d46e623c9fc1f73b53e Mon Sep 17 00:00:00 2001 From: Tomas Fabian Date: Sat, 3 Feb 2024 13:44:34 +0100 Subject: [PATCH] [Joker.OData] - OData 8.x migration --- .../Controllers/ODataControllerBase.cs | 44 ++++++++++--------- .../Controllers/ReadOnlyODataController.cs | 26 ++++------- .../KeylessEntityRoutingConvention.cs | 2 - Joker.OData/Startup/ODataStartup.cs | 19 -------- Joker.OData/Startup/ODataStartupBase.cs | 15 ++----- Joker.OData/Startup/ODataStartupSettings.cs | 9 ---- 6 files changed, 35 insertions(+), 80 deletions(-) diff --git a/Joker.OData/Controllers/ODataControllerBase.cs b/Joker.OData/Controllers/ODataControllerBase.cs index 54d0faaa..70fe947e 100644 --- a/Joker.OData/Controllers/ODataControllerBase.cs +++ b/Joker.OData/Controllers/ODataControllerBase.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.OData; using Microsoft.AspNetCore.OData.Deltas; using Microsoft.AspNetCore.OData.Extensions; +using Microsoft.OData.UriParser; namespace Joker.OData.Controllers { @@ -34,7 +35,7 @@ protected ODataControllerBase(IRepository repository) #region Post - public async Task Post([FromBody]TEntity entity) + public async Task Post([FromBody] TEntity entity) { var validationResult = await ValidatePostAsync(entity); @@ -45,7 +46,7 @@ public async Task Post([FromBody]TEntity entity) if (actionResult != null) return actionResult; - + return Created(entity); } @@ -71,14 +72,14 @@ protected virtual async Task OnPostAsync(TEntity entity) public async Task Patch(object key, Delta delta) { var keys = GetKeysFromPath(); - + var entityToUpdate = repository.GetAll().FirstOrDefault(CreateKeysPredicate(keys)); if (entityToUpdate == null) return NotFound(); delta.Patch(entityToUpdate); - + var validationResult = await ValidatePatchAsync(delta, entityToUpdate); if (validationResult != null) @@ -91,7 +92,7 @@ public async Task Patch(object key, Delta delta) return Updated(entityToUpdate); } - + protected virtual async Task OnPatchAsync(Delta delta, TEntity patchedEntity) { repository.Update(patchedEntity); @@ -111,7 +112,7 @@ protected virtual Task ValidatePatchAsync(Delta delta, T #region Put [HttpPut] - public async Task Put(object key, [FromBody]TEntity entity) + public async Task Put(object key, [FromBody] TEntity entity) { var validationResult = await ValidatePutAsync(entity); @@ -119,7 +120,7 @@ public async Task Put(object key, [FromBody]TEntity entity) return validationResult; var actionResult = await OnPutAsync(entity); - + if (actionResult != null) return actionResult; @@ -153,7 +154,7 @@ public async Task Delete(object key, ODataOptions oDataOptions) public async Task Delete() { var keys = GetKeysFromPath(); - + var validationResult = await ValidateDeleteAsync(keys); if (validationResult != null) @@ -168,7 +169,7 @@ public async Task Delete() } protected virtual async Task OnDeleteAsync(params object[] keys) - { + { repository.Remove(keys); await repository.SaveChangesAsync(); @@ -191,11 +192,11 @@ protected virtual dynamic TryGetDbSet(Type entityType) } #endregion - + #region CreateRef - + [AcceptVerbs("POST", "PUT")] - public async Task CreateRef(string navigationProperty, [FromBody] Uri link) + public async Task CreateRef(object key, string navigationProperty, [FromBody] Uri link) { return await OnCreateRef(navigationProperty, link); } @@ -209,16 +210,17 @@ protected virtual async Task OnCreateRef(string navigationPropert if (entity == null) return NotFound($"{nameof(TEntity)}: {keys}"); - var odataPath = Request.ODataFeature().Path; + var edmModel = Request.GetModel(); + + var baseAddress = Request.ODataFeature().BaseAddress; + var oDataUriParser = new ODataUriParser(edmModel, new Uri(baseAddress), link); + var odataPath = oDataUriParser.ParsePath(); var relatedObjectKeys = GetKeysFromPath(odataPath); var type = typeof(TEntity).GetProperty(navigationProperty).PropertyType; - var navigationPropertyType = type.GetCollectionGenericType(); - - if (navigationPropertyType == null) - navigationPropertyType = type; + var navigationPropertyType = type.GetCollectionGenericType() ?? type; dynamic relatedRepository = TryGetDbSet(navigationPropertyType); dynamic relatedEntity = relatedRepository.Find(relatedObjectKeys); @@ -234,7 +236,7 @@ protected virtual async Task OnCreateRef(string navigationPropert await repository.SaveChangesAsync(); - return StatusCode((int) HttpStatusCode.NoContent); + return StatusCode((int)HttpStatusCode.NoContent); } #endregion @@ -248,14 +250,14 @@ public async Task DeleteRef(object key, string navigationProperty } protected virtual async Task OnDeleteRef(string navigationProperty) - { + { var keys = GetKeysFromPath(); var keyPredicate = CreateKeysPredicate(keys); var entity = repository.GetAllIncluding(navigationProperty).Where(keyPredicate).FirstOrDefault(); if (entity == null) return NotFound($"{nameof(TEntity)}: {keys}"); - + var type = typeof(TEntity).GetProperty(navigationProperty).PropertyType; var navigationPropertyType = type.GetCollectionGenericType(); @@ -265,7 +267,7 @@ protected virtual async Task OnDeleteRef(string navigationPropert if (typeof(ICollection).IsAssignableFrom(type)) { - var relatedObjectKeys = GetAllKeysFromPath().Last().Select(c => c.Value).ToArray(); + var relatedObjectKeys = GetAllKeysFromPath(); dynamic relatedRepository = TryGetDbSet(navigationPropertyType); dynamic relatedEntity = relatedRepository.Find(relatedObjectKeys); diff --git a/Joker.OData/Controllers/ReadOnlyODataController.cs b/Joker.OData/Controllers/ReadOnlyODataController.cs index a7afd071..9f19198a 100644 --- a/Joker.OData/Controllers/ReadOnlyODataController.cs +++ b/Joker.OData/Controllers/ReadOnlyODataController.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.OData.Query.Validator; using Microsoft.AspNetCore.OData.Results; using Microsoft.AspNetCore.OData.Routing.Controllers; +using Microsoft.OData.Edm; using Microsoft.OData.UriParser; namespace Joker.OData.Controllers @@ -86,13 +87,6 @@ protected virtual Expression> CreateKeysPredicate(params obj #endregion - private bool HasKeyInODataPath() - { - var odataPath = Request.ODataFeature().Path; - - return odataPath.OfType().Any(); - } - #region GetKeysFromPath protected object[] GetKeysFromPath() @@ -115,17 +109,15 @@ protected object[] GetKeysFromPath(ODataPath odataPath) return value; } - protected IEnumerable>> GetAllKeysFromPath() + protected object[] GetAllKeysFromPath() { - var odataPath = Request.ODataFeature().Path; - - var keySegment = odataPath.OfType(); - if (keySegment == null) - throw new InvalidOperationException("The link does not contain a key."); - - var keys = keySegment.Select(c => c.Keys); - - return keys; + var link = Request.Query["$id"]; + var oDataFeature = Request.ODataFeature(); + var uriBuilder = new UriBuilder(Request.Scheme, Request.Host.Host, Request.Host.Port ?? -1); //TODO: get relativeUri differently + var baseAddress = uriBuilder.Uri + oDataFeature.RoutePrefix; + var oDataUriParser = new ODataUriParser(Request.GetModel(), new Uri(baseAddress), new Uri(link)); + var odataPath = oDataUriParser.ParsePath(); + return GetKeysFromPath(odataPath); } #endregion diff --git a/Joker.OData/Routing/Conventions/KeylessEntityRoutingConvention.cs b/Joker.OData/Routing/Conventions/KeylessEntityRoutingConvention.cs index 1b4292f0..d300cf13 100644 --- a/Joker.OData/Routing/Conventions/KeylessEntityRoutingConvention.cs +++ b/Joker.OData/Routing/Conventions/KeylessEntityRoutingConvention.cs @@ -1,11 +1,9 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.OData.Routing.Conventions; using Microsoft.OData.Edm; -using Microsoft.OData.ModelBuilder; namespace Joker.OData.Routing.Conventions { diff --git a/Joker.OData/Startup/ODataStartup.cs b/Joker.OData/Startup/ODataStartup.cs index ac459456..66677364 100644 --- a/Joker.OData/Startup/ODataStartup.cs +++ b/Joker.OData/Startup/ODataStartup.cs @@ -1,5 +1,4 @@ using System; -using System.Text.Json.Serialization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.OData; @@ -93,24 +92,6 @@ protected override void OnRegisterMiddleWares(IApplicationBuilder app) protected override void OnConfigureOData(IApplicationBuilder app) { - // app.UseEndpoints(endpoints => - // { - // endpoints.EnableDependencyInjection(); - // - // endpoints.Select().Expand().Filter().OrderBy().MaxTop(null).Count(); - - // var edmModel = app.ApplicationServices.GetService() ?? EdmModel; - - // if (ODataStartupSettings.EnableODataBatchHandler) - // { - // endpoints.EnableContinueOnErrorHeader(); - - // endpoints.MapODataRoute(ODataStartupSettings.ODataRouteName, ODataStartupSettings.ODataRoutePrefix, edmModel, - // CreateODataBatchHandler()); - // } - // else - // endpoints.MapODataRoute(ODataStartupSettings.ODataRouteName, ODataStartupSettings.ODataRoutePrefix, edmModel); - // }); } #endregion diff --git a/Joker.OData/Startup/ODataStartupBase.cs b/Joker.OData/Startup/ODataStartupBase.cs index d5414fe0..b5507633 100644 --- a/Joker.OData/Startup/ODataStartupBase.cs +++ b/Joker.OData/Startup/ODataStartupBase.cs @@ -10,20 +10,11 @@ using Microsoft.AspNetCore.OData; namespace Joker.OData.Startup { - public abstract class ODataStartupBase : StartupBase + public abstract class ODataStartupBase(IWebHostEnvironment env) : StartupBase(env) { #region Fields - internal readonly ODataStartupSettings ODataStartupSettings = new ODataStartupSettings(); - - #endregion - - #region Constructors - - protected ODataStartupBase(IWebHostEnvironment env) - : base(env) - { - } + internal readonly ODataStartupSettings ODataStartupSettings = new(); #endregion @@ -31,7 +22,7 @@ protected ODataStartupBase(IWebHostEnvironment env) private IEdmModel edmModel; - public IEdmModel EdmModel => edmModel ?? (edmModel = CreateEdmModel()); + public IEdmModel EdmModel => edmModel ??= CreateEdmModel(); #endregion diff --git a/Joker.OData/Startup/ODataStartupSettings.cs b/Joker.OData/Startup/ODataStartupSettings.cs index 6c201cbe..a20b85fc 100644 --- a/Joker.OData/Startup/ODataStartupSettings.cs +++ b/Joker.OData/Startup/ODataStartupSettings.cs @@ -4,8 +4,6 @@ public class ODataStartupSettings { public bool EnableODataBatchHandler { get; private set; } = true; - // public string ODataRouteName { get; private set; } = "odata"; - public string ODataRoutePrefix { get; private set; } = "odata"; public ODataStartupSettings DisableODataBatchHandler() @@ -15,13 +13,6 @@ public ODataStartupSettings DisableODataBatchHandler() return this; } - // public ODataStartupSettings SetODataRouteName(string value) - // { - // ODataRouteName = value; - // - // return this; - // } - public ODataStartupSettings SetODataRoutePrefix(string value) { ODataRoutePrefix = value;