Regarding to this topic and answer I have adapters for my async services registrations :
Async provider in .NET Core DI
And it looks very fine. But I have some services, where I have properties in interface. Properties cant be async, but I need to await client object : var client = await this.connectedClient.Value;
I mean I cant use public bool Connected => (await this.connectedClient.Value).Connected;
What should I do in this case?
public interface IMyAppService
{
bool Connected{ get; }
string Host{ get; }
Task<Data> GetData();
Task SendData(Data data);
}
PS : I dont want to .Result and .GetAwaiter().GetResult() etc. I know Its potentially deadlock there
Given the adapter structure suggested by Steven in the linked question, you can simply implement the Connected property as:
public bool Connected => this.connectedClient.IsValueCreated;
but in the general case, there is no way to run code asynchronously in a property getter or setter.
Related
This question asks about how to retrieve all users from AspNetCore Identity, in an async method:
ASP.NET Identity 2 UserManager get all users async
The non-sync method is simple:
[HttpGet]
public ActionResult<IEnumerable<UserDto>> GetAsync()
{
var users = userManager.Users
.ToList()
.Select(user => user.AsDto());
return Ok(users);
}
The obvious solution is this:
[HttpGet]
public async Task<ActionResult<IEnumerable<UserDto>>> GetAsync()
{
var users = await userManager.Users
.ToListAsync()
.Select(user => user.AsDto());
return Ok(users);
}
But this doesn't work because userManager.Users is an IQueryable<>, and that doesn't define a .ToListAsync().
The recommended answer in the question above is:
public async Task<List<User>> GetUsersAsync()
{
using (var context = new YourContext())
{
return await UserManager.Users.ToListAsync();
}
}
But that is tied to Entity Framework, and if you're using AspNetCore.Identity.MongoDbCore, you won't have any dbcontexts, and the above simply doesn't work.
One comment on the answer points out that the .ToListAsync() extension method is defined in System.Data.Entity - but if you're using MongoDb you won't be including that.
How, actually, do you access all users from UserManager<> in an async method?
Basiccally, AspNetCore.Identity.MongoDbCore was just implementation wrapping around core concept of AspNetCore.Identity. And things gone just a bit difference from Sql implementation, cause they doesn't make use of unit of work concept (I know, SaveChange implement would wrap operation in transaction, but for everymethod call, the query execute immediately got this pretty similar to mongo in someway).
Then, If we need any furthur extension of those basic task, why don't just write our own implementation on top of default MongoDbCore implementation like good old days ?
// Starting with UserStore
public class ApplicationUserStore : MongoUserStore<How many generic would depend on use cases>, IApplicationUserStore
{
protected IMongoCollection<TUser> ApplicationUsersCollection;
public ApplicationUserStore(ApplicationDbContext context, IdentityErrorDescriber describer = null) : base(context, describer)
{
ApplicationUsersCollection = Context.GetCollection<TUser>();
}
public async Task<ICollection<ApplicationUser>> GetAllUserAsync() => // We have access to UsersCollection, implement as normal mongodb operation;
}
// Then, UserManager
public class ApplicationUserManager : UserManager<How many generic would depend on use cases>
{
private readonly IApplicationUserStore _applicationUserStore;
// Constructtor that could resolve our ApplicationUserStore.
public ApplicationUserManager(IApplicationUserStore applicationUserStore,...)
{
_applicationUserStore = applicationUserStore;
}
public async Task<ICollection<ApplicationUser>> GetAllUserAsync() => _applicationUserStore.GetAllUserAsync();
// Registering things
services.AddScoped<IApplicationUserStore, ApplicationUserStore>();
services.AddScoped<ApplicationUserManager>();
}
This was just describe the idea, implementation should be vary.
Hello i am developing a ASP NET Core application having an issue with designing interfaces.I am using serilog and when a request enters a controller it gets a GUID .I am trying to find an elegant way to track individual requests deep in calls without including this GUID in all my interfaces.
public interface IService
{
Task GetSomething(string corellationId); //how do i get rid of this id
}
public interface ISomeOtherService
{
Task DoSomethingElse(string corellationId); //how do i get rid of this id
}
public class SomeController:Controller
{
public IService someService {get;set;}
[HttpGet]
public Task Get()
{
string corellationId=Guid.NewGuid().ToString();
Log.Information($"[{corellationId}] - Request started");
try
{
Log.Information($"[{corellationId}] - Get");
await this.someService.GetSomething(corellationId);
}catch(Exception ex)
{
Log.Error($"[{corellationId}] - Get",ex.Message);
}
}
}
public SomeService:ISomeService
{
private ISomeOtherService service{get;set;}
public GetSomething(corellationId)
{
Log.Information("$[{corellationId}] - GetSomething: ");
this.service.DoSomethingElse(corellationId);
}
}
As you can see if i have some deep calls i would need to change all interfaces so that they all include the corellationId which is the GUID that was set when the request entered my controller.
Is there any way of tracking individual requests throughout calls without passing this GUID from layer to layer?
You can use LogContext.PushProperty - this uses AsyncLocal under the hood so multi-threaded scenario is no concern.
For more info check this link
If you call Serilog.AspNetCore's UseSerilog(), and Enrich.FromLogContext() on your LoggerConfiguration, then ASP.NET Core will assign an (effectively) GUID RequestId property for each request, and this will be attached to all events raised during the request automatically, including in deep calls.
I am interested in the architectural solution of the following moment.
I have:
public class GenericRepository<T> : IDisposable {
public GenericRepository(ISession session){
_session = session;
};
public T InsertAsync(T entity){...};
public IQueryable<T> Read(){...};
public T UpateAsync(T entity){...};
public void DeleteAsync(T entity){...};
public Task Commit(){
return _session.Transaction.Commit();
};
public void Dispose(){
if(_session.Transaction.IsActive){
_session.Transaction.Rollback();
}
};
}
public class UserService{
public UserService(GenericRepository<User> repository){...}
public long CreateUser(string userName){
...
_repository.Commit(); // [1]
};
}
public class OrganizationService{
public OrganizationService(GenericRepository<Organization> repository){...}
public int CreateOrganization(string code){
...
_repository.Commit(); // [2]
};
}
The following registration is used:
services.AddScoped<ISession>(x => x.GetRequiredService<NHSessionProvider>().OpenSession());
services.AddScoped(typeof(GenericRepository<>));
services.AddScoped<UserService>();
services.AddScoped<OrganizationService>();
These CreateOrganization and CreateUser can be used independently in any parts of the code:
public IActionResult Post([FromServices] OrganizationService service, [FromBody] string code){
service.CreateOrganization(code);
return Ok();
}
public IActionResult Post([FromServices] UserService service, [FromBody] string userName){
service.CreateUser(userName);
return Ok();
}
However, now I have a new service:
public class MyBillingService{
public MyBillingService(GenericRepository<Contractor> repository, OrganizationService organizationService, UserService userService){...}
public int CreateNewContractor(string organizationCode, string userName){
...
_organizationService.CreateOrganization(organizationCode);
...
_userService.CreateUser(userName);// [3]
...
_repository.Commit(); // [4]
}
}
In this implementation, CreateOrganization and CreateUser have their own transactions, and if [3] throws an exception, then the organization will be created anyway.
Ok, because ISession is registered as Scoped, then I can delete _repository.Commit from CreateOrganization and CreateUser([1] and [2]). In this case, [4] will be responsible for committing all changes.
But what then to do when OrganizationService and UserService are used independently? After all, now they have become non-independent services and cannot save data without delegating the commit of changes to some other service:
public IActionResult Post([FromServices] UserService service, [FromServices] TransactionService transaction, [FromBody] string userName){
service.CreateUser(userName);
transaction.Commit();
return Ok();
}
As far as this decision is a good one?
Transactions requires a unit of work. There is no other way to coordinate repositories. The reason you're facing issues here is that your entire design is wrong.
First and foremost, you should not have these repositories at all. You're using EF Core, which is an ORM, and already implements the repository and unit of work patterns. Using an ORM is opting to use a third-party library for your DAL. Wrapping your own DAL layer around that is pointless and imposes needless maintenance and testing costs on your application with zero benefit. Your services should depend on your context directly.
Then, services should be self-contained units of functionality. If they depend on other services, you're doing it wrong. The service should correspond with a particular subdomain of your application. If users and organization need to be managed together transactionally, then you should have one service that encompasses both.
Alternatively, if you want/need to keep the two separate, then you would need to incorporate the concept of sagas.
So I've started to move more towards what Chris mentioned in his answer and use the ISession directly, but I have used a generic repository in the past. Your repos can't correctly handle transactions that are already started.
So my generic repo has a couple of methods
protected virtual TResult Transact<TResult>(Func<TResult> func)
{
if (_session.Transaction.IsActive)
return func.Invoke();
TResult result;
using (var tx = _session.BeginTransaction(IsolationLevel.ReadCommitted))
{
result = func.Invoke();
tx.Commit();
}
return result;
}
protected virtual void Transact(System.Action action)
{
Transact(() =>
{
action.Invoke();
return false;
});
}
Then the methods that are implementing the repo functionality look like this
public bool Remove(T item)
{
Transact(() => _session.Delete(item));
return true;
}
This allows the method to use an existing Transaction if it is already started, otherwise create your transaction for this work.
You also should not have a Dispose in your repo since you don't own the reference to ISession. It's life cycle should be handled by whoever created that instance.
The generic repository also shouldn't have commit functionality except when it is explicitly starting a new transaction. So now you need to have something that handles starting and committing said transaction. In a web scenario you are typically in a session per request scenario. This would mean you are creating your session in BeginRequest and disposing of it in EndRequest. I then use a transaction attribute to manage creating transactions prior to executing the controller action and commit/rollback after the execution of the controller method.
I use the CQS pattern in my asp.net core project. Let's start with an example to better explain what I want to achieve. I created a command:
public class EmptyCommand : INotification{}
The command handler:
public class EmptyCommandHandler : INotificationHandler<EmptyCommand>
{
public Task Handle(EmptyCommand notification, CancellationToken cancellationToken)
{
return Task.FromResult(string.Empty);
}
}
The query:
public class EmptyQuery : IRequest<string>{}
The query handler:
public class EmptyQueryHandler : IRequestHandler<EmptyQuery, string>
{
public Task<string> Handle(EmptyQuery notification, CancellationToken cancellationToken)
{
return Task.FromResult(string.Empty);
}
}
and this is a simple example of how to run the command and query and invoke the Handle method from the EmptyCommandHandler and EmptyQueryHandler:
readonly IMediator _mediator;
public HomeController(IMediator mediator)
{
_mediator = mediator;
}
public async Task<IActionResult> Index()
{
await _mediator.Publish(new EmptyCommand());
var queryResult = await _mediator.Send(new EmptyQuery());
return View();
}
Please bear in mind that query can return other types not necessarily the string.
I would like to create some kind of a bridge class e.g. MediatorBoostrapper, which allows me to run some business logic(e.g. log command/query via Logger) every time the Publish method is invoked and then
invoke the public Task Handle(EmptyCommand notification,... method from the command handler. The solution must be generic, so this method would be invoked every time I run the Publish method. I also want to be able to do the same thing for the Send method.
I was thinking about the creation of the public class MediatorBoostrapper : IMediator
but not sure what should be a proper implementation of the class and if my idea is good.
Any ideas? Cheers
Edit
I want to have an example of how to use the Behaviors
to create a generic way to run some external method from the generic handler every time I Run the Send method for queries. I want to have a similar example for Publish method, which I use for sending commands.
I want to have an example of how to use Polymorphic dispatch
for the creation of the GenericCommandHandler and a GenericQueryHandler
I created a sample project on GitHub which can be found here
You can feel free to try to extend this project with your solution.
This time I want to answer the question starting from the end.
2.
TL;DR Polymorphic Dispatch cannot be used for the CQS
After some time of playing with the MediatR library, reading the comments under my Question and consultation with my friend, I found the Polymorphic Dispatch(PD) can be used to create a generic handler only in case of the Commands. The PD solution cannot be implemented for Queries. Based on the Documentation, the handlers are contravariant and not covariant. This means the PD works only in the case where the TResponse is a constant type. In case of the Queries, this is false and each Query handler can return a different result.
I also found this issue. I think it's interesting to know you can use the Polymorphic Dispatch only if your container supports it.
1. Behaviors is the one and only solution for CQS when using the MediatR.
Based on the comment under my question from #Steve and comment from jbogard I've found the way how to use Behaviors and IRequestHandler for the strict Command pattern. The full comment:
Just to summarize the changes, there are 2 main flavors of requests:
those that return a value, and those that do not. The ones that do not
now implement IRequest<T> where T : Unit. This was to unify requests
and handlers into one single type. The diverging types broke the
pipeline for many containers, the unification means you can use
pipelines for any kind of request.
It forced me to add the Unit type in all cases, so I've added some helper classes for you.
IRequestHandler<T> - implement this and you will return Task<Unit>.
AsyncRequestHandler<T> - inherit this and you will return Task.
RequestHandler<T> - inherit this and you will return nothing (void).
For requests that do return values:
IRequestHandler<T, U> - you will return Task<U>
RequestHandler<T, U> - you will return U
I got rid of the AsyncRequestHandler because it really wasn't doing anything after the consolidation, a redundant base class.
The example
a) The Commands management:
public class EmptyCommand : IRequest{...}
public class EmptyCommandHandler : RequestHandler<EmptyCommand>
{
protected override void Handle(EmptyCommand request){...}
}
b) The Queries management:
// can be any other type not necessarily `string`
public class EmptyQuery : IRequest<string>{...}
public class EmptyQueryHandler : IRequestHandler<EmptyQuery, string>
{
public Task<string> Handle(EmptyQuery notification, CancellationToken cancellationToken)
{
return Task.FromResult("Sample response");
}
}
c) The sample LogginBehavior class:
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var requestType = typeof(TRequest).Name;
var response = await next();
if (requestType.EndsWith("Command"))
{
_logger.LogInformation($"Command Request: {request}");
}
else if (requestType.EndsWith("Query"))
{
_logger.LogInformation($"Query Request: {request}");
_logger.LogInformation($"Query Response: {response}");
}
else
{
throw new Exception("The request is not the Command or Query type");
}
return response;
}
}
d) To register the LoggingBehavior add the command
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
to the body of the ConfigureServices method in the Startup.cs.
e) The example of how to run sample command and query:
await _mediator.Send(new EmptyCommand());
var result = await _mediator.Send(new EmptyQuery());
MediatR supports dispatching notifications to generic handlers (polymorphic dispatch). For example:
public class GenericHandler<TNotification> : INotificationHandler<TNotification>
where TNotification : INotification
{
public Task Handle(TNotification notification, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
This handler will be invoked for every notification that is published through Publish(). The same is true for requests (queries/commands). You should also take a look at behaviors.
If you're using MediatR with ASP.NET Core I suggest you use the MediatR.Extensions.Microsoft.DependencyInjection library which takes care of wiring all the handlers together.
Let's say I have an interface:
interface ILoader()
{
Task<Data> LoadAsync(int id);
}
I have two implementations of this interface:
class NiceDataBase : ILoader
{
public async Task<Data> LoadAsync(int id)
{
//this database has async way of fetching the data
return await NiceDataBaseDriver.LoadDataAsync(id);
}
}
class NotNiceDataBase : ILoader
{
public async Task<Data> LoadAsync(int id)
{
//this database's driver does not have aysnc methods, because it's old or done poorly.
return await Task.Run(() => NotNiceDataBaseDriver.LoadData(id));
}
}
The NotNiceDataBase doesn't provide real async way to load the data, that's why I actually run it on a new thread, which, as I understand, is not really async, because real async does not use a new thread. Is my implementation of NotNiceDataBase a good one then? It kind of cheats the user to think that he is running a real async operation.
What is the optimal way to deal with such situation? I think that the client of NotNiceDataBase should be completely aware what he is doing, otherwise he can't control performance of hiw application well.
My interface could have additional Load method. But in such case, what's the real benefit here? Still LoadAsync of NotNiceDataBase would need to have some implementation. Throwing NotImplementedException is never a good solution I think.
As you know async is an implementation detail and you can not define async on interfaces. So all you have to do is
public class NotNiceDataBase : ILoader
{
public Task<Data> LoadAsync(int id)
{
//this database's driver does not have aysnc methods, because it's old or done poorly.
var result = NotNiceDataBaseDriver.LoadData(id);
return Task.FromResult(result);
}
}
Simply run the method synchronously and return a completed task
e.g.
class NotNiceDataBase : ILoader
{
public Task<Data> LoadAsync(int id)
{
var data = NotNiceDataBaseDriver.LoadData(id);
return Task.From(data);
}
}
You say
I think that the client of NotNiceDataBase should be completely aware
what he is doing, otherwise he can't control performance of hi(s)
application well.
I disagree, if performance is an issue and if they've identified that it's the call to NotNiceDataBase then they can do something about it.
elaboration
Time worrying about how the client is using the interface is almost certainly1 time wasted, and isn't even "premature optimization" but is existential angst over someone else's unknown optimization needs.
1Unless you are your own client, then it's still probably time wasted.