IDistributedCache call a constructor with injection - c#

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

Related

Passing IHttpClientFactory into class

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

(Interface) A circular dependency was detected for the service of type

I have 2 interfaces:
public interface IPedidoService
{
UsuarioDrogueria CUsuarioDrogueria(string userId, int idDrogueria);
List<PedidoComboProducto> CPedidosCombosProductos(int idcombo, int idPedido);
}
public interface IEmailService
{
void SendEmailAttachment(string email, string subject, string archive);
void SendNotificationEmail(List<Pedido> pedidos, string email, Drogueria drog);
void SendNotificationEmailADM(Pedido pedido) ;
}
I want to use the functions from IEmailService inside IPedidoService, so I inject it in its constructor when I create the respository.
public class PedidoService : IPedidoService
{
private readonly IEmailService emailService;
public PedidoService(IEmailService e)
{
this.emailService = e;
}
}
Up until here everything works fine, but when I try to do reverse the roles (IPedidoService functions inside IEmailService):
public class EmailService : IEmailService
{
private readonly IPedidoService pedidoSettings;
public EmailService(IPedidoService p)
{
this.pedidoSettings = p;
}
}
I end up getting this exception:
System.InvalidOperationException: A circular dependency was detected for the service of type
'EnvioPedidos.Data.Abstract.IPedidoService'.
EnvioPedidos.Data.Abstract.IPedidoService(EnvioPedidos.PedidoService) ->
EnvioPedidos.Data.Abstract.IEmailService(EnvioPedidos.EmailService) ->
EnvioPedidos.Data.Abstract.IPedidoService
Can anybody help me trace the issue here?
A simple way is to use Lazy<T> class which is based on this blog:
Custom extension method:
public static class LazyResolutionMiddlewareExtensions
{
public static IServiceCollection AddLazyResolution(this IServiceCollection services)
{
return services.AddTransient(
typeof(Lazy<>),
typeof(LazilyResolved<>));
}
}
public class LazilyResolved<T> : Lazy<T>
{
public LazilyResolved(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService<T>)
{
}
}
Configure in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//services.AddSingleton<IPedidoService, PedidoService>();
//services.AddSingleton<IEmailService, EmailService>();
services.AddLazyResolution();
}
Change your implements class:
public class PedidoService : IPedidoService
{
private readonly Lazy<IEmailService> emailService;
public PedidoService(Lazy<IEmailService> e)
{
this.emailService = e;
}
//...
}
public class EmailService : IEmailService
{
private readonly Lazy<IPedidoService> pedidoSettings;
public EmailService(Lazy<IPedidoService> p)
{
this.pedidoSettings = p;
}
//...
}
When you have 2 classes, they cannot reference each other by dependency injection. This is called a circular dependency, as shown by your error. You need a 3rd class that references both services and you can use the methods there.
public class PedidoService
{
public PedidoService()
{
}
}
public class EmailService
{
public EmailService()
{
}
}
public class Container
{
private readonly EmailService emailService;
private readonly PedidoService pedidoService;
public Container(EmailService emailService, PedidoService pedidoService)
{
this.emailService = emailService;
this.pedidoService = pedidoService;
}
//use the services here
}

use mediator cqrs in TDD for integration test .net core 3

i use Mediator in my project .
Demo Project on Github
i want to use TDD in my project and integration test with .Net core 3.0
i write this code int test class for use intergration test with mediator :
public class SubscribeTest : IClassFixture<TravelRequest<Startup>>, IClassFixture<DbContextFactory>, IDisposable
{
private readonly TravelRequest<Startup> request;
private readonly DbContextFactory contextFactory;
public SubscribeTest(TravelRequest<Startup> request , DbContextFactory contextFactory)
{
this.request = request;
this.contextFactory = contextFactory;
}
public void Dispose()
{
request.Dispose();
}
[Fact]
public async Task ListSubscribeAsync()
{
var add = await request.Get("/Subscribe/GetListSubscribe");
await add.BodyAs<SubscribListDto>();
}
}
and this is TravelRequest :
public class TravelRequest<TStartup> : IDisposable where TStartup : class
{
private readonly HttpClient client;
private readonly TestServer server;
public TravelRequest()
{
var webHostBuilder = new WebHostBuilder().UseStartup<TStartup>().UseConfiguration(ConfigorationSingltonConfigoration.GetConfiguration());
this.server = new TestServer(webHostBuilder);
this.client = server.CreateClient();
}
}
and this is ConfigorationSingltonConfigoration for use the appSetting-test.json :
public class ConfigorationSingltonConfigoration
{
private static IConfigurationRoot configuration;
private ConfigorationSingltonConfigoration() { }
public static IConfigurationRoot GetConfiguration()
{
if (configuration is null)
configuration = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Path.GetFullPath("../../../")))
.AddJsonFile("appsettings-test.json")
.AddEnvironmentVariables()
.Build();
return configuration;
}
}
and finally this is for set DbContext :
public class DbContextFactory : IDisposable
{
public TravelContext Context { get; private set; }
public DbContextFactory()
{
var dbBuilder = GetContextBuilderOptions<TravelContext>("SqlServer");
Context = new TravelContext(dbBuilder.Options);
Context.Database.Migrate();
}
public void Dispose()
{
Context.Dispose();
}
public TravelContext GetRefreshContext()
{
var dbBuilder = GetContextBuilderOptions<TravelContext>("SqlServer");
Context = new TravelContext(dbBuilder.Options);
return Context;
}
private DbContextOptionsBuilder<TravelContext> GetContextBuilderOptions<T>(string connectionStringName)
{
var connectionString = ConfigorationSingltonConfigoration.GetConfiguration().GetConnectionString(connectionStringName);
var contextBuilder = new DbContextOptionsBuilder<TravelContext>();
var servicesCollection = new ServiceCollection().AddEntityFrameworkSqlServer().BuildServiceProvider();
contextBuilder.UseSqlServer(connectionString).UseInternalServiceProvider(servicesCollection);
return contextBuilder;
}
}
Now my problem is here , when i RunTest in result it show me this error :
---- System.InvalidOperationException : Unable to resolve service for type 'System.Collections.Generic.IList1[FluentValidation.IValidator1[Travel.Services.SubscribeServices.Query.SubscribeList.SubscribeListCommand]]' while attempting to activate 'Travel.Common.ValidateBehavior.ValidateCommandBehavior2[Travel.Services.SubscribeServices.Query.SubscribeList.SubscribeListCommand,Travel.Common.Operation.OperationResult1[System.Collections.Generic.IEnumerable`1[Travel.ViewModel.SubscibeDto.SubscribListDto]]]'. ---- System.NotImplementedException : The method or operation is not implemented.
whats the problem ? how can i solve ths problem ??? i put the source code of project in top of question
I suspect that the validators are not registered into the container.
You can use the FluentValidation in .NET Core with Dependency Injection, by installing the nuget and than passing the assembly.
More references at Using FluentValidation in .NET Core with Dependency Injection.
More reference of how you can do this at Fluent Validation on .NET Core 2.0 does not register.

How to set a readonly property in a C# async constructor

I have a service in an ASP .Net Core 2.2 Web API. The constructor is async because it calls an async method. But because the constructor is async, it's complaining about trying to initialize a property.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public async Task MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
await DoSomething();
}
}
It gives me this error:
"A readonly field cannot be assigned to (except in a constructor or a variable initializer)"
Any ideas?
As users mentioned in the comments above, I was mistaken to think that I could make a constructor async.
Mathew Watson and Stephen Cleary provided me with a link with a good alternative to my problem: https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
Summary:
Factory Pattern
Use a static creation method, making the type its own factory:
public sealed class MyClass
{
private MyData asyncData;
private MyClass() { ... }
private async Task<MyClass> InitializeAsync()
{
asyncData = await GetDataAsync();
return this;
}
public static Task<MyClass> CreateAsync()
{
var ret = new MyClass();
return ret.InitializeAsync();
}
}
public static async Task UseMyClassAsync()
{
MyClass instance = await MyClass.CreateAsync();
...
}
One common example to solve your problem is to create a static method on the class and call the async method from there and well as the constructor.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public static async Task<MyService> BuildMyService(IServiceScopeFactory serviceScopeFactory)
{
await DoSomething();
return new MyService(serviceScopeFactory);
}
public MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
}
}

How to resolve a dependency at runtime with parameters?

I have a simple interface ICloudStorageRepository which is implemented by two concrete classes:
public class AWSStorageRepository : ICloudStorageRepository
{
private readonly IS3Client _client;
public AWSStorageRepository(AWSCredentials credentials)
{
_client = new AWSStorageFactory(credentials).Create();
}
}
and:
public class AzureStorageRepository : ICloudStorageRepository
{
private readonly IAzureClient _client;
public AzureStorageRepository(AzureCredentials credentials)
{
_client = new AzureStorageFactory(credentials).Create();
}
}
then in my client I have a service:
public class CloudService
{
public CloudService(ICloudStorageRepository repository)
....
public Task<ListFiles> GetFiles(GetFilesInput input)
{
if(input.Provider == 'aws')
resolve with AWSStorageRepository
if(input.Provider == 'azure')
resolve with AzureStorageRepository
}
}
I'm using Castle Windsor as container, I'll get the credentials at runtime within the input parameter, just to use once, so I need to pass it as the argument dependency.
How can i do it in runtime without registering it on container?

Categories

Resources