-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #246 from Avanade/feature/structV8
feat(Liquid.Repository.Odata): Create Liquid.Repository.Odata cartridge
- Loading branch information
Showing
18 changed files
with
877 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# CI & CD workflow | ||
name: CI/CD - Liquid.Repository.OData Cartridge for Liquid Application Framework | ||
|
||
on: | ||
push: | ||
branches: [ main, releases/v2.X.X, releases/v6.X.X ] | ||
paths: | ||
- 'src/Liquid.Repository.OData/**' | ||
|
||
pull_request: | ||
branches: [ main, releases/** ] | ||
types: [opened, synchronize, reopened] | ||
paths: | ||
- 'src/Liquid.Repository.OData/**' | ||
|
||
# Allows you to run this workflow manually from the Actions tab | ||
workflow_dispatch: | ||
|
||
jobs: | ||
call-reusable-build-workflow: | ||
uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main | ||
with: | ||
component_name: Liquid.Repository.OData | ||
secrets: | ||
sonar_token: ${{ secrets.SONAR_TOKEN_ODATA }} | ||
nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/Liquid.Repository.OData/Extensions/ILiquidRepositoryExtension.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using Liquid.Core.Entities; | ||
using Liquid.Core.Interfaces; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Liquid.Repository.OData.Extensions | ||
{ | ||
/// <summary> | ||
/// Extension methods for <see cref="ILiquidRepository{TEntity, TIdentifier}"/>. | ||
/// </summary> | ||
public static class ILiquidRepositoryExtension | ||
{ | ||
/// <summary> | ||
/// Set the token to perform operations. | ||
/// </summary> | ||
/// <typeparam name="TEntity"></typeparam> | ||
/// <typeparam name="TIdentifier"></typeparam> | ||
/// <param name="repository"></param> | ||
/// <param name="token"></param> | ||
/// <returns></returns> | ||
public static ILiquidRepository<TEntity, TIdentifier> SetODataAuthenticationHeader<TEntity, TIdentifier>(this ILiquidRepository<TEntity, TIdentifier> repository, string token) where TEntity : LiquidEntity<TIdentifier>, new() | ||
{ | ||
var oDataRepository = repository as ODataRepository<TEntity, TIdentifier>; | ||
|
||
oDataRepository.SetToken(token); | ||
|
||
return repository; | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/Liquid.Repository.OData/Extensions/IServiceCollectionExtension.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using Liquid.Core.Entities; | ||
using Liquid.Core.Extensions.DependencyInjection; | ||
using Liquid.Core.Interfaces; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Liquid.Repository.OData.Extensions | ||
{ | ||
/// <summary> | ||
/// Extension methods for IServiceCollection. | ||
/// </summary> | ||
public static class IServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Registers a <see cref="ODataRepository{TEntity, TIdentifier}"/> for the entity <typeparamref name="TEntity"/>, | ||
/// and a <see cref="ODataClientFactory"/> if not previously registered. | ||
/// </summary> | ||
/// <typeparam name="TEntity">Type of entity that the repository should correspond to</typeparam> | ||
/// <typeparam name="TIdentifier">Entity identifier type.</typeparam> | ||
/// <param name="services">Extended ServiceCollection object.</param> | ||
/// <param name="sectionName">Name of the configuration section where all entities have their repository settings configured.</param> | ||
/// <param name="entityName">Name of the entity in the database that the repository should correspond to.</param> | ||
public static IServiceCollection AddLiquidOdataRepository<TEntity, TIdentifier>(this IServiceCollection services, string sectionName, string entityName) | ||
where TEntity : LiquidEntity<TIdentifier>, new() | ||
{ | ||
services.TryAddSingleton<IODataClientFactory, ODataClientFactory>(); | ||
|
||
services.AddOptions<ODataOptions>() | ||
.Configure<IConfiguration>((settings, configuration) => | ||
{ | ||
configuration.GetSection(sectionName).Bind(settings); | ||
}); | ||
|
||
services.AddScoped<ILiquidRepository<TEntity, TIdentifier>>((provider) => | ||
{ | ||
return ActivatorUtilities.CreateInstance<ODataRepository<TEntity, TIdentifier>>(provider, entityName); | ||
}); | ||
|
||
return services; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Simple.OData.Client; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Liquid.Repository.OData | ||
{ | ||
/// <summary> | ||
/// Defines an object with the ability to create an OData client. | ||
/// </summary> | ||
public interface IODataClientFactory | ||
{ | ||
/// <summary> | ||
/// Create an OData client. | ||
/// </summary> | ||
/// <param name="entityName">The entity name.</param> | ||
/// <param name="token">Authorization token.</param> | ||
IODataClient CreateODataClientAsync(string entityName, string token); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/Liquid.Repository.OData/Liquid.Repository.OData.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<PackageId>Liquid.Repository.OData</PackageId> | ||
<Nullable>enable</Nullable> | ||
<PackageLicenseExpression>MIT</PackageLicenseExpression> | ||
<Authors>Avanade Brazil</Authors> | ||
<Company>Avanade Inc.</Company> | ||
<Product>Liquid Application Framework</Product> | ||
<Copyright>Avanade 2019</Copyright> | ||
<PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl> | ||
<PackageIcon>logo.png</PackageIcon> | ||
<Version>8.0.0-beta-01</Version> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<IsPackable>true</IsPackable> | ||
<DebugType>Full</DebugType> | ||
<Description> | ||
Liquid Repository adapter for Odata apis. | ||
This component is part of Liquid Application Framework. | ||
</Description> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<None Include="..\..\logo.png" Link="logo.png"> | ||
<PackagePath></PackagePath> | ||
<Pack>True</Pack> | ||
</None> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Liquid.Core" Version="8.0.0-alpha-05" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" /> | ||
<PackageReference Include="Simple.OData.Client" Version="6.0.1" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using Microsoft.Extensions.Options; | ||
using Simple.OData.Client; | ||
|
||
namespace Liquid.Repository.OData | ||
{ | ||
///<inheritdoc/> | ||
public class ODataClientFactory : IODataClientFactory | ||
{ | ||
private readonly IOptions<ODataOptions> _options; | ||
|
||
/// <summary> | ||
/// Initialize a new instance of <see cref="ODataClientFactory"/> | ||
/// </summary> | ||
/// <param name="options"></param> | ||
public ODataClientFactory(IOptions<ODataOptions> options) | ||
{ | ||
_options = options ?? throw new ArgumentNullException(nameof(options)); | ||
} | ||
|
||
///<inheritdoc/> | ||
public IODataClient CreateODataClientAsync(string entityName, string token) | ||
{ | ||
var settings = _options?.Value?.Settings.FirstOrDefault(x => x.EntityName == entityName); | ||
|
||
if (settings == null) | ||
throw new ArgumentOutOfRangeException(nameof(entityName)); | ||
|
||
var client = new ODataClient(GetODataSettings(settings, token)); | ||
|
||
return client; | ||
} | ||
|
||
/// <summary> | ||
///Initialize a new instance of <see cref="ODataClientSettings"/> | ||
/// </summary> | ||
/// <param name="settings">OData settings.</param> | ||
/// <param name="token"> Authorization token.</param> | ||
/// <returns></returns> | ||
private static ODataClientSettings GetODataSettings(ODataSettings? settings, string token) | ||
{ | ||
var odataSettings = new ODataClientSettings(new Uri(settings.BaseUrl)); | ||
|
||
odataSettings.BeforeRequest = (message) => | ||
{ | ||
message.Headers.Add("Authorization", token); | ||
}; | ||
|
||
if (!settings.ValidateCert) | ||
{ | ||
var handler = new HttpClientHandler(); | ||
|
||
odataSettings.OnApplyClientHandler = (handler) => | ||
{ | ||
handler.ServerCertificateCustomValidationCallback += | ||
(sender, certificate, chain, errors) => | ||
{ | ||
return true; | ||
}; | ||
}; | ||
} | ||
|
||
return odataSettings; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using Liquid.Core.Entities; | ||
using Liquid.Core.Interfaces; | ||
using Simple.OData.Client; | ||
using System.Linq.Expressions; | ||
|
||
namespace Liquid.Repository.OData | ||
{ | ||
///<inheritdoc/> | ||
public class ODataRepository<TEntity, TIdentifier> : ILiquidRepository<TEntity, TIdentifier> where TEntity : LiquidEntity<TIdentifier>, new() | ||
{ | ||
///<inheritdoc/> | ||
public ILiquidDataContext DataContext => throw new NotImplementedException(); | ||
|
||
private readonly IODataClientFactory _clientFactory; | ||
private readonly string _entityName; | ||
private string _token; | ||
|
||
/// <summary> | ||
/// Initialize a new instance of <see cref="ODataRepository{TEntity, TIdentifier}"/> | ||
/// </summary> | ||
/// <param name="clientFactory"> Factory to create OData client.</param> | ||
/// <param name="entityName"> Name of the entity to be used in the repository.</param> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public ODataRepository(IODataClientFactory clientFactory, string entityName) | ||
{ | ||
_clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory)); | ||
_entityName = entityName ?? throw new ArgumentNullException(nameof(entityName)); | ||
} | ||
|
||
/// <summary> | ||
/// Set the token to perform operations. | ||
/// </summary> | ||
/// <param name="token">Token to be set.</param> | ||
public void SetToken(string token) | ||
{ | ||
_token = token; | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task AddAsync(TEntity entity) | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
Check warning on line 44 in src/Liquid.Repository.OData/ODataRepository.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
|
||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
await client.For<TEntity>().Set(entity).InsertEntryAsync(); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<IEnumerable<TEntity>> FindAllAsync() | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
} | ||
|
||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
return await client.For<TEntity>().FindEntriesAsync(); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<TEntity> FindByIdAsync(TIdentifier id) | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
} | ||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
return await client.For<TEntity>().Key(id).FindEntryAsync(); | ||
Check warning on line 74 in src/Liquid.Repository.OData/ODataRepository.cs GitHub Actions / call-reusable-build-workflow / build
Check warning on line 74 in src/Liquid.Repository.OData/ODataRepository.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
|
||
///<inheritdoc/> | ||
public async Task RemoveByIdAsync(TIdentifier id) | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
} | ||
|
||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
await client.For<TEntity>().Key(id).DeleteEntryAsync(); | ||
Check warning on line 87 in src/Liquid.Repository.OData/ODataRepository.cs GitHub Actions / call-reusable-build-workflow / build
Check warning on line 87 in src/Liquid.Repository.OData/ODataRepository.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
|
||
///<inheritdoc/> | ||
public async Task UpdateAsync(TEntity entity) | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
} | ||
|
||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
await client.For<TEntity>().Set(entity).UpdateEntryAsync(); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause) | ||
{ | ||
if (string.IsNullOrEmpty(_token)) | ||
{ | ||
throw new InvalidOperationException("Token is required to perform this operation."); | ||
} | ||
|
||
var client = _clientFactory.CreateODataClientAsync(_entityName, _token); | ||
|
||
return await client.For<TEntity>().Filter(whereClause).FindEntriesAsync(); | ||
} | ||
} | ||
} |
Oops, something went wrong.