I am trying to build a microservice that pulls commands and queries off of a queue. My service watches a specific queue and pulls a message off that could be any type command for that domain. That message is pulled off and passed to the dispatcher. My problem is that in trying to make everything as generic as possible, my message is being passed into the dispatcher as an object, but the dispatcher needs a concrete IQuery class. I can cast it to IQuery because I know that it is that type, but when I try to resolve the dependencies in the dispatcher based on the type, it fails because the concrete type is not known. I will try to keep the code samples small and to the point:
Main Service
private static async Task HandleMessageReceived(MessageReceivedEventArgs args) {
await queryDispatcher.Dispatch((IQuery)args.Message.Payload);
}
Query Dispatcher
public class QueryDispatcher : IQueryDispatcher {
#region attributes
private readonly IComponentContext _context;
#endregion
#region ctor
public QueryDispatcher(IComponentContext context) {
_context = context;
}
#endregion
#region methods
public async Task<IEvent> Dispatch<T>(T query) where T : IQuery{
if (query == null) {
return new ArgumentNullEvent(nameof(query));
}
var validator = _context.Resolve<IValidator<T>>();
var handler = _context.Resolve<IQueryHandler<T>>();
List<ValidationResult> errors = await validator.Validate(query);
if(errors.Count == 0) {
return await handler.Handle(query);
} else {
return new ValidationFailedEvent(query.Id, errors);
}
}
#endregion
}
Queue Message
public class QueueMessage {
public Guid OperationId { get; set; }
public object Payload { get; set; }
}
Concrete IQuery Impl
public class GetSite : BaseQuery, IQuery {
public Guid SiteGuid { get; set; }
}
You could build the type using MakeGenericType:
var validator = _context.Resolve(typeof(IValidator<>)
.MakeGenericType(new[] { query.GetType() }));
var handler = _context.Resolve(typeof(IQueryHandler<>)
.MakeGenericType(new[] { query.GetType() }));
Related
I am creating a RESTful api in Net 5, according to the instructions I must create repositories and services that make use of them. The logic must be in the services.
The Services I have are:
SubGroupService
GroupsService
The problem I have is that I generated a circular reference since in GroupsService I need a method of SubGroupsService and SubGroupsService i need a method of GroupsService .
Injecting the GroupsService service into SubGroupsService there is no problem, but injecting SubGroupsService into GroupsService generates the circular reference.
Please can you tell me how to solve this type of problem, since I don't have much experience with dependency injection.
SubGroupService
public class SubGroupService: ISubGroupService
{
private readonly ISubGroupRepository _SubGroupRepository;
private readonly IGroupService _GroupService;
public SubGroupService(
ISubGroupRepository SubGroupRepository,
IGroupService GroupService
{
_SubGroupRepository = SubGroupRepository;
_GroupService = GroupService;
}
public async Task InsertSubGroupService(Subgroup subgroup)
{
var group = await _GroupService.GetGroupService(subgroup.idgroup);
if (group != null)
{
await _SubGroupRepository.InsertSubGroupRepository(subgroup);
}
else
{
throw new BusinessException("This group not exists");
}
}
public async Task<Subgroups> GetSubGroupService(int idgroup)
{
return await _SubGroupRepository.GetSubGroupRepository(idgroup);
}
}
Group Service
public class GroupService : IGroupService
{
private readonly ISubGroupService _SubGroupService;
private readonly IGroupRepository _GroupRepository;
public GroupService(
ISubGroupService SubGroupService,
IGroupRepository GroupRepository)
{
_SubGroupService = SubGroupService;
_GroupRepository = GroupRepository;
}
public async Task<bool> DeleteGroupService(int Idgroup)
{
var existsSubGroup = await _SubGroupRepository(Idgroup);
if(existsSubGroup == null)
{
return await _GroupRepository.DeleteGroupRepository(Idgroup);
}
}
public async Task<Groups> GetGroupService(int Idgroup)
{
return await _GroupRepository.GetGroupRepository(Idgroup);
}
}
Interfaces:
public interface IGroupService
{
Task<Groups> GetGroupsService(int Idgroup);
Task<bool> DeleteGroupService(int Idgroup);
}
public interface ISubGroupService
{
Task<Subgroups> GetSubGroupService(int idsubgrupo);
Task InsertSubgroupService(Subgroup subgroup);
}
You can't use constructor injection in that case. You can switch to property injection:
public class SubGroupService: ISubGroupService
{
private readonly ISubGroupRepository _SubGroupRepository;
public IGroupService GroupService { get; set; }
public SubGroupService(
ISubGroupRepository SubGroupRepository)
{
_SubGroupRepository = SubGroupRepository;
}
// methods of the class
}
public class GroupService : IGroupService
{
public ISubGroupService SubGroupService {get; set;}
private readonly IGroupRepository _GroupRepository;
public GroupService(
IGroupRepository GroupRepository)
{
_GroupRepository = GroupRepository;
}
// methods of the class
}
You'll have to create the objects like this:
IGroupRepository groupRepository = new GroupRepository();
IGroupService groupService = new GroupService(groupRepository);
ISubGroupService subGroupService = new SubGroupService(groupRepository);
groupService.SubGroupSerivce = subGroupService;
subGroupService.GroupService = groupService;
Of course, creation of the objects is now much more complicated. You might put the creation into a facotry method to avoid errors:
public (IGroupService,ISubGroupService) CreateGroupAndSubGroupService()
{
// code from above
}
And it is also advisable to add null checks, because someone might create the objects without initializing the service correctly.
I am using a shared database fixture for my tests, but when running multiple tests at the same time, I get the following error message:
System.InvalidOperationException: A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
This is my code of my Fixture:
public class SharedDatabaseFixture : IDisposable
{
public static readonly object _lock = new object();
private static bool _databaseInitialized;
private const string postgresConnectionString = "Host=localhost;Database=IntegrationTests; Username=postgres;Password=password";
public SharedDatabaseFixture()
{
Connection = new NpgsqlConnection(postgresConnectionString);
Seed();
Connection.Open();
}
public DbConnection Connection { get; }
public AppDbContext CreateContext(DbTransaction transaction = null!)
{
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkNpgsql()
.AddMediatR(typeof(IAggregateRoot).Assembly)
.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>))
.AddDbContext<AppDbContext>(options => options.UseNpgsql(Connection))
.BuildServiceProvider();
ServiceLocator.SetLocatorProvider(serviceProvider);
DomainEvents.Mediator = () => ServiceLocator.Current.GetInstance<IMediator>();
var builder = new DbContextOptionsBuilder<AppDbContext>();
builder.UseNpgsql(Connection).UseInternalServiceProvider(serviceProvider);
var context = new AppDbContext(builder.Options);
if (transaction != null)
{
context.Database.UseTransaction(transaction);
}
return context;
}
private void Seed()
{
lock (_lock)
{
if (!_databaseInitialized)
{
using (var context = CreateContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var appDbContextSeed = new AppDbContextSeed(context);
appDbContextSeed.SeedAsync().Wait();
}
_databaseInitialized = true;
}
}
}
public void Dispose() => Connection.Dispose();
}
The code I am testing uses events and those events do queries to the database. Therefore, I am registering some services and also a DbContext.
The problem is, when I run multiple tests at the same time, events are raised at the same time as well and because they are all using the same DbContext, it throws an exception when two handlers try to use the DbContext at the same time.
So, my question is: how can I instantiate a DbContext for each test (but using the same connection) or prevent it from using the DbContext at the same time?
An Example of one of my tests:
public class Project_Create : IClassFixture<SharedDatabaseFixture>
{
public SharedDatabaseFixture Fixture { get; }
public Project_Create(SharedDatabaseFixture fixture) => Fixture = fixture;
[Fact]
public void Creates_succesfully()
{
var project = new Project(SeedConstants.TEST_COMPANY_ID, "ABC", "Hallo123", "2018-123");
Assert.Equal(SeedConstants.TEST_COMPANY_ID, project.CompanyId);
Assert.Equal("ABC", project.Code);
Assert.Equal("Hallo123", project.Description);
Assert.Equal("2018-123", project.Number);
}
}
Project.cs:
public class Project : BaseEntity<Guid, ProjectValidator, Project>, IAggregateRoot
{
public Guid CompanyId { get; private set; }
public string Code { get; private set; }
public string Description { get; private set; }
public string Number { get; private set; }
public Project(Guid companyId, string code, string description, string number)
{
CompanyId = companyId;
Code = code;
Description = description;
Number = number;
Validate(this);
DomainEvents.Raise(new SetCompanyIdEvent(companyId)).GetAwaiter().GetResult();
}
}
As you can see, this project class raises an event. This event has a handler and looks like this:
public class CheckIfProjectIdExistsHandler : INotificationHandler<SetProjectIdEvent>
{
private readonly IAsyncRepository<Project> _projectRepository;
public CheckIfProjectIdExistsHandler(IAsyncRepository<Project> projectRepository)
{
_projectRepository = projectRepository;
}
public async Task Handle(SetProjectIdEvent notification, CancellationToken cancellationToken)
{
var project = await _projectRepository.GetByIdAsync(notification.ProjectId, cancellationToken);
if (project == null)
{
throw new ProjectDoesNotExistsException($"The project with ID {notification.ProjectId} does not exist.");
}
}
}
I hope this illustrates what I am testing
The answer is always simpler than you think.
When adding the DbContext in the Service Provider, I didn't specify the ServiceLifetime, so it is a singleton by default. Changing this to Transient solves the issue. Then the Connection should also be changed by the connectionString, so there are no multiple operations on the same connection.
So, this line:
.AddDbContext<AppDbContext>(options => options.UseNpgsql(Connection))
Should be change like so:
.AddDbContext<AppDbContext>(options => options.UseNpgsql(postgresConnectionString), ServiceLifetime.Transient)
Also, The registration of the repository should be as Transient and not Scoped.
Long story short, i have following class:
public class FlowBasePipeline<T>
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public void Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
}
public void Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
What I'm looking for is forcing programmer to call Push method in the first place and then give them access to Trigger method, in this case following scenario is not allowed
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Trigger()// Trigger method is not recognized
we should first call Push method
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep()).Trigger()//Now Trigger is recognized
What I've done:
I applied explicit interface method implementation as follows to get it to work:
public interface IBasePipeline<T> where T:BaseResult,new()
{
void Trigger();
IBasePipeline<T> Push(StepBaseBusiness<T> step);
}
public class FlowBasePipeline<T>:IBasePipeline<T> where T:BaseResult,new()
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public IBasePipeline<T> Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
return this;
}
void IBasePipeline<T>.Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
Now it works well and we don't have access to Trigger method before Push method, but from my prospective it's not a good way as we might need more level of orders and i don't know how it could be done in this way.
As i know, method chaining is one of the key rules of functional programming.
Is there any pattern or strategy to implement this kind of chaining?
Update:
we need to call push method multiple times
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();
After first push, push and trigger would be available.
One way to do this is to use interfaces to restrict access to specific methods by specifying an interface as the result.
public interface IStartCar
{
IDriveCar Start(string key);
}
public interface IDriveCar
{
IParkCar Drive(string address);
}
public interface IParkCar
{
IStopCar Park();
}
public interface IStopCar
{
IParkCar Drive(string address);
void Stop();
}
public class Car : IStartCar, IDriveCar, IParkCar, IStopCar
{
public IDriveCar Start(string key);
public IParkCar Drive(string address);
public IStopCar Park();
public IStopCar Park();
private Car() { }
public static IStartCar Get()
{
var result = new Car();
return result;
}
}
Now to get a Car you use the CarFactory method Get(), it returns a car, but you really only have access to the interface result. This pattern only allows developers to string specific methods together:
var car = Car.Get();
car.Start("key").Drive("address1").Park().Drive("address2").Park().Stop();
Example of approach I use for api's that inherently 'guide' the callers with a fluent syntax:
public class Pipeline
{
readonly List<Action> _steps = new List<Action>();
// only Push is available when Pipeline is initialized
public PipelineWithSteps Push(Action step)
{
_steps.Add(step);
// or cache this if you want 'Push' repeatable
return new PipelineWithSteps(this);
}
public class PipelineWithSteps
{
// not required but often the chained context wants/needs access to the first context
readonly Pipeline _context;
// api is public but ctor cannot be invoked by external caller
internal PipelineWithSteps(Pipeline context) => _context = context;
// now Trigger is available only after something was pushed
public PipelineWithSteps Trigger()
{
foreach(var step in _context._steps)
step();
Console.WriteLine();
return this;
}
// usually I don't repeat an initialization method;
// this could be done using the 'context'
// but would have to be refactored to return the existing 'PipelineWithSteps'
public PipelineWithSteps Push(Action step)
{
_context._steps.Add(step);
return this;
}
}
}
Usage:
var pipeline = new Pipeline();
pipeline.Push(() => Console.WriteLine("A"))
.Push(() => Console.WriteLine("B"))
.Trigger()
.Push(() => Console.WriteLine("C"))
.Trigger();
Output:
A
B
A
B
C
After hours ,i came up with this design:
public interface IBasePipelineRegister<T> where T:BaseResult
{
IStagePipeline<T> Push(StepBaseBusiness<T> step);
List<StepBaseBusiness<T>> Steps { get; set; }
}
public interface IBasePipelineTrigger<T> where T:BaseResult
{
void Trigger(T result);
}
public interface IStagePipeline<T>: IBasePipelineTrigger<T>,IBasePipelineRegister<T> where T:BaseResult
{
}
public class FlowBasePipeline<TResult> : IBasePipelineRegister<TResult> where TResult : BaseResult,new()
{
public List<StepBaseBusiness<TResult>> Steps { get ; set ; }
private IStagePipeline<TResult> _stagePipeline;
public BasePipeline()
{
this.Steps = new List<StepBaseBusiness<TResult>>();
this._stagePipeline = new StagePipeline<TResult>(this);
}
public IStagePipeline<TResult> Push(StepBaseBusiness<TResult> step)
{
Steps.Add(step);
return _stagePipeline;
}
}
As you see, BasePipeline just implements IBasePipelineRegister and Register method presents new StagePipeline class that is consist of current class plus trigger implementation.
public class StagePipeline<T>: IStagePipeline<T> where T:BaseResult
{
private readonly IBasePipelineRegister<T> pipelineRegister;
public List<StepBaseBusiness<T>> Steps { get; set; }
public StagePipeline(IBasePipelineRegister<T> pipelineRegister)
{
this.pipelineRegister = pipelineRegister;
Steps = pipelineRegister.Steps;
}
public IStagePipeline<T> Push(StepBaseBusiness<T> step)
{
return pipelineRegister.Push(step);
}
public void Trigger(T result)
{
foreach (var step in Steps)
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
Now each method adds a new feature not replacing new one.
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();
We've improved the performance of our API's adding services without state to .SingleInstance() , but I've a question, regarding the demo code attached,
The IBusAppService that we are using on the controller is set to SingleInstance(), but inside the BusAppService, we are using more Interfaces, for example ( IBusRepository or IBusDomainService )
So the question is, in order to increase the performnace, should we set all interfaces to SingleInstance() inside the IBusAppService or the performance is the same because they are inside a SingleInstance??
I'll attach here some code with the workflow :
The ApiController:
public class BusApiController : ApiController
{
private readonly IBusAppService _iBusAppService;
private readonly IBusMapper _iBusMapper;
public BusApiController(IBusAppService iBusAppService,
IBusMapper iBusMapper)
{
_iBusAppService = iBusAppService;
_iBusMapper = iBusMapper;
}
[HttpGet]
public BusResponse Get(long id)
{
var bus = _iBusAppService.Get(id);
var busResponse = _iBusMapper.Convert(bus);
return busResponse;
}
}
public class BusResponse {
public long Id { get; set; }
}
public interface IBusMapper
{
BusResponse Convert(Bus bus);
}
public class BusMapper : IBusMapper
{
public BusResponse Convert(Bus bus)
{
if (bus == null) return null;
var result = new BusResponse{Id = bus.Id};
return result;
}
}
builder.RegisterType<BusAppService>().As<IBusAppService>().SingleInstance();
builder.RegisterType<BusMapper>().As<IBusMapper>().SingleInstance();
The ApplicationService
public interface IBusAppService
{
Bus Get(long id);
}
public class BusAppService : IBusAppService
{
private readonly IBusRepository _iBusRepository;
private readonly IBusDomainService _iBusDomainService;
public BusAppService(IBusRepository iBusRepository, IBusDomainService iBusDomainService )
{
_iBusRepository = iBusRepository;
_iBusDomainService = iBusDomainService;
}
public Bus Get(long id)
{
var bus = this._iBusRepository.Get(id);
var busTax = this._iBusDomainService.CalculateTax(bus);
var result = bus;
return result;
}
}
Anything consumed by a single instance service will end up being single instance due to captive dependencies. You could change them to be single instance, too, but it won't necessarily change the performance related to instantiation cost that you see now.
I'm looking for a way to keep track of the total time spent on the database, and merge it over one Service Operation call or maybe even an entire session. Since I'm currently using the default PerCall InstanceContextMode, the constructor of the Service class is called every time a service method is called, so I was thinking something like hooking into some pipeline method that is called before and after each service method, calling a non-empty constructor. And then injecting an object to pass further into the hierarchy:
[ServiceContract]
public interface IJobsService { ... }
public partial class JobsService : IJobsService
{
public PerformanceContext PerformanceContext { get; private set; }
JobsService() { ... }
JobsService(PerformanceContext context) : this()
{
RequestContext = context;
}
}
public class PerformanceContext
{
private object syncObj = new object();
private long? userID;
public long? UserID { ... }
public string Source { get; set; }
private long totalTicksUsed = 0;
public long TotalTicksUsed
{
get { return totalTicksUsed; }
private set { totalTicksUsed = value; }
}
public void AddTicksUsed(long ticks, long? userID)
{
Interlocked.Add(ref totalTicksUsed, ticks);
UserID = userID;
}
}
Then I would have the reference of it outside the scope of the service contract, and be able to log it there.
As it is now, the "simplest" way for me to implement this behavior is to call a logging function in the very end of every single service method, but I don't find it very pretty, if there's a better way.
I've tried following Explicitly calling a service constructor when hosting a WCF web service on IIS, Hooking into wcf pipeline and some of the Carlos Figueira MSDN blog: WCF Extensibility, without much success. I'm also having trouble finding much documentation on it general. In other words, I'm stuck.
I am a bit torn between the IOperationInvoker and the IInstanceProvider.
The IOperationInvoker has turned out to be fairly complicated for what I need, since I need to extend both synchronous and asynchronous calls. But it's advantage is that it is specifically made to perform actions before and after each method call. Although I'm still not entirely sure how to pass on an object to any service method, which I can use to track the use, lower in the hierarchy. And Carlos Figueira's blog on WCF Extensibility unfortunately doesn't touch on this in his example (he shows how to cache calls).
The IInstanceProvider turned out to be more simple for me to implement, and also makes it possible to perform actions before and after each operation - as long as the InstanceContextMode is PerCall. If I were to change it to PerSession, I would suddenly perform the actions once per session instead. But in my case, that's acceptable, since the primary objective is to merge the data as much as possible:
One of my Service classes with the custom ServiceBehavior Attribute and inheriting an abstract type that dictates we have a constructor that takes a PerformanceContext:
[ServiceContract]
public interface IJobsService { ... }
[PerformanceInstanceProviderBehavior]
public partial class JobsService : PerformanceMonitoredService, IJobsService
{
public PerformanceContext PerformanceContext { get; protected set; }
JobsService() { ... }
JobsService(PerformanceContext perfContext) : this()
{
PerformanceContext = perfContext;
}
...
}
IInstanceProvider which allows calling a specific constructor and injecting an IExtension into the pipeline, which we can obtain after the Service instance is released:
public class ServiceInstanceProvider : IInstanceProvider
{
public Type ServiceType { get; set; }
public ServiceInstanceProvider(Type serviceType) { ServiceType = serviceType; }
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
var perfContext = new PerformanceInstanceContext();
instanceContext.Extensions.Add(new PerformanceInstanceExtension(perfContext));
return ServiceFactory.Create(ServiceType, perfContext);
//return new JobsService(perfContext);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
var perfContext = (instanceContext.Extensions.FirstOrDefault(ice =>
ice is PerformanceInstanceExtension)
as PerformanceInstanceExtension
)?.PerformanceContext;
//Handle the object which has been through the pipeline
//Note (IErrorHandler):
//This is called after "ProvideFault", but before "HandleError"
}
}
The IServiceBehavior and Attribute that will be added to all services that needs a PerformanceContext injected.
public class PerformanceInstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
//Each Service Type is getting their own InstanceProvider,
//So we can pass the type along,
//and let a factory create the appropriate instances:
ed.DispatchRuntime.InstanceProvider =
new ServiceInstanceProvider(serviceDescription.ServiceType);
}
}
}
}
...
}
The IExtension that we can attach to the InstanceContext through the instance provider pipeline:
public class PerformanceInstanceExtension : IExtension<InstanceContext>
{
public PerformanceInstanceExtension()
{
PerformanceContext = new PerformanceContext();
}
public PerformanceInstanceExtension(PerformanceContext perfContext)
{
PerformanceContext = perfContext;
}
public PerformanceContext PerformanceContext { get; private set; }
public void Attach(InstanceContext owner) {}
public void Detach(InstanceContext owner) {}
}
The abstract service type that should allow this injection:
public abstract class PerformanceMonitoredService
{
public abstract PerformanceContext PerformanceContext { get; protected set; }
public PerformanceMonitoredService() {}
public PerformanceMonitoredService(PerformanceContext perfContext) {}
}
A factory for services that inherit PerformanceMonitoredService:
public class PerformanceServiceFactory
{
private static ConcurrentDictionary<Type, ConstructorInfo> Constructors
= new ConcurrentDictionary<Type, ConstructorInfo>();
public static object Create(Type type, PerformanceContext perfContext)
{
ConstructorInfo ctor;
if(Constructors.TryGetValue(type, out ctor))
{
return InvokeConstructor(ctor, perfContext);
}
else if (type.IsSubclassOf(typeof(PerformanceMonitoredService))
||type.IsAssignableFrom(typeof(PerformanceMonitoredService)))
{
ConstructorInfo newCtor = type.GetConstructor(
new[] { typeof(PerformanceContext) }
);
if(Constructors.TryAdd(type, newCtor))
{
return InvokeConstructor(newCtor, perfContext);
} else if(Constructors.TryGetValue(type, out ctor))
{
return InvokeConstructor(ctor, perfContext);
}
}
throw new ArgumentException(
$"Expected type inheritable of {typeof(PerformanceMonitoredService).Name}"}",
"type");
}
private static object InvokeConstructor(ConstructorInfo ctor,
PerformanceContext perfContext)
{
return ctor.Invoke(new object[] { perfContext });
}
}