I created a service that allowed me to utilize the Stripe.Net classes (I called it a handler) but it wasn't really testable because in the methods I would instantiate the class. For example:
public Customer CreateCustomer(string email)
{
var service = new CustomerService();
return service.Create(new CustomerCreateOptions
{
Email = email
});
}
which it's great when trying to create a test. So I figured I could just use the classes in Stripe.net instead of creating a handler. So I have tried doing this:
private static void AddTransients(IServiceCollection services)
{
services.AddTransient<Service<IStripeEntity>>();
services.AddTransient<ICreatable<IStripeEntity, BaseOptions>>();, BaseOptions));
}
Which I through would allow me to pass the classes around my controllers like any other injected class. But when I launch my application I get this error:
Cannot instantiate implementation type 'Stripe.IStripeEntity' for service type 'Stripe.IStripeEntity'.
So I tried registering the classes as generic like this:
private static void AddTransients(IServiceCollection services)
{
services.AddTransient(typeof(Service<>));
services.AddTransient(typeof(ICreatable<,>));
}
But when I run that, I get the same error. Does anyone know what I can do to get this to work?
I solved it by creating wrapper classes. Not the most ideal, but it works:
public class StripeCustomerService : IStripeCustomerService
{
private readonly CustomerService _customerService;
public StripeCustomerService() => _customerService = new CustomerService();
public Customer Create(string email)
{
return _customerService.Create(new CustomerCreateOptions
{
Email = email
});
}
public async Task<Customer> GetAsync(string id, CancellationToken cancellationToken) =>
await _customerService.GetAsync(id, cancellationToken: cancellationToken);
}
Related
I have an api client that in its constructor accepts access token
public class ApiClient : IApiClient
{
public ApiClient(string accessToken)
}
To get that api token I need to create instance of another class and call method GetTokenAsync()
public class TokenClient
{
public Task<string> GetTokenAsync();
}
now I want to inject IApiClient to my TestService
public class TestService
{
public TestService(IApiClient client)
}
However it is not possible register instance in this way
services.AddScoped<IApiClient,ApiClient>(async x=>
{
tokenClient = x.GetService<TokenClient>();
var token = await tokenClient.GetTokenAsync();
return new ApiClient(token);
}
to overcome that I have created ApiClientProvider class
public class ApiClientProvider()
{
public async Task<IApiClient> GetClientAsync()
{
tokenClient = x.GetService<TokenClient>();
var token = await tokenClient.GetTokenAsync();
return new ApiClient(token);
}
}
and now I inject it to TestService
but in every method I have to use
IApiClient apiClient= await _apiClientProvider.GetClientAsync();
I don not like this code, I prefer when dependencies are injected and not resolved in every function, however I do not see any way around. Can you advise if this can be moved to registration or maybe it shouldn't go there.
You should change your design slightly.
Rather than inject a string into your ApiClient, inject an ITokenClient:
public interface ITokenClient
{
Task<string> GetTokenAsync();
}
public class TokenClient : ITokenClient
{
public Task<string> GetTokenAsync() { }
}
public class ApiClient : IApiClient
{
readonly Task<string> tokenTask;
public ApiClient(ITokenClient tokenClient)
{
// Initiate the token request on construction
tokenTask = tokenClient.GetTokenAsync();
}
public async Task SomeMethod()
{
string token = await tokenTask;
// Use your token..
}
}
Any methods that rely on the token must be async, but as your calling an API they're likely to be async anyway.
Using this method, you simply need to register your clients with the container and no factories / provider types are required.
In every example I've seen, including the Microsoft ones here and here, the author's explain the improvements made by IHttpClientFactory over HttpClient and give examples of how to use it simply out-of-the-box or in Named form. But then they all seem to mention that utilizing the Typed form really is best for its structure, usability, and more. The reasons make sense for our use case.
Though like the links provided above, there isn't a single line of code instantiating, injecting, or using IHttpClientFactory in the involvement of creating a Typed HttpClient (or Service as a Client). You create the Typed Client:
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
and then you consume it in some model or controller:
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
I'm extremely confused. My team was originally hitting roadblocks trying to mock (with Moq) Typed clients for unit testing, and the conclusion that we came to after many great resources was that mocking was exponentially easier with IHttpClientFactory. But I haven't found a single example that explicitly uses IHttpClientFactory with Typed clients.
The framework will use ITypedHttpClientFactory to create the HttpClient to be injected into the typed client. This is happening under the hood when the typed client is configured like so:
services.AddHttpClient<ICatalogService, CatalogService>()
If we peek into AddHttpClient, we can see that it'll attempt to create a transient version of IHttpClientFactory called ITypedHttpClientFactory
services.TryAdd(ServiceDescriptor.Transient(typeof(ITypedHttpClientFactory<>), typeof(DefaultTypedHttpClientFactory<>)));
Typed clients do also allow for abstracted clients
public class GitHubService :IGitHubService { // <-- NOTE THE INTERFACE
HttpClient client
public GitHubService(HttpClient client) {
this.client = client;
}
//...
Where the interface is registered along with its implementation using AddHttpClient
services.AddHttpClient<IGitHubService, GitHubService>();
and used accordingly
//...
private readonly IGitHubService gitHubService;
public TypedClientModel(IGitHubService gitHubService) {
this.gitHubService = gitHubService;
}
public async Task OnGet() {
try {
LatestIssues = await gitHubService.GetAspNetDocsIssues();
}
//...
The advantage here is that You decouple from 3rd party dependencies (framework concerns) since you are the one in control of the typed client and its abstraction.
This will allow for easier mocking of the typed client abstraction when testing in isolation.
With IHttpClientFactory you have three options:
IHttpClientFactory
Usage
public class SampleController
{
private readonly IHttpClientFactory _clientFactory;
public SampleController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
}
Mocking
//Arrange
var mockClientFactory = new Mock<IHttpClientFactory>();
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(expectedResponseMessage);
var client = new HttpClient(mockMessageHandler.Object);
mockClientFactory
.Setup(_ => _.CreateClient(It.IsAny<string>()))
.Returns(client);
Named client
Usage
public class SampleController
{
private readonly HttpClient _client;
public SampleController(IHttpClientFactory clientFactory)
{
_client = clientFactory.CreateClient("SampleProxy");
}
}
Mocking
As an alternative we can avoid the usage of Moq.Protected by using a custom HttpMessageHandler
public class FakeMessageHandler: HttpMessageHandler
{
public virtual HttpResponseMessage Send(HttpRequestMessage request)
{
throw new NotImplementedException();
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(Send(request));
}
}
//Arrange
var mockClientFactory = new Mock<IHttpClientFactory>();
var mockMessageHandler = new Mock<FakeMessageHandler> { CallBase = true };
mockMessageHandler
.Setup(handler => handler.Send(It.IsAny<HttpRequestMessage>()))
.Returns(expectedResponseMessage);
var client = new HttpClient(mockMessageHandler.Object);
mockClientFactory
.Setup(_ => _.CreateClient("SampleProxy"))
.Returns(client);
Typed client
Usage
public class SampleController
{
private readonly ISampleClient _client;
public SampleController(ISampleClient client)
{
_client = client;
}
}
Mocking
//Arrange
var clientMock = new Mock<ISampleClient>();
clientMock
.Setup(client => client.GetXYZ(It.IsAny<SampleRequest>()))
.ReturnsAsync(expectedSampleResponse);
var SUT = new SampleController(clientMock.Object);
Due on Improper Instantiation problem it is recommended to create private static readonly instance of HttpClient.
Due on lack of time I have injected mocked client into test method with client as their parameter.
The problem is how can I in simple way inject mock into private static readonly HttpClient field of SingleHttpClientInstanceController?
how can I in simple way inject mock into private static readonly
HttpClient field of SingleHttpClientInstanceController?
Answer: There is no simple way.
Suggestion:
Abstract the resource behind an accessor
public interface IHttpClientAccessor {
HttpClient HttpClient { get; }
}
and inject that into the dependent controller.
public class SingleHttpClientInstanceController : ApiController {
private readonly HttpClient HttpClient;
public SingleHttpClientInstanceController(IHttpClientAccessor httpClientAccessor) {
HttpClient = httpClientAccessor.HttpClient;
}
// This method uses the shared instance of HttpClient for every call to GetProductAsync.
public async Task<Product> GetProductAsync(string id) {
var hostName = HttpContext.Current.Request.Url.Host;
var result = await HttpClient.GetStringAsync(string.Format("http://{0}:8080/api/...", hostName));
return new Product { Name = result };
}
}
The same should also be done for accessing HttpContext which is what was recently introduced in Asp.Net-Core's IHttpContextAccessor
An implementation of the IHttpClientAcessor can look something like this
public class HttpClientAccessor : IHttpClientAccessor {
static readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() => new HttpClient());
public HttpClient HttpClient { get { return client.Value; } }
}
So now for tests you can inject mock of the dependency.
If using a DI container remember to register the accessor as a singleton as well.
We have a websolution with autofac. Now we want to reuse things in a windows service/console app where things are only available when a message comes in from an enterprise bus.
I have the following service to reuse
public SettingsService : ISettingsService {
public readonly ITenantIdentifer _tenantIdentifier
public SettingsService (ITenantIdentifier tenantIdentifier) {
this._tenantIdentifier =tenantIdentifier;
}
// do other stuff
}
The current working setup
the ITenantIdentifier for the webcontext is simply registered for the webapplication using builder.RegisterType<WebTenantIdentifier>().As<ITenantIdentifier>();.
Evething works fine.
Our enterprise bus
The enterprise bus can not resolve the ITenantIdentifier until the message is available. So we created a MessageTenantIdentifier and registered a factory.
public class MessageTenantIdentifier : ITenantIdentifier
{
public delegate MessageTenantIdentifier Factory(int tenantId);
public MessageTenantIdentifier(int tenantId, IOtherDependency stuff)
{
_tenantId = tenantId;
// ...
}
}
// somewhere else the this is registered
builder.RegisterType<MessageTenantIdentifier >().As<ITenantIdentifier>().AsSelf();
builder.RegisterGeneratedFactory<MessageTenantIdentifier.Factory>();
The problem
The factory can only be used when the message is being handled in a
public class MsgTypeHandler : IHandleMessages<MsgType>
{
public MsgTypeHandler(ISettingsService settingsService, MessageTenantIdentifier factory) { ...}
public async Task Handle(MsgType message)
{
var tenantId = message.TenantId;
// THIS IS THE MOMENT I CAN CONFIGURE THE MessageTenantIdentifier
var tenantIdentifier = factory.Invoke(tenantId);
// but this factory is not used against the ISettingsService. The service to be reused. <== THE REAL PROBLEM
}
}
The question
So, how can I solve this issue? E.g. how should I setup the registration of the MessageTenantIdentifier in the servicebus?
Or is my dependency setup just plain wrong?
If the MsgTypeHandler class needs an ISettingsService, but the entire object graph can't be resolved until the tenant ID is available, that means that the MsgTypeHandler is the Composition Root. That's OK, but that means that this is where you resolve your entire object graph, so don't inject individual services here; instead, inject the factory you need:
public class MsgTypeHandler : IHandleMessages<MsgType>
{
public MsgTypeHandler(ISettingsServiceFactory factory) {...}
public async Task Handle(MsgType message)
{
var tenantId = message.TenantId;
ISettingsService svc = this.factory.Create(tenantId);
// User svc here...
}
}
For a standard Request Server I use the below code to match a request to a service and process the incoming requests.
ServiceProvider
public class ServiceProvider
{
public ServiceProvider()
{
Services = new Dictionary<Type, IService>
{
{ typeof(FooRequest), new FooService() },
{ typeof(BarRequest), new BarService() },
};
}
protected void OnRequestReceived(object request)
{
Services[request.GetType()].Process(request);
}
}
FooService
public class FooService : IService
{
public object Process(object request)
{
// Process request
}
}
This works like a charm, but I want to get rid of one method (Process) per service. I tried working with Actions and Delegates but I somehow cannot accomplish this simple structure.
Basically my question is: How can I register multiple methods/callbacks from another class and store them in a dictionary for whenever I need to call them?
Desired result (pseudocode):
ServiceProvider
public class ServiceProvider
{
public ServiceProvider()
{
var fooService = new FooService();
var barService = new BarService();
Handlers = new Dictionary<Type, Action>
{
{ typeof(FooRequestA), fooService.ProcessA },
{ typeof(FooRequestB), fooService.ProcessB },
{ typeof(BarRequest), barService.Process },
};
}
protected void ProcessRequest(object request)
{
Handlers[request.GetType()].Invoke(request);
}
}
FooService
public class FooService
{
public object ProcessA(FooRequestA request)
{
// Process request A
}
public object ProcessB(FooRequestB request)
{
// Process request B
}
}
Improvement on solution
Using the below method you can simplify the recurring request-service matching code:
public void RegisterHandler<TRequest>(Action<TRequest> function)
{
Handlers.Add(typeof(TRequest), request => function.Invoke((TRequest) request));
}
Which results in a very clean usage:
RegisterHandler<FooRequestA>(request => fooService.ProcessA(request));
This is the best I can come up with. (while trying to stay close what you asked for... there may be much better ways to achieve what you actually want to do). I think you lose a little type safety with that solution:
FooService
public class FooService
{
public object ProcessA(FooRequestA request)
{
return null;
}
public object ProcessB(FooRequestB request)
{
return null;
}
}
BarService
public class BarService
{
public void Process(BarRequest request)
{ }
}
ServiceProvider
public class ServiceProvider
{
private readonly Dictionary<Type, Action<object>> Handlers;
public ServiceProvider()
{
var fooService = new FooService();
var barService = new BarService();
Handlers = new Dictionary<Type, Action<object>>
{
{typeof(FooRequestA), request => fooService.ProcessA((FooRequestA)request)},
{typeof(FooRequestB), request => fooService.ProcessB((FooRequestB)request)},
{typeof(BarRequest), request => barService.Process((BarRequest)request)}
};
}
protected void ProcessRequest(object request)
{
Handlers[request.GetType()].Invoke(request);
}
}
Since you cannot convert a method group (like fooService.ProcessA) into an Action, you need to add lambdas to your Dictionary<Type, Action<object>> and provide the request as parameter.
Since you declare the dictionary as <Type, Action>, you cannot pass an argument to .Invoke(object) method - Action does not accept any arguments. What you probably need is Dictionary<Type, Action<object>>. I say "probably" because ProcessA and ProcessBmethods return an object, so Dictionary<Type, Func<object, object>> seems more logical. Anyhow, I hope this is just an educational question because there are other ways far more correct and efficient to accomplish what your'e looking for.
Instead of registering single methods in the ServiceProvider, you could also let the services decide which requests they can handle. You could create an interface that contains the following methods (I'm using Request as a base class for all requests to avoid the object parameter):
public interface IService
{
bool CanHandle(Request request);
void Handle(Request request);
}
In your registry, you register the services and route the request to the service:
public class ServiceProvider
{
private readonly IEnumerable<IService> _registeredServices = new IService[]
{
new FooService(),
new BarService();
};
protected void OnRequestReceived(Request request)
{
// Find first service that can handle the request
var serviceForRequest =
_registeredServices.Where(x => x.CanHandle(request)).FirstOrDefault();
if (serviceForRequest == null)
throw new InvalidOperationException("No service registered that can handle request " + request.ToString();
// Let the service handle the request
serviceForRequest.Handle(request);
}
}
This structure has the advantage that you do not have to change the ServiceProvider every time a service can handle a new type of request. Transferred to your sample, you could add the ProcessB method to FooService and change the implementation of CanHandle and Handle in the class without having to change the registration.
Instead of registering the services, you can detect them dynamically either by using a IoC container or a reflection-based implementation. In this case you don't have to change the ServiceProvider even if you add a new service.