Compare commits
8 Commits
ba94f4689a
...
ab4d8646d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab4d8646d1 | ||
|
|
9f649a11f2 | ||
|
|
9bd377de80 | ||
|
|
52d350ae48 | ||
|
|
f128a719e8 | ||
|
|
c09ff44287 | ||
|
|
d84ef820f1 | ||
|
|
8d38e883df |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace DigitalData.Core.Client
|
||||
{
|
||||
public enum Method
|
||||
{
|
||||
GET
|
||||
}
|
||||
}
|
||||
21
DigitalData.Core.Client/ServiceFactory.cs
Normal file
21
DigitalData.Core.Client/ServiceFactory.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
20db819e4979be9dc844efcd6f693dcb34c96eb5d3cf949e5e5683b5681e6999
|
||||
Binary file not shown.
Binary file not shown.
35
DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs
Normal file
35
DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user