Skip to content

Commit 361af49

Browse files
committed
2 parents d07a00a + c5c51bb commit 361af49

File tree

4 files changed

+176
-7
lines changed

4 files changed

+176
-7
lines changed

ApiToolKit.cs

+31-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Newtonsoft.Json.Linq;
1010
using Newtonsoft.Json;
1111
using System.Diagnostics;
12+
using Microsoft.Extensions.DependencyInjection;
1213
using System.Text.Json;
1314
using static System.Web.HttpUtility;
1415

@@ -424,6 +425,31 @@ public class ATError
424425
public string StackTrace { get; set; }
425426
}
426427

428+
public interface IApiToolkitClientFactory
429+
{
430+
HttpClient CreateClient(ATOptions options);
431+
}
432+
433+
public class ApiToolkitClientFactory : IApiToolkitClientFactory
434+
{
435+
private readonly IHttpClientFactory _httpClientFactory;
436+
private readonly IServiceProvider _serviceProvider;
437+
438+
public ApiToolkitClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
439+
{
440+
_httpClientFactory = httpClientFactory;
441+
_serviceProvider = serviceProvider;
442+
}
443+
444+
public HttpClient CreateClient(ATOptions options)
445+
{
446+
var client = _httpClientFactory.CreateClient();
447+
448+
var handler = _serviceProvider.GetRequiredService<ObservingHandler>();
449+
handler.SetOptions(options);
450+
return new HttpClient(handler);
451+
}
452+
}
427453

428454
public class ATOptions
429455
{
@@ -436,9 +462,13 @@ public class ObservingHandler : DelegatingHandler
436462
{
437463
private readonly HttpContext _context;
438464
private readonly Func<Payload, Task> _publishMessageAsync;
439-
private readonly ATOptions _options;
465+
private ATOptions _options;
440466
private readonly string _project_id;
441467
private readonly string? _msg_id;
468+
public void SetOptions(ATOptions options)
469+
{
470+
_options = options;
471+
}
442472
public ObservingHandler(Func<Payload, Task> publishMessage, string project_id, HttpContext? httpContext = null, ATOptions? options = null) : base(new HttpClientHandler())
443473
{
444474
_context = httpContext ?? throw new ArgumentNullException(nameof(httpContext));

ApiToolkitTests.cs

+74-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
using Microsoft.AspNetCore.Hosting;
1111
using Microsoft.Extensions.Hosting;
1212
using Microsoft.AspNetCore.Builder;
13-
13+
using Moq;
14+
using System.Net.Http;
15+
using Microsoft.Extensions.DependencyInjection;
1416
public class RedactTests
1517
{
1618
[Test]
@@ -208,3 +210,74 @@ public async Task MiddlewareTest_ReturnsNotFoundForRequest()
208210
}
209211
}
210212

213+
214+
public class ApiToolkitClientFactoryTests
215+
{
216+
private Mock<IHttpClientFactory> _httpClientFactoryMock;
217+
private Mock<IServiceProvider> _serviceProviderMock;
218+
private Mock<ObservingHandler> _observingHandlerMock;
219+
private IApiToolkitClientFactory _apiToolkitClientFactory;
220+
221+
[SetUp]
222+
public void SetUp()
223+
{
224+
_httpClientFactoryMock = new Mock<IHttpClientFactory>();
225+
_serviceProviderMock = new Mock<IServiceProvider>();
226+
_observingHandlerMock = new Mock<ObservingHandler>();
227+
228+
// Set up the service provider to return the observing handler mock
229+
_serviceProviderMock
230+
.Setup(sp => sp.GetService(typeof(ObservingHandler)))
231+
.Returns(_observingHandlerMock.Object);
232+
233+
// Initialize the ApiToolkitClientFactory with mocks
234+
_apiToolkitClientFactory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, _serviceProviderMock.Object);
235+
}
236+
237+
[Test]
238+
public void CreateClient_ShouldReturnHttpClient_WithConfiguredHandler()
239+
{
240+
// Arrange
241+
var options = new ATOptions
242+
{
243+
PathWildCard = "/posts/{id}",
244+
RedactHeaders = new List<string> { "User-Agent" },
245+
RedactRequestBody = new List<string> { "$.user.password" },
246+
RedactResponseBody = new List<string> { "$.user.data.email" }
247+
};
248+
249+
// Act
250+
var client = _apiToolkitClientFactory.CreateClient(options);
251+
252+
// Assert
253+
Assert.NotNull(client);
254+
_observingHandlerMock.Verify(h => h.SetOptions(options), Times.Once);
255+
}
256+
257+
[Test]
258+
public void CreateClient_ShouldUseObservingHandler_FromServiceProvider()
259+
{
260+
// Act
261+
var client = _apiToolkitClientFactory.CreateClient(new ATOptions());
262+
263+
// Assert
264+
_serviceProviderMock.Verify(sp => sp.GetService(typeof(ObservingHandler)), Times.Once);
265+
}
266+
267+
[Test]
268+
public void CreateClient_ShouldThrowException_WhenHandlerNotRegistered()
269+
{
270+
// Arrange
271+
var invalidServiceProvider = new Mock<IServiceProvider>();
272+
invalidServiceProvider.Setup(sp => sp.GetService(typeof(ObservingHandler)))
273+
.Returns(null); // Simulate missing handler registration
274+
275+
var factory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, invalidServiceProvider.Object);
276+
277+
// Act & Assert
278+
Assert.Throws<NullReferenceException>(() => factory.CreateClient(new ATOptions()));
279+
}
280+
}
281+
282+
283+

README.md

+70-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
## .NET Core SDK
77

8-
[![APItoolkit SDK](https://img.shields.io/badge/APItoolkit-SDK-0068ff?logo=dotnet)](https://github.com/topics/apitoolkit-sdk) [![Join Discord Server](https://img.shields.io/badge/Chat-Discord-7289da)](https://discord.gg/dEB6EjQnKB) [![APItoolkit Docs](https://img.shields.io/badge/Read-Docs-0068ff)](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_source=github-sdks) [![Build Status](https://github.com/apitoolkit/apitoolkit-dotnet/workflows/.NET/badge.svg)](https://github.com/apitoolkit/apitoolkit-dotnet1/actions?query=workflow%3ACI) [![NuGet](https://img.shields.io/nuget/v/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net) [![Nuget](https://img.shields.io/nuget/dt/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net)
8+
[![APItoolkit SDK](https://img.shields.io/badge/APItoolkit-SDK-0068ff?logo=dotnet)](https://github.com/topics/apitoolkit-sdk) [![Join Discord Server](https://img.shields.io/badge/Chat-Discord-7289da)](https://apitoolkit.io/discord?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) [![APItoolkit Docs](https://img.shields.io/badge/Read-Docs-0068ff)](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) [![Build Status](https://github.com/apitoolkit/apitoolkit-dotnet/workflows/.NET/badge.svg)](https://github.com/apitoolkit/apitoolkit-dotnet1/actions?query=workflow%3ACI) [![NuGet](https://img.shields.io/nuget/v/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net) [![Nuget](https://img.shields.io/nuget/dt/ApiToolkit.Net.svg)](https://nuget.org/packages/ApiToolkit.Net)
99

1010
APItoolkit is an end-to-end API and web services management toolkit for engineers and customer support teams. To integrate .Net web services with APItoolkit, you need to use this SDK to monitor incoming traffic, aggregate the requests, and then deliver them to the APItoolkit's servers.
1111

@@ -38,6 +38,11 @@ Next, initialize APItoolkit in your application's entry point (e.g., `Program.cs
3838
using ApiToolkit.Net;
3939

4040
// Initialize the APItoolkit client
41+
builder.Services.AddTransient<ObservingHandler>();
42+
43+
// Register the custom API Toolkit Client Factory
44+
builder.Services.AddSingleton<IApiToolkitClientFactory, ApiToolkitClientFactory>();
45+
4146
var config = new Config
4247
{
4348
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
@@ -60,22 +65,82 @@ app.Use(async (context, next) =>
6065
# ...
6166
```
6267

68+
## Usage
69+
70+
You can now use the IApiToolKitClientFactory Interface to directly make your Http requests
71+
72+
```csharp
73+
public class MyService
74+
{
75+
private readonly IApiToolkitClientFactory _apiToolkitClientFactory;
76+
77+
public MyService(IApiToolkitClientFactory apiToolkitClientFactory)
78+
{
79+
_apiToolkitClientFactory = apiToolkitClientFactory;
80+
}
81+
82+
public async Task<string> GetPostAsync()
83+
{
84+
var options = new ATOptions
85+
{
86+
PathWildCard = "/posts/{id}",
87+
RedactHeaders = new[] { "User-Agent" },
88+
RedactRequestBody = new[] { "$.user.password" },
89+
RedactResponseBody = new[] { "$.user.data.email" }
90+
};
91+
92+
var client = _apiToolkitClientFactory.CreateClient(options);
93+
var response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");
94+
return await response.Content.ReadAsStringAsync();
95+
}
96+
}
97+
```
98+
99+
Traditional Middleware Setup
100+
If you prefer to set up the middleware traditionally, here's how you can initialize APItoolkit in your application's entry point (e.g., Program.cs):
101+
102+
```csharp
103+
using ApiToolkit.Net;
104+
105+
// Initialize the APItoolkit client
106+
var config = new Config
107+
{
108+
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
109+
Debug = false,
110+
Tags = new List<string> { "environment: production", "region: us-east-1" },
111+
ServiceVersion: "v2.0",
112+
};
113+
var client = await APIToolkit.NewClientAsync(config);
114+
115+
// Register the middleware to use the initialized client
116+
app.Use(async (context, next) =>
117+
{
118+
var apiToolkit = new APIToolkit(next, client);
119+
await apiToolkit.InvokeAsync(context);
120+
});
121+
122+
// app.UseEndpoint(..)
123+
// other middleware and logic
124+
// ...
125+
```
126+
127+
63128
> [!NOTE]
64129
>
65130
> - Please make sure the APItoolkit middleware is added before `UseEndpoint` and other middleware are initialized.
66-
> - The `{ENTER_YOUR_API_KEY_HERE}` demo string should be replaced with the [API key](https://apitoolkit.io/docs/dashboard/settings-pages/api-keys?utm_source=github-sdks) generated from the APItoolkit dashboard.
131+
> - The `{ENTER_YOUR_API_KEY_HERE}` demo string should be replaced with the [API key](https://apitoolkit.io/docs/dashboard/settings-pages/api-keys?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme) generated from the APItoolkit dashboard.
67132
68133
<br />
69134

70135
> [!IMPORTANT]
71136
>
72-
> To learn more configuration options (redacting fields, error reporting, outgoing requests, etc.), please read this [SDK documentation](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_source=github-sdks).
137+
> To learn more configuration options (redacting fields, error reporting, outgoing requests, etc.), please read this [SDK documentation](https://apitoolkit.io/docs/sdks/dotnet/dotnetcore?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme).
73138
74139
## Contributing and Help
75140

76141
To contribute to the development of this SDK or request help from the community and our team, kindly do any of the following:
77142
- Read our [Contributors Guide](https://github.com/apitoolkit/.github/blob/main/CONTRIBUTING.md).
78-
- Join our community [Discord Server](https://discord.gg/dEB6EjQnKB).
143+
- Join our community [Discord Server](https://apitoolkit.io/discord?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme).
79144
- Create a [new issue](https://github.com/apitoolkit/apitoolkit-dotnet/issues/new/choose) in this repository.
80145

81146
## License
@@ -86,6 +151,6 @@ This repository is published under the [MIT](LICENSE) license.
86151

87152
<div align="center">
88153

89-
<a href="https://apitoolkit.io?utm_source=github-sdks" target="_blank" rel="noopener noreferrer"><img src="https://github.com/apitoolkit/.github/blob/main/images/icon.png?raw=true" width="40" /></a>
154+
<a href="https://apitoolkit.io?utm_campaign=devrel&utm_medium=github&utm_source=sdks_readme" target="_blank" rel="noopener noreferrer"><img src="https://github.com/apitoolkit/.github/blob/main/images/icon.png?raw=true" width="40" /></a>
90155

91156
</div>

apitoolkit-dotnet.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.5" />
2828
<!-- Deprecated -->
2929
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
30+
<PackageReference Include="Moq" Version="4.20.70" />
3031
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
3132
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
3233
<PackageReference Include="NUnit" Version="3.13.3" />

0 commit comments

Comments
 (0)