I have a kind of bus that implements this interface:
public interface IBus
{
void Publish<T>(T t);
void Subscribe<T>(Guid subscriptionId, Action<T> action);
void Unsubscribe<T>(Guid subscriptionId);
}
Here is an example on how I use it:
public void PrintName()
{
IBus bus = new Bus();
var id = Guid.NewGuid();
bus.Subscribe<ReplyUserName>(id, replyUserName =>
{
bus.Unsubscribe<ReplyUserName>(id);
Console.WriteLine(replyUserName.UserName);
});
Bus.Publish(new RequestUserName());
}
And here are the RequestUserName and ReplyUserName classes:
public class RequestUserName {}
public class ReplyUserName
{
public string UserName { get; set; }
}
However I would like to write an extension method that would wrap this with async:
public static class BusExtension
{
public static async Task<TResult> Request<TRequest, TResult>(this IBus bus, TRequest request)
{
// TODO...
}
}
So that I will be able to write the previous code in such a way:
public async void PrintName()
{
IBus bus = new Bus();
var replyUserName = await bus.Request<RequestUserName, ReplyUserName>(new RequestUserName());
Console.WriteLine(replyUserName.UserName);
}
what should I write instead of the TODO?
You can use TaskCompletionSource<T> to wrap anything into an await-compatible method.
public static Task<TResult> Request<TRequest, TResult>(this IBus bus, TRequest request)
{
var tcs = new TaskCompletionSource<TResult>();
var id = Guid.NewGuid();
bus.Subscribe<TResult>(id, result =>
{
bus.Unsubscribe<TResult>(id);
tcs.TrySetResult(result);
});
bus.Publish(request);
return tcs.Task;
}
Note, however, that you should ensure that the task is completed. If there's any chance that the bus won't respond to the request, you should have a timer or something that faults the TaskCompletionSource.
You could implement this as follows:
var taskCompletionSource = new TaskCompletionSource<TResult>();
bus.Subscribe<TResult>(id, result =>
{
bus.Unsubscribe<TResult>(id);
taskCompletionSource.SetResult(result);
});
bus.Publish(request);
return taskCompletionSource.Task;
You might also want to check out Reactive Extensions (Rx) as your IBus interface looks similar to the ISubject interface (http://msdn.microsoft.com/en-us/library/hh211669.aspx). The Reactive Extensions library already provides convenient extension methods similar to the one you are attempting to implement.
Related
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 have to use an API that mandates a class that implements its callback interface as a parameter to an authentication method.
public class CallBack : ICallBack
{
public object Response;
public void OnSuccess(object response)
{
Response = response;
}
public void OnException(Exception ex) { }
}
Authentication Call
public async Task<bool> LoginAsync(string username, string password)
{
CallBack callback = new CallBack();
await Task.Factory.StartNew(
() => userService.Authenticate(username, password, callback),
TaskCreationOptions.AttachedToParent);
return callback.Response is User ? true : false;
}
The problem is that LoginAsync finishes before the callback is invoked. I hoped that by starting the Authenticate call using TaskCreationOptions.AttachedToParent, it would propagate down to any child tasks started in Authenticate but it does not.
You should use a TaskCompletionSource object to wrap your callback based async method into a awaitable task.
I assume your ICallBack is like this :
public interface ICallBack
{
void OnSuccess(object response);
void OnException(Exception ex);
}
So you can implement LoginAsync like this :
public async Task<bool> LoginAsync(string username, string password)
{
var tcs = new TaskCompletionSource<object>();
ICallBack callback = new CallBackAsync(tcs);
userService.Authenticate(username, password, callback);
var result = await tcs.Task;
return result is User ? true : false;
}
public class CallBackAsync : ICallBack
{
private TaskCompletionSource<object> _tcs;
public CallBackAsync(TaskCompletionSource<object> tcs)
{
_tcs = tcs;
}
public void OnSuccess(object response)
{
_tcs.TrySetResult(response);
}
public void OnException(Exception ex) {
_tcs.TrySetException(ex);
}
}
For the quick explanation, when you use Task.Factory.StartNew(), the completion of the task is raised at the end of the lambda expression. But in your case this occurs before CallBack.OnSuccess call. So the result is not set.
The TaskCompletionSource class allow you to fully control when the task completion must occurs.
I am busy implementing a EventProcessorHost client for an azure EventBus client.
I have a class that implements IEventProcessor as follows:
public class MyEventProcessor : IEventProcessor
{
Stopwatch checkpointStopWatch;
//TODO: get provider id from parent class
public async Task CloseAsync(PartitionContext context, CloseReason reason)
{
Debug.WriteLine("Processor Shutting Down. Partition '{0}', Reason: '{1}'.", context.Lease.PartitionId, reason);
if (reason == CloseReason.Shutdown)
{
await context.CheckpointAsync();
}
}
public Task OpenAsync(PartitionContext context)
{
Debug.WriteLine("SimpleEventProcessor initialized. Partition: '{0}', Offset: '{1}'", context.Lease.PartitionId, context.Lease.Offset);
eventHandler = new MyEventHandler();
this.checkpointStopWatch = new Stopwatch();
this.checkpointStopWatch.Start();
return Task.FromResult<object>(null);
}
async Task IEventProcessor.ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
{
foreach (EventData eventData in messages)
{
string data = Encoding.UTF8.GetString(eventData.GetBytes());
Debug.WriteLine(data);
}
//Call checkpoint every 5 minutes, so that worker can resume processing from the 5 minutes back if it restarts.
if (this.checkpointStopWatch.Elapsed > TimeSpan.FromMinutes(5))
{
await context.CheckpointAsync();
this.checkpointStopWatch.Restart();
}
}
}
I then call this as follows:
EventProcessorHost _eventProcessorHost = new EventProcessorHost(eventProcessorHostName, EndpointName, EventHubConsumerGroup.DefaultGroupName, ConnectionString, storageConnectionString, "messages-events");
await _eventProcessorHost.RegisterEventProcessorAsync<MyEventProcessor>();
I need to pass a parameter to the instance of MyEventProcessor which the EventProcessorHost creates. How would I go about doing this?
You just need to use RegisterEventProcessorFactoryAsync to pass in a factory instance. That factory class can pass in whatever parameters are appropriate in the factory method possibly by passing them into the factory in the first place, or having the factory vary the behavior. In the code sketched out below you can see two parameters being passed into the IEventProcessor. One of them from the factory's parameters and the other is a counter of how many times the factory has been called.
class AzureStreamProcessor : IEventProcessor
{
....
}
class AzureStreamProcessorFactory : IEventProcessorFactory
{
public AzureStreamProcessorFactory(string str)
{
this.randomString = str;
}
private string randomString;
private int numCreated = 0;
IEventProcessor IEventProcessorFactory.CreateEventProcessor(PartitionContext context)
{
return new AzureStreamProcessor(context, randomString, Interlocked.Increment(ref numCreated));
}
}
host.RegisterEventProcessorFactoryAsync(new AzureStreamProcessorFactory("a parameter"), options);
May be try doing a constructor dependency injection to the MyEventProcessor class with a parameter something like below.
public class MyEventProcessor : IEventProcessor
{
Stopwatch checkpointStopWatch;
//TODO: get provider id from parent class
IParameters _parameter;
public MyEventProcessor (IParameters param)
{
this._parameter = param;
}
public async Task CloseAsync(PartitionContext context, CloseReason reason)
{
Debug.WriteLine("Processor Shutting Down. Partition '{0}', Reason: '{1}'.", context.Lease.PartitionId, reason);
if (reason == CloseReason.Shutdown)
{
await context.CheckpointAsync();
}
}.....
Use _parameter to retrieve what you need.
below is how you can register the dependencies for your IParameters
Here i use Ninject dependency resolver.
//Bind the class that implements IParameter.
var parameters = new Parameter();
paramters.Property = "my data"
kernel.Bind<IParameters>().ToConstant(parameters);
hope that helps
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);
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.