Class library to build clients and work with HTTP web services.
$ dotnet add package Universal.Common.Net.HttpClass library accelerate building clients for various web services.
You can derive a strongly-typed client from HttpServiceClient or the more specialized versions such as JsonHttpServiceClient.
public class MyClient : HttpServiceClient
{
// ...
}
Alternative, you can also use these classes directly.
The InterceptingDelegatingHandler is a powerful tool for intercepting and modifying HTTP requests and responses. It allows you to define rules that match specific requests and either replace them with custom responses or modify the actual responses.
var handler = new InterceptingDelegatingHandler();
var httpClient = new HttpClient(handler);
Use When() to define matching conditions and RespondWith() to provide custom responses:
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.AbsolutePath.Contains("/api/test"))
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Mocked response")
});
Use Modify() to transform responses from actual HTTP calls:
var handler = new InterceptingDelegatingHandler()
.When(req => req.Method == HttpMethod.Get)
.Modify((req, resp) =>
{
resp.Headers.Add("X-Custom-Header", "Modified");
return resp;
});
Both RespondWith() and Modify() support async operations:
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.Host == "api.example.com")
.RespondWith(async req =>
{
var data = await GetDataAsync();
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(data)
};
});
Chain multiple rules to handle different scenarios:
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.AbsolutePath == "/api/users")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"users\":[]}")
})
.When(req => req.RequestUri.AbsolutePath == "/api/products")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"products\":[]}")
});
// Mock external API calls in tests
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.Host == "external-api.com")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"status\":\"success\"}")
});
// Automatically add authentication to responses
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.AbsolutePath.StartsWith("/api/"))
.Modify(async (req, resp) =>
{
var token = await GetAuthTokenAsync();
resp.Headers.Add("Authorization", $"Bearer {token}");
return resp;
});
// Simulate errors for testing
var handler = new InterceptingDelegatingHandler()
.When(req => req.Headers.Contains("X-Simulate-Error"))
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("Simulated error")
});
public class MyClient : HttpServiceClient
{
protected override HttpClient CreateHttpClient()
{
var handler = new InterceptingDelegatingHandler()
.When(req => req.RequestUri.AbsolutePath.Contains("/slow"))
.Modify((req, resp) =>
{
resp.Headers.Add("X-Cache", "HIT");
return resp;
});
return new HttpClient(handler);
}
}
The Universal.Common.Net.Http.Extensions namespace provides extension methods that simplify common matching scenarios:
Match requests by URI pattern (case-insensitive):
var handler = new InterceptingDelegatingHandler()
.WhenUri("/api/users")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK));
Match requests using regular expressions:
var handler = new InterceptingDelegatingHandler()
.WhenUriMatches(new Regex(@"/api/users/\d+"))
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"id\":123,\"name\":\"John\"}")
});
Match requests by HTTP method:
var handler = new InterceptingDelegatingHandler()
.WhenMethod(HttpMethod.Post)
.Modify((req, resp) =>
{
resp.Headers.Add("X-Request-Method", "POST");
return resp;
});
Match requests containing a specific header with a given value:
var handler = new InterceptingDelegatingHandler()
.WhenHeader("X-API-Version", "v2")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"version\":\"2.0\"}")
});
Chain multiple conditions for more complex scenarios:
var handler = new InterceptingDelegatingHandler()
.WhenMethod(HttpMethod.Get)
.WhenUri("/api/")
.WhenHeader("Authorization", "Bearer test-token")
.RespondWith(req => new HttpResponseMessage(HttpStatusCode.OK));