Passing IHttpClientFactory into class - c#

If I have a controller class, and I want to pass it to a different namespace that handles my HTTP calls, such as in the below scenario, Main task calls TaskA() which calls TaskG(), do I need to pass it to TaskG via A like the below? Or is there someway to just create it in the namespace HttpClassFurtherDown without the calling classes needing to pass it.
namespace Controllers{
public class Drawings : ControllerBase
{
private IHttpClientFactory _client {get;set;}
public Drawings(IHttpClientFactory client)
{
_client=client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content)
{
HttpExample e = new HttpExample(_client);
e.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}}
namespace HttpClassExample{
public class HttpExample
{
private IHttpClientFactory _client {get;set;}
public HttpExample(IHttpClientFactory client)
{
_client=client;
}
public void TaskA()
{
DoSomeProcessing();
HttpClassExampleFurtherDown e = new HttpClassExampleFurtherDown(client);
e.TaskG();
}
}
}
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown
{
private IHttpClientFactory _client {get;set;}
public HttpExampleFurtherDown(IHttpClientFactory client)
{
_client=client;
}
public void TaskG(client)
{
//Finally Using It Here. I want to avoid having to generate it at the controller level and pass it all the way down.
client.CreateClient();
client.SendAsync();
}
}
}

I want to avoid having to generate it at the controller level and pass it all the way down.
If following DIP then inject explicit dependencies where they are actually needed instead of tightly coupling to implementation concerns.
While I believe the example provided are oversimplified, here is what the example above should look like
Controllers.Drawings
namespace Controllers{
using HttpClassExample;
//...
public class Drawings : ControllerBase {
private readonly IHttpExample client;
public Drawings(IHttpExample client) {
this.client = client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content) {
await client.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}
}
HttpClassExample.HttpExample
namespace HttpClassExample{
using HttpClassExampleFurtherDown;
//...
public class HttpExample : IHttpExample{
private readonly IHttpExampleFurtherDown client;
public HttpExample(IHttpExampleFurtherDown client) {
this.client = client;
}
public async Task TaskA() {
DoSomeProcessing();
await client.TaskG();
}
//...
}
}
HttpClassExampleFurtherDown.HttpExampleFurtherDown
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown : IHttpExampleFurtherDown {
private readonly IHttpClientFactory factory;
public HttpExampleFurtherDown(IHttpClientFactory factory) {
this.factory = factory;
}
public async Task TaskG() {
HttpClient client = factory.CreateClient();
//...
var response = await client.SendAsync();
//...
}
}
}
This assumes that a container is being used to manage the resolution and injection of dependency implementations based on their registered abstractions

Related

Reading HttpContext.Request as object?

My base Request class looks like this:
public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}
public abstract class QueryBase<T> : UserContext, IRequest<T> // IRequest is MediatR interface
{
}
public abstract class UserContext
{
public string ApplicationUserId { get; set; } // and other properties
}
I want to write a middleware to my .NET Core 3.1 WebApi that will grab JWT from request header amd read ApplicationUserId from it. I started to code something:
public class UserInformation
{
private readonly RequestDelegate next;
public UserInformation(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var jwt = context.Request.Headers["Authorization"];
// read jwt here
var userContext = (UserContext)context.Request.Body; // i know it wont work
userContext.ApplicationUserId = //whats next? Any ideas?
await this.next(context);
}
}
But to be honest i have no idea how to start so here are my questions:
As you can see, every request will be packed with my UserContext class and so on. How to cast HttpContext.Request.Body to my request object and attach ApplicationUserId to it? Is it possible? I want to acces to user credentials from my JWT from headers and i want to have that information in every request in my API (pass it to controller, then to command etc).
If getting this information from middleware is not the best practice, what is?
EDIT: Mcontroller that using MediatR:
// base controller:
[ApiController]
[Route("[controller]")]
public abstract class BaseController : ControllerBase
{
private IMediator mediator;
protected IMediator Mediator => this.mediator ?? (this.mediator = HttpContext.RequestServices.GetService<IMediator>());
}
// action in ProjectControlle
[HttpGet]
[Authorize]
public async Task<ActionResult<ProjectsListModel>> GetAllProjects()
{
return Ok(await base.Mediator.Send(new GetAllProjectsQuery()));
}
// query:
public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}
// handler:
public class GetAllProjectsQueryHandler : IRequestHandler<GetAllProjectsQuery, ProjectsListModel>
{
private readonly IProjectRepository projectRepository;
public GetAllProjectsQueryHandler(IProjectRepository projectRepository)
{
this.projectRepository = projectRepository;
}
public async Task<ProjectsListModel> Handle(GetAllProjectsQuery request, CancellationToken cancellationToken)
{
var projects = await this.projectRepository.GetAllProjectsWithTasksAsync();
return new ProjectsListModel
{
List = projects
};
}
}
You might not need a middleware, but need a model binder:
See: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1
Also see: https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1
public class UserContextModelBinder : IModelBinder
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IModelBinder _defaultModelBinder;
public UserContextModelBinder(
IHttpContextAccessor httpContextAccessor,
IOptions<MvcOptions> mvcOptions,
IHttpRequestStreamReaderFactory streamReaderFactory)
{
_httpContextAccessor = httpContextAccessor;
_defaultModelBinder = new BodyModelBinder(mvcOptions.Value.InputFormatters, streamReaderFactory);
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (!typeof(UserContext).IsAssignableFrom(bindingContext.ModelType))
{
return;
}
await _defaultModelBinder.BindModelAsync(bindingContext);
if (bindingContext.Result.IsModelSet && bindingContext.Result.Model is UserContext)
{
var model = (UserContext)bindingContext.Result.Model;
var httpContext = _httpContextAccessor.HttpContext;
// Read JWT
var jwt = httpContext.Request.Headers["Authorization"];
model.ApplicationUserId = jwt;
bindingContext.Result = ModelBindingResult.Success(model);
}
}
}
Then add model binder to UserContext class:
[ModelBinder(typeof(UserContextModelBinder))]
public abstract class UserContext
{
public string ApplicationUserId { get; set; }
}
Also add IHttpContextAccessor to services in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpContextAccessor();
}

ASP.NET Core dependency injection - How to create instances?

In Startup:
services.AddTransient<IMyService, MyService>()
Controller method:
[HttpGet]
public JsonResult GetSomething()
{
Helper helper = new Helper(new MyService()); // works but looking better solution
return Ok("");
}
Helper class:
public class Helper
{
private readonly IMyService myService;
public Helper(IMyService myService)
{
this.myService = myService;
}
public Helper()
{
this.myService = ?;
}
}
I want to instantiate Helper class without inject the dependency manually with new MyService().
The MyService() class should be the class in startup.
I also want to place the the Helper class in another assembly.
I see some code with
var service = (IFooService)serviceProvider.GetService(typeof(IMyService));
but i don't know how to get a serviceProvider instance without injecting it to the helper.
Add the helper to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<Helper>(sp => new Helper(sp.GetRequiredService<IMyService>()));
And explicitly inject it into the controller
public class MyController: Controller {
private readonly Helper helper;
public MyController(Helper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
Ideally the helper should be derived from an abstraction as well
public class Helper : IHelper {
private readonly IMyService myService;
public Helper(IMyService myService) {
this.myService = myService;
}
//...
}
And added accordingly to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<IHelper, Helper>();
to avoid the controller having tight coupling to concretions (implementation concerns).
public class MyController: Controller {
private readonly IHelper helper;
public MyController(IHelper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
A way to properly resolve the service via DI:
[HttpGet]
public JsonResult GetSomething([FromServices] IMyService myService)
{
Helper helper = new Helper(myService);
return Ok("");
}
Or you inject it via ctor and use it in the method.

IDistributedCache call a constructor with injection

I have a project using redis distributed cache based on asp.net core 2.1 solution. There's something that I haven't understood.
I have a class myClassName with a constructor subject to injection.
public class myClassName
{
private readonly IDistributedCache _userCache;
public myClassName(IDistributedCache distributedCache) => _userCache
= distributedCache;
public async Task FirstMethod(...)
private async Task SecondMethod(...)
}
from another class "myClassNameTwo" I have to create a "myClassName" instance and access to some methods.
So I have :
Public class myClassNameTwo : Hub
{
private readonly AssetsBroadcaster _broadcaster;
public myClassNameTwo(AssetsBroadcaster broadcaster)
{
_broadcaster = broadcaster;
}
public async Task DoSomething(...)
{
myClassName hello = new myClassName(???)
await hello.FirstMethod(...)
}
}
How can retrieve the IDistributedCache service instance to pass to myClassName constructor?
If you are using .Net Core, Using dependency injunction, You can inject the instants of the myClassName class if you have registered it in the startup.
like,
public class myClassName{
private readonly IDistributedCache _userCache;
public myClassName(IDistributedCache distributedCache) {
_userCache = distributedCache;
}
public async Task FirstMethod(...)
private async Task SecondMethod(...)
}
For the second class it can be like following
Public class myClassNameTwo : Hub
{
private readonly AssetsBroadcaster _broadcaster;
private readonly myClassName _myClassName;
public myClassNameTwo(AssetsBroadcaster broadcaster,
myClassName myClassName)
{
_broadcaster = broadcaster;
_myClassName = myClassName;
}
public async Task DoSomething(...)
{
await _myClassName.FirstMethod(...)
}
}
Dependencies for the myClassName will be automatically injected. So you don't need to inject it separately.
For more details

How to fix DbContext has been disposed for an async scenario?

We have upgraded our application from NserviceBus v5 to v6 and after that we run into major problem, most of the time receiving the following error.
The operation cannot be completed because the DbContext has been
disposed.
It was not obvious until we got load to our system.
We are running with eight concurrent threads and by that we receive the above error.
public class EndpointInitializer
{
public void Initialize(IKernel container)
{
var endpointConfiguration = new EndpointConfiguration("MyEndpoint");
endpointConfiguration.UseContainer<NinjectBuilder>(
customizations => { customizations.ExistingKernel(container); });
//More settings...
}
}
.
public class MyMessageHandler : IHandleMessages<MyCommand>
{
private readonly IPersonRepository _personRepository;
public MyMessageHandler(IPersonRepository personRepository)
{
_personRepository = personRepository;
}
public async Task Handle(MyCommand message, IMessageHandlerContext context)
{
var person = await _personRepository.GetByIdentifierAsync(message.Identifier).ConfigureAwait(false);
//More code...
await _personRepository.UpdateAsync(person);
}
}
.
[Serializable]
public class MyCommand
{
public string Identifier { get; set; }
}
.
public class DependencyRegistrar
{
public IKernel Container { get; set; }
public void Create()
{
Container = new StandardKernel();
RegisterTypes(Container);
}
public void RegisterTypes(IKernel kernel)
{
kernel.Bind<IPersonRepository>().To<PersonRepository>();
kernel.Bind<DbContext>().To<MyDbContext>().InThreadScope();
//More registrations...
}
}
.
public class MyDbContext : DbContext
{
public MyDbContext() : base("MyConn")
{
}
}
.
public interface IPersonRepository
{
Task<Person> GetByIdentifierAsync(string identifier);
Task UpdateAsync(Person entity);
//More methods...
}
.
public class PersonRepository : IPersonRepository
{
private readonly DbContext _dbContext;
public PersonRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Person> GetByIdentifierAsync(string identifier)
{
var personList = await _dbContext.Set<Person>().Where(x => x.Identifier == identifier).ToListAsync().ConfigureAwait(false);
//More code...
return personList.SingleOrDefault();
}
public async Task UpdateAsync(Person entity)
{
//More code...
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
.
public class Person
{
public int Id { get; set; }
public string Identifier { get; set; }
//More properties...
}
One option that we noticed is working is to pick up DataContext using Particulars example to use UnitOfWorkSetupBehavior. But it does not fit that well in our scenario because we have a complicated setup with services and repositories injecting the DbContext in the constructor throughout our application.
Ie, the (partial) solution for now is to call the method on the repository like;
var person = await _personRepository.GetByIdentifierAsync(context.DataContext(), message.Identifier).ConfigureAwait(false);
But now, when we run inte more complicated scenarios this won¨t suffice.
So, what are we missing? What is really the issue here?
Ninject PerThreadScope uses System.Threading.Thread.CurrentThread. With async in place the thread can change potentially for every continuation (the code that follows an await statement). You can either use a custom named scope, an async local scope or use the InUnitOfWorkScope from NServiceBus.Ninject.

Refactoring class to make it injectable/mockable

I am really struggling to properly refactor my class so I can inject it.
This is the class I am talking about:
internal class OCRService : IDisposable, IOCRService
{
private const TextRecognitionMode RecognitionMode = TextRecognitionMode.Handwritten;
private readonly ComputerVisionClient _client;
public OCRService(string apiKey)
{
_client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
{
Endpoint = "https://westeurope.api.cognitive.microsoft.com"
};
}
public async Task<List<Line>> ExtractTextAsync(byte[] image)
{
//Logic with _client here
}
}
I really don't know where to Initialize the ComputerVisionClient. I am thinking of the following options:
Make ComputerVisionClient a public property which can be set after injecting.
Putting the apikey in a config file and then read it in the constructor.
The problem is that I want to mock this service but when I mock it it still calls the constructor which connects to the ComputerVisionClient.
Depending on the rest of your architecture, you have a few options. The simplest is to inject the ComputerVisionClient (or IComputerVisionClient if you can create one) into the constructor, and mock it in your tests.
public class OCRService : IOCRService, IDisposable
{
public OCRService(IComputerVisionClient client)
{
_client = client;
}
}
If, for some reason, you must create the client in the constructor, you can create a factory and inject that:
internal class ComputerVisionClientFactory : IComputerVisionClientFactory
{
public GetClient(string apiKey)
{
return new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
{
Endpoint = "https://westeurope.api.cognitive.microsoft.com"
};
}
}
// ...
internal class OCRService : IOCRService, IDisposable
{
public OCRService(string apiKey, IComputerVisionClientFactory clientFactory)
{
_client = clientFactory.GetClient(apiKey);
}
}
As #maccettura suggested, you can also further abstract away the apiKey by creating an IOCRServiceConfiguration that contains the logic for getting the key, and pass that into the constructor for either OCRService or ComputerVisionFactory, depending on your architecture. Naively:
internal class OCRServiceConfiguration : IOCRServiceConfiguration
{
public OCRServiceConfiguration(string apiKey)
{
ApiKey = apiKey;
}
public string ApiKey { get; }
}

Categories

Resources