8 Commits

Author SHA1 Message Date
Developer 02
ab4d8646d1 Gitignore aktualisieren. 2024-06-27 13:53:13 +02:00
Developer 02
9f649a11f2 chore: Aktualisiere den Pfad für PackageIcon 2024-06-27 12:45:23 +02:00
Developer 02
9bd377de80 chore: Upgrade Abstractions and Client projects from 1.0.0 to 1.0.1 2024-06-27 12:39:18 +02:00
Developer 02
52d350ae48 Refactor: Make Build method private to ensure IServiceProvider is only created via Lazy initialization for thread safety and consistency. 2024-06-27 12:35:37 +02:00
Developer 02
f128a719e8 feat: Implement ServiceFactory for dependency injection
- Added ServiceFactory class to manage service registrations and service provider creation.
- Implemented a lazy-loaded IServiceProvider to ensure services are only built once.
- Prevent further modifications to the service collection after the service provider is created.
- Added Provide<T>() method to resolve and retrieve services from the service provider.
2024-06-27 12:29:31 +02:00
Developer 02
c09ff44287 Gitignore aktualisieren. 2024-06-27 09:18:30 +02:00
Developer 02
d84ef820f1 GetCookies-Methode hinzugefügt. Test für http-Dienst hinzugefügt 2024-06-26 16:57:30 +02:00
Developer 02
8d38e883df Die Klasse Method (Http) und unnötige Erweiterungen wurden entfernt. 2024-06-26 16:40:54 +02:00
17 changed files with 87 additions and 88 deletions

2
.gitignore vendored
View File

@@ -405,3 +405,5 @@ FodyWeavers.xsd
/DigitalData.Core.Infrastructure/obj
/DigitalData.Core.Application/obj/Release/net7.0/DigitalData.Core.Application.AssemblyInfo.cs
/DigitalData.Core.Application/obj/Release/net7.0/ref/DigitalData.Core.Application.dll
/DigitalData.Core.ConsoleApp/DigitalData.Core.ConsoleApp.csproj
/DigitalData.Core.ConsoleApp/Program.cs

View File

@@ -1,9 +1,13 @@
namespace DigitalData.Core.Abstractions.Client
using System.Net;
namespace DigitalData.Core.Abstractions.Client
{
public interface IBaseHttpClientService
{
public string Uri { get; init; }
public CookieCollection GetCookies(string route = "");
Task<HttpResponseMessage> FetchAsync(
string route = "",
HttpMethod? method = null,

View File

@@ -18,7 +18,7 @@
<PackAsTool>False</PackAsTool>
<NeutralLanguage>aa-DJ</NeutralLanguage>
<PackageIcon>Assets\icon.png</PackageIcon>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@ namespace DigitalData.Core.Client
public class BaseHttpClientService : IBaseHttpClientService
{
protected readonly HttpClient _client;
protected readonly CookieContainer _cookies;
protected readonly CookieContainer _cookies;
[StringSyntax("Uri")]
public string Uri { get; init; }
@@ -20,6 +20,8 @@ namespace DigitalData.Core.Client
Uri = clientOptions.Value.Uri;
}
public CookieCollection GetCookies(string route = "") => _cookies.GetCookies(uri: new Uri(Uri + route));
public async Task<HttpResponseMessage> FetchAsync(
string route = "",
HttpMethod? method = null,
@@ -42,7 +44,10 @@ namespace DigitalData.Core.Client
if (sendWithCookie)
{
var cookieHeader = _cookies.GetCookieHeader(requestUri);
requestMessage.Headers.Add("Cookie", cookieHeader);
if (!string.IsNullOrWhiteSpace(cookieHeader))
{
requestMessage.Headers.Add("Cookie", cookieHeader);
}
}
// Add body content if provided

View File

@@ -17,7 +17,7 @@ namespace DigitalData.Core.Client
return services;
}
public static IServiceCollection AddHttpClientService<TClientOptions>(this IServiceCollection services, Action<TClientOptions>? clientOptions = null, bool setAsDefault = false)
public static IServiceCollection AddHttpClientService<TClientOptions>(this IServiceCollection services, Action<TClientOptions>? clientOptions = null, bool setAsDefaultBase = false)
where TClientOptions : HttpClientOptions, new()
{
services.TryAddSingleton<HttpClient>();
@@ -25,7 +25,7 @@ namespace DigitalData.Core.Client
services.AddSingleton<IHttpClientService<TClientOptions>, HttpClientService<TClientOptions>>();
services.Configure(clientOptions ?? (_ => { }));
if (setAsDefault)
if (setAsDefaultBase)
services.AddSingleton<IBaseHttpClientService, HttpClientService<TClientOptions>>();
return services;

View File

@@ -6,18 +6,19 @@
<Nullable>enable</Nullable>
<Description>This package provides HTTP client extension methods for the DigitalData.Core library, offering simplified and asynchronous methods for fetching and handling HTTP responses. It includes utility methods for sending GET requests, reading response content as text or JSON, and deserializing JSON into dynamic or strongly-typed objects using Newtonsoft.Json. These extensions facilitate efficient and easy-to-read HTTP interactions in client applications.</Description>
<PackageId>DigitalData.Core.Client</PackageId>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
<Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company>
<Product>Digital Data GmbH</Product>
<Copyright>Copyright 2024</Copyright>
<PackageProjectUrl></PackageProjectUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageIcon>Assets\icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackageTags>digital data core http client json serilization</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

View File

@@ -8,22 +8,6 @@ namespace DigitalData.Core.Client
/// </summary>
public static class HttpExtensions
{
/// <summary>
/// Fetches data from the specified URL using the given HTTP method.
/// </summary>
/// <param name="url">The URL to fetch data from.</param>
/// <param name="method">The HTTP method to use for the request. Defaults to GET.</param>
/// <returns>A task representing the HTTP response message.</returns>
public static async Task<HttpResponseMessage> Fetch(this string url, Method method = Method.GET)
{
using HttpClient client = new();
return method switch
{
Method.GET => await client.GetAsync(url),
_ => throw new NotImplementedException(nameof(method)),
};
}
/// <summary>
/// Reads the content of the HTTP response message as a string.
/// </summary>
@@ -61,39 +45,6 @@ namespace DigitalData.Core.Client
return JsonConvert.DeserializeObject<dynamic>(json) ?? string.Empty;
}
/// <summary>
/// Fetches data from the specified URL using the given HTTP method and reads the response content as a string.
/// </summary>
/// <param name="url">The URL to fetch data from.</param>
/// <param name="method">The HTTP method to use for the request. Defaults to GET.</param>
/// <returns>A task representing the response content as a string.</returns>
public static async Task<string> FetchText(this string url, Method method = Method.GET) => await url.Fetch(method: method).ThenAsync(Text);
/// <summary>
/// Fetches data from the specified URL using the given HTTP method and deserializes the response content to a specified type.
/// </summary>
/// <typeparam name="T">The type to deserialize the response content to.</typeparam>
/// <param name="url">The URL to fetch data from.</param>
/// <param name="method">The HTTP method to use for the request. Defaults to GET.</param>
/// <returns>A task representing the deserialized response content.</returns>
public static async Task<T?> FetchJson<T>(this string url, Method method = Method.GET) => await url.Fetch(method: method).ThenAsync(Json<T>);
/// <summary>
/// Fetches data from the specified URL using the given HTTP method and deserializes the response content to a dynamic object.
/// </summary>
/// <param name="url">The URL to fetch data from.</param>
/// <param name="method">The HTTP method to use for the request. Defaults to GET.</param>
/// <returns>A task representing the deserialized response content as a dynamic object.</returns>
public static async Task<dynamic> FetchJson(this string url, Method method = Method.GET) => await url.Fetch(method: method).ThenAsync(Json);
/// <summary>
/// Fetches data from the specified URL using the given HTTP method and deserializes the response content to a list of dynamic objects.
/// </summary>
/// <param name="url">The URL to fetch data from.</param>
/// <param name="method">The HTTP method to use for the request. Defaults to GET.</param>
/// <returns>A task representing the deserialized response content as a list of dynamic objects.</returns>
public static async Task<IEnumerable<dynamic>> FetchJsonList(this string url, Method method = Method.GET) => await url.Fetch(method: method).ThenAsync(JsonList);
/// <summary>
/// Executes an action when a task is completed.
/// </summary>

View File

@@ -1,7 +0,0 @@
namespace DigitalData.Core.Client
{
public enum Method
{
GET
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Client
{
public static class ServiceFactory
{
private static readonly IServiceCollection _services = new ServiceCollection();
private static readonly Lazy<IServiceProvider> _lazyProvider = new(Build);
public static IServiceCollection Services => !_lazyProvider.IsValueCreated
? _services
: throw new InvalidOperationException(
"Service provider has already been created. " +
"Further modifications to the service collection are not allowed. " +
"This is to ensure that the dependency injection container remains in a consistent state.");
private static IServiceProvider Build() => _services.BuildServiceProvider();
public static T Provide<T>() where T : notnull => _lazyProvider.Value.GetRequiredService<T>();
}
}

View File

@@ -1,22 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("DigitalData.Core.CultureServices")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+82da3586a5e28ae5fbd4242f05f60f9e5327e5f2")]
[assembly: System.Reflection.AssemblyProductAttribute("DigitalData.Core.CultureServices")]
[assembly: System.Reflection.AssemblyTitleAttribute("DigitalData.Core.CultureServices")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.

View File

@@ -1 +0,0 @@
20db819e4979be9dc844efcd6f693dcb34c96eb5d3cf949e5e5683b5681e6999

View File

@@ -0,0 +1,35 @@
using DigitalData.Core.Abstractions.Client;
using DigitalData.Core.Client;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.Core.Tests
{
[TestFixture]
public class BaseHttpClientServiceTests
{
private IServiceProvider _serviceProvider;
private IBaseHttpClientService _service;
[SetUp]
public void SetUp()
{
_serviceProvider = new ServiceCollection()
.AddHttpClientService("https://jsonplaceholder.typicode.com/todos")
.BuildServiceProvider();
_service = _serviceProvider.GetRequiredService<IBaseHttpClientService>();
}
[Test]
public async Task FetchJsonAsync_ShouldReturnJsonResponse()
{
// Act
var expectedUserId = (int) await _service.FetchAsync("/1", sendWithCookie: false, saveCookie: false)
.ThenAsync(res => res.Json())
.ThenAsync(todo => todo.userId);
// Assert
Assert.That(expectedUserId, Is.EqualTo(1), "The userId of the fetched JSON object should be 1.");
}
}
}

View File

@@ -20,8 +20,12 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DigitalData.Core.Abstractions\DigitalData.Core.Abstractions.csproj" />
<ProjectReference Include="..\DigitalData.Core.API\DigitalData.Core.API.csproj" />
<ProjectReference Include="..\DigitalData.Core.Application\DigitalData.Core.Application.csproj" />
<ProjectReference Include="..\DigitalData.Core.Client\DigitalData.Core.Client.csproj" />
<ProjectReference Include="..\DigitalData.Core.DTO\DigitalData.Core.DTO.csproj" />
<ProjectReference Include="..\DigitalData.Core.Infrastructure\DigitalData.Core.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@@ -19,9 +19,9 @@
<Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost\17.3.2\build\netcoreapp2.1\Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost\17.3.2\build\netcoreapp2.1\Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.3.2\build\netstandard1.0\Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.3.2\build\netstandard1.0\Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.3.2\build\netcoreapp2.1\Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.3.2\build\netcoreapp2.1\Microsoft.NET.Test.Sdk.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\7.0.16\buildTransitive\net6.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\7.0.16\buildTransitive\net6.0\Microsoft.EntityFrameworkCore.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgNUnit_Analyzers Condition=" '$(PkgNUnit_Analyzers)' == '' ">C:\Users\tekh\.nuget\packages\nunit.analyzers\3.5.0</PkgNUnit_Analyzers>
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\tekh\.nuget\packages\newtonsoft.json\9.0.1</PkgNewtonsoft_Json>
</PropertyGroup>
</Project>

View File

@@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Client", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalData.Core.Abstractions", "DigitalData.Core.Abstractions\DigitalData.Core.Abstractions.csproj", "{13E40DF1-6123-4838-9BF8-086C94E6ADF6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigitalData.Core.ConsoleApp", "DigitalData.Core.ConsoleApp\DigitalData.Core.ConsoleApp.csproj", "{344EEF74-83DD-480A-A1A4-F62E0E3F2102}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -50,6 +52,10 @@ Global
{13E40DF1-6123-4838-9BF8-086C94E6ADF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13E40DF1-6123-4838-9BF8-086C94E6ADF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13E40DF1-6123-4838-9BF8-086C94E6ADF6}.Release|Any CPU.Build.0 = Release|Any CPU
{344EEF74-83DD-480A-A1A4-F62E0E3F2102}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{344EEF74-83DD-480A-A1A4-F62E0E3F2102}.Debug|Any CPU.Build.0 = Debug|Any CPU
{344EEF74-83DD-480A-A1A4-F62E0E3F2102}.Release|Any CPU.ActiveCfg = Release|Any CPU
{344EEF74-83DD-480A-A1A4-F62E0E3F2102}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE