It is a good practice to have a simple methods, which returns tasks:
public class MessageService : IMessageService
{
public Task<IEnumerable<Message>> DownloadMessagesTask()
{
return MyWebClient.GetMessages();
}
Now, I'd like to add a caching to the local storage:
public Task<bool> WriteMessagesTask(IEnumerable<Message> list)
{
return MyIsoStorageManager.Write(list);
}
// same for reading
Most naive way is to call them from viewmodel:
public async void Init()
{
var result = await messageService.ReadMessagesTask();
if (result == null)
{
MessagesList = await messageService.DownloadMessagesTask();
var writingResult = await messageService.WriteMessagesTask(MessagesList);
}
But how can I store this logic in a service, just to avoid code repeating in another viewmodels? Or should I keep service clean and call tasks in a viewmodel?
Expose one method from your service that wraps what you now have in you async void Init() and call it from VM. You could also extract interface and inject that in your viewmodel (via constructor or property).
META
public class MyViewModel
{
public MyViewModel()
:this(new Service())
{}
public MyViewModel(IService service)
{
Service = service;
Initialize();
}
public IService Service { get; set; }
private async void Initialize()
{
// Fire forget
await Service.DoSomething();
}
}
META
public interface IService
{
// change if you need to return something
Task DoSomething();
}
public Service : IService
{
public async Task DoSomething()
{
var result = await ReadMessagesAsync();
if (result == null)
{
var messages = await DownloadMessagesAsync();
await WriteMessagesAsync(messages);
}
}
// private read/write/download methods here...
}
Maybe you cold split these methods into some helper classes and use them in viewmodels as you see fit. Or if you already have some base viewmodel class (for INotifyPropertyChanged for example) you could move them there, assuming they are mainly for viewmodels.
Get rid of the void after async. Because it is "fire and forget", you essentially start the method but have no control over when it is completed. In some cases it is ok, but avoid it if you can.
Related
In the Call asynchronous method in constructor? question is no answer that, starts the async Operation in the constructor and store the Task in a member and an awaits it before using the resource:
public class DeviceAccess
{
private readonly Task<Container> containerTask;
public DeviceAccess(Database database)
{
containerTask = GetContainer(database);
}
private async Task<Container> GetContainer(Database database)
{
var conatinerResponse = await database.CreateContainerIfNotExistsAsync("Device");
return conatinerResponse.Container;
}
public async Task<Device> GetDevice(string deviceId)
{
var container = await containerTask;
return await doSomething(container);
}
}
In my case every Operation needs the resource, so I see no advantage to use some lazy loading.
Is it valid to start a async Operation in a constructor or can result this into problems?
The biggest problem I can see here is that [Value]Task[<T>] is an API that enables async, not a promise to be async; just because CreateContainerIfNotExistsAsync is named *Async and returns Task<T> - that doesn't actually mean it is async - it could run synchronously and return a result via Task.FromResult (aka "async over sync"). If you're not concerned about that problem, then fine I guess. But I wonder whether an OpenAsync() method that you call after construction would be more appropriate, i.e.
public class DeviceAccess
{
private Container _container;
public DeviceAccess() {}
public async ValueTask OpenAsync(Database database) {
if (_container == null)
_container = await GetContainerAsync(database);
}
public async Task<Device> GetDeviceAsync(string deviceId)
{
var container = _container ?? throw new InvalidOperationException("not open");
return await doSomething(container); // might be able to inline the "await" here
}
}
I have a microservices architecture using simple injector in each service. The services communicates through Azure Service Bus. I'm currently trying to find a way to implement a generic solution/library for interacting with Azure Service Bus. The library is the core infrastructure of the services and has a topic publisher (for pushing events /messages to azure) and a subscriber (for listening to messages from azure).
Besides that I have a common interface for the events /messages containing an ID and time stamp for creation. I also have a generic interface for event handlers IEventHandler<T> where T : IEvent. Now my problem is, how do I best keep my composition root separated from the rest of the code while still being able to register a set of handlers for the different types of events in a given service?
Reading the docs for simple injector suggests a factory or something like that, but my interface is generic and the factory is not which makes public IEventHandler GetHandler (Type eventType) illegal...
UPDATE: Added code
Publishing:
public interface IEventPublisher
{
Task PublishAsync(IEvent #event);
}
public class EventPublisher : IEventPublisher
{
private readonly ITopicClient topicClient;
public EventPublisher(ITopicClient topicClient)
{
this.topicClient = topicClient;
}
public async Task PublishAsync(IEvent #event)
{
try
{
var json = JsonConvert.SerializeObject(#event);
var message = new Message()
{
Body = Encoding.UTF8.GetBytes(json),
PartitionKey = nameof(#event),
MessageId = #event.Id.ToString()
};
message.UserProperties.Add("Type", #event.GetType().FullName);
await topicClient.SendAsync(message);
}
catch (Exception e)
{
//Handle error
}
}
}
Handling events:
public interface IEventHandler<T> where T : IEvent
{
void HandleEvent(T #event);
}
public interface IEventSubscriber
{
//Currently empty, might need some method for registration of handlers?
}
public class EventSubscriber : IEventSubscriber
{
private readonly ISubscriptionClient subscriptionClient;
public EventSubscriber(ISubscriptionClient subscriptionClient, )
{
this.subscriptionClient = subscriptionClient;
var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
AutoComplete = false
};
this.subscriptionClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);
}
private Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
{
var context = exceptionReceivedEventArgs.ExceptionReceivedContext;
logger.Error($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}.");
logger.Error("Exception context for troubleshooting:");
logger.Error($"- Endpoint: {context.Endpoint}");
logger.Error($"- Entity Path: {context.EntityPath}");
logger.Error($"- Executing Action: {context.Action}");
return Task.CompletedTask;
}
private async Task ProcessMessagesAsync(Message message, CancellationToken cancellationToken)
{
JsonConvert.DeserializeObject<BankDataChangedEvent>(Encoding.UTF8.GetString(message.Body));
// HERE I NEED SOME CODE TO FETCH/FIND THE RIGHT HANDLER FOR THE EVENT TYPE
await subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
}
}
Most of the pulisher and subscriber are boilerplate code from Microsoft docs for Azure Service Bus with .Net - only slightly modified.
Maybe I know what do you want.
Do you have something like this?
internal sealed class CommonEventConsumer :
IConsumer<Event1>,
IConsumer<Event2>
{
private readonly ISomeService _someService;
public CommonEventConsumer(ISomeService someService)
{
_someService = someService;
}
public async Task HandleEventAsync(Event1 eventMessage)
{
await _someService.DoSomeThing1(eventMessage);
}
public async Task HandleEventAsync(Event2 eventMessage)
{
await _someService.DoSomeThing2(eventMessage);
}
}
where IConsumer<Tevent> is global interface which has method HandleEventAsync(Tevent event message); and CommonEventConsumer is average consumer in any of your microservice.
Also the publisher is like:
public sealed class EventPublisher : IEventPublisher
{
public async Task PublishAsync<T>(T eventMessage)
{
var subscriptions = DependencyResolver.ResolveAll<IConsumer<T>>();
foreach (var subscription in subscriptions)
{
await subscription.HandleEventAsync(eventMessage);
}
}
}
where I resolve all event subscribers and push messages to them.
If yes, then I have the same structure in my application, and my SimpleInjector registration for eventConsumers look's like that:
private static void RegisterConsumers(Container container)
{
container.Register<IEventPublisher, EventPublisher>(Lifestyle.Scoped);
container.Collection.Register(typeof(IConsumer<>), new[] {
typeof(CommonConsumer),
typeof(MeasurementEventConsumer),
typeof(PartRepairEventConsumer),
typeof(OrderItemEventConsumer),
typeof(OrderTaskEventConsumer),
typeof(OrderItemWorkStatusEventConsumer),
typeof(OrderItemTaskEventConsumer),
typeof(OrderTaxEventConsumer)
});
}
I got two console applications which calls my webapi the same time and I get back in the console application the follow response from my api:
A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
So they call at the same time my webapi and then something inside the webapi cannot handle those 2 async calls so this error is returned.
I checked all my code on the webapi project and all methods are async and got await so I cannot see why I get this.
Here is the code of the webapi.
Controller:
public class FederationsController : ApiController
{
private readonly IFederationRepository _federationRepository;
public FederationsController(IFederationRepository federationRepository)
{
_federationRepository = federationRepository;
}
[HttpGet]
[Route("federations", Name = "GetFederations")]
public async Task<IHttpActionResult> GetFederations()
{
var federations = await _federationRepository.GetAllAsync();
return Ok(federations.ToModel());
}
}
Repository
public class FederationRepository : IFederationRepository, IDisposable
{
private Models.DataAccessLayer.CompetitionContext _db = new CompetitionContext();
#region IQueryable
private IQueryable<Models.Entities.Federation> FederationWithEntities()
{
return _db.Federations.Include(x => x.Clubs)
.Where(x => !x.DeletedAt.HasValue && x.Clubs.Any(y => !y.DeletedAt.HasValue));
}
#endregion IQueryable
public async Task<IEnumerable<Models.Entities.Federation>> GetAllAsync()
{
return await FederationWithEntities().ToListAsync();
}
}
Mapper
public static class FederationMapper
{
public static List<Federation> ToModel(this IEnumerable<Models.Entities.Federation> federations)
{
if (federations == null) return new List<Federation>();
return federations.Select(federation => federation.ToModel()).ToList();
}
public static Federation ToModel(this Models.Entities.Federation federation)
{
return new Federation()
{
Name = federation.Name,
FederationCode = federation.FederationCode,
CreatedAt = federation.CreatedAt,
UpdatedAt = federation.UpdatedAt
};
}
}
DbContext
public class CompetitionContext : DbContext
{
public CompetitionContext() : base("ContextName")
{
}
public DbSet<Federation> Federations { get; set; }
}
UnityConfig
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IFederationRepository, FederationRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Thank you for all the advices/help.
In your repository you are creating a single CompetitionContext and reusing it. I'm assuming that IoC setup is registring the repository as some kind of single instance, so the same repository is getting used every time. If that's the case you should create a new CompetitionContext for each method call.
Also, probably should make sure it's closed with a using statement.
I'm also not clear from your code snippets why you are returning an IQueryable from that FederationWithEntities, method, do you have other things that are using it?
Anyway, I'd probably change that GetAllMethod to be something like this:
public async Task<IEnumerable<Models.Entities.Federation>> GetAllAsync()
{
using (Models.DataAccessLayer.CompetitionContext _db = new CompetitionContext())
{
return _db.Federations.Include(x => x.Clubs)
.Where(x => !x.DeletedAt.HasValue && x.Clubs.Any(y => !y.DeletedAt.HasValue))
.ToListAsync();
}
}
I write web application using ASP.NET MVC WebAPI and I want to transform current synchronous code to asynchronous for optimization. Problem is that I fill ViewModel with multiple objects taken from repository. These calls from repository should be async.
Let's asume I have signature for repository calls respecting this interface
public interface ICompanyRepository
{
IEnumerable<Company> GetCompanies();
IEnumerable<Address> GetAddresses();
}
ViewModels definition
public class CompaniesFullViewModel
{
public IEnumerable<Company> Companies { get; set; }
public IEnumerable<Address> Addresses { get; set; }
}
And controller:
public class CompanyController
{
public readonly ICompanyRepository Repository { get; private set; }
public CompanyController(IRepository repository)
{
Repository = repository;
}
[ResponseType(typeof(CompaniesFullViewModel))]
public HttpResponseMessage Get()
{
var companies = Repository.GetCompanies();
var addresses = Repository.GetAddresses();
HttpStatusCode statusCode = companies.Any()
? HttpStatusCode.OK
: HttpStatusCode.PartialContent;
return
Request.CreateResponse(
statusCode,
new CompaniesFullViewModel
{
Companies = companies,
Addresses = addresses
});
}
}
Furthermore I have tests implemented to the controller:
[TestClass]
public sealed class CompanyTestController : BaseTestController
{
#region Fields
private static Mock<ICompanyRepository> _repositoryMock;
private static CompanyController _controller;
#endregion
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
// Mock repository
_repositoryMock = new Mock<ICompanyRepository>();
DependencyResolver.Default.Container.RegisterInstance(_repositoryMock.Object);
// Create controller
_controller =
DependencyResolver.Default.Container.Resolve<CompanyController>();
// Init request
_controller.Request = new HttpRequestMessage();
_controller.Request.SetConfiguration(new HttpConfiguration());
}
[ClassCleanup]
public static void Cleanup()
{
_controller.Dispose();
}
[TestMethod]
public void Get_ActionExecutes_ReturnsEmptyCompaniesViewModel()
{
var companies = new List<Company>();
var addresses = new List<Address>();
// Setup fake method
_repositoryMock
.Setup(c => c.GetCompanies())
.Returns(companies);
_repositoryMock
.Setup(c => c.GetAddresses())
.Returns(addresses);
// Execute action
var response = _controller.Get();
// Check the response
Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode);
}
}
How can I convert the controller to async, if the repository is async and the signature looks like this:
public interface ICompanyRepository
{
Task<IEnumerable<Company>> GetCompaniesAsync();
Task<IEnumerable<Address>> GetAddressesAsync();
}
What you need to do is change the Controller action to be async as well, and change the return type to Task<>. You can then await your asynchronous repository calls:
[ResponseType(typeof(CompaniesFullViewModel))]
public async Task<HttpResponseMessage> Get() // async keyword.
{
var companies = await Repository.GetCompaniesAsync(); // await
var addresses = await Repository.GetAddressesAsync(); // await
HttpStatusCode statusCode = companies.Any()
? HttpStatusCode.OK
: HttpStatusCode.PartialContent;
return
Request.CreateResponse(
statusCode,
new CompaniesFullViewModel
{
Companies = companies,
Addresses = addresses
});
}
By convention, you can also change the name of the controller action to end in Async as well, although if you are using RESTful conventions and / or Routing attributes, the actual name of the controller action isn't really important.
Testing
I use XUnit and NUnit, but it seems MSTest also supports testing of asynchronous methods, and Moq also provides Async versions of the setups:
[Test]
public async Task Get_ActionExecutes_ReturnsEmptyCompaniesViewModel() // async Task
{
var companies = new List<Company>();
var addresses = new List<Address>();
// Setup fake method
_repositoryMock
.Setup(c => c.GetCompaniesAsync())
.ReturnsAsync(companies); // Async
_repositoryMock
.Setup(c => c.GetAddressesAsync())
.ReturnsAsync(addresses); // Async
// Execute action
var response = await _controller.Get(); // Await
// Check the response
Assert.AreEqual(HttpStatusCode.PartialContent, response.StatusCode);
_repositoryMock.Verify(m => m.GetAddressesAsync(), Times.Once);
_repositoryMock.Verify(m => m.GetCompaniesAsync(), Times.Once);
}
As an aside, it seems you are using Setter Dependency injection. An alternative is to use Constructor injection, which has the benefit of ensuring that the class is always in a valid state (i.e. there is no transient state while it is waiting for the dependencies to be set). This also allows the dependencies (your repository in this case) to be made readonly.
Apart from .NET 4.5.1 there is a new option on the TransactionScope which enables to use async flow. This allows to write the following client code
using(var txt = new TransactionScope(..., TransactionScopeAsyncFlowOption.Enabled)
{
await sender.SendAsync();
}
So far so good. But when I need to implement a volatile IEnlistmentNotification I'm struggling to do that. Let's imagine the following scenario, assumption: My underlying infrastructure is completely async from bottom to top
public class MessageSender : ISendMessages
{
public async Task SendAsync(TransportMessage message, SendOptions options)
{
await sender.SendAsync(message);
}
}
So what I want to achieve is to introduce a volatile IEnlistmentNotification like this:
internal class SendResourceManager : IEnlistmentNotification
{
private readonly Func<Task> onCommit;
public SendResourceManager(Func<Task> onCommit)
{
this.onCommit = onCommit;
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
await this.onCommit();
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
}
and the new sender
public class MessageSender : ISendMessages
{
public async Task SendAsync(TransportMessage message, SendOptions options)
{
// Dirty: Let's assume Transaction.Current is never null
Transaction.Current.EnlistVolatile(new SendResourceManager(async () => { await sender.SendAsync(message) }));
}
}
Note: Of course this code doesn't compile. It would require me to declare the commit method async void. Which is aweful.
So my question is: How can I write an enlistment which can internally await an asynchronous operation?
As long as EnlistVolatile isn't a heavy CPU bound time consuming operation, you can create a thin Task based wrapper over EnlistVolatile using Task.FromResult:
public static class TranscationExtensions
{
public static Task EnlistVolatileAsync(this Transaction transaction,
IEnlistmentNotification
enlistmentNotification,
EnlistmentOptions enlistmentOptions)
{
return Task.FromResult(transaction.EnlistVolatile
(enlistmentNotification,
enlistmentOptions));
}
}
and then consume it inside your method:
public class MessageSender : ISendMessages
{
public Task SendAsync(TransportMessage message, SendOptions options)
{
return Transaction.Current.EnlistVolatileAsync
(new SendResourceManager(async () =>
{ await sender.SendAsync(message) }));
}
}
which can be awaited higher in your callstack:
MessageSender sender = new MessageSender();
await sender.SendAsync(message, options);