I using signal R core to send me a list of messages but this happen
public ObservableCollection<ChatMessage> Messages { get; set; } = new ObservableCollection<ChatMessage>();
public async void InitSignalRAsync()
{
ChatMessage mess = new ChatMessage();
hubConnection = new HubConnectionBuilder().WithUrl("http://localhost:5000/chatHub").Build();
await hubConnection.StartAsync();
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
mess.user = user;
mess.message = message;
Messages.Add(mess);
});
}
I got an error
System.Runtime.InteropServices.COMException:
at my
Messages.Add(mess);
when I receive the data
As Martin noted, you must update ViewModel components from their UI thread.
However, for a solution, I recommend using the more general-purpose SynchronizationContext rather than the UWP-specific Dispatcher class. By using the more general type, your code is more reusable and more testable.
E.g.:
public ObservableCollection<ChatMessage> Messages { get; set; } = new ObservableCollection<ChatMessage>();
public async Task InitSignalRAsync()
{
var context = SynchronizationContext.Current;
hubConnection = new HubConnectionBuilder().WithUrl("http://localhost:5000/chatHub").Build();
await hubConnection.StartAsync();
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var mess = new ChatMessage
{
user = user,
message = message,
};
context.Post(_ => Messages.Add(mess));
});
}
I also changed your async void to async Task (again, better reusability and testability), and made a new ChatMessage for each chat message, which I believe is the intended behavior.
This is happening because the Add() must run on the UI thread when you are using ObservableCollection. So to make it work, make sure to execute the call in Dispatcher.RunAsync():
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
Messages.Add(mess);
});
Related
I'm trying to Unit test a MassTransit Consumer using the MassTransit.Testing Framework and the InMemoryTestHarness.
I'm able to successfully test that a message is sent for two separate consumers so far.
One of the consumers is also successfully consumed, but I get an error message as follows:
R-FAULT loopback://localhost/vhost/input_queue 49820000-5689-0050-3b5c-08d5ecc4708c Acme.Company.Messages.Commands.ISomeCommand Acme.Company.SomeService.Consumers.SomeCommandConsumer(00:00:00.2328493) Failure: The payload was not found: MassTransit.RabbitMqTransport.ModelContext, StackTrace: at GreenPipes.PipeExtensions.GetPayload[TPayload](PipeContext context) at MassTransit.DeferExtensions.Defer[T](ConsumeContext1 context, TimeSpan delay, Action2 callback)
The code at this point is attempting to defer the message for one minute so I wonder whether that is the reason for the missing payload???
The code is as follows:
[TestFixture]
public class SomeCommandConsumerTests
{
private InMemoryTestHarness _harness;
private Mock<ISomeRepository> _SomeRepositoryMock;
private Mock<IAnotherRepository> _AnotherRepositoryMock;
[OneTimeSetUp]
public async Task OneTimeInit()
{
_harness = new InMemoryTestHarness("vhost");
_harness.Consumer(() => new SomeCommandConsumer(_SomeRepositoryMock.Object, _AnotherRepositoryMock.Object));
await _harness.Start();
}
[SetUp]
public void Init()
{
_SomeRepositoryMock = new Mock<ISomeRepository>();
_AnotherRepositoryMock = new Mock<IAnotherRepository>();
_SomeRepositoryMock.Setup(x => x.UpdateSomeId(It.IsAny<SomeEnum>(), It.IsAny<int>()))
.Returns(Task.Factory.StartNew(() => { }));
_SomeRepositoryMock.Setup(x => x.UpdateProcMessage(It.IsAny<string>(), It.IsAny<int>()))
.Returns(Task.Factory.StartNew(() => { }));
_SomeRepositoryMock.Setup(
x => x.UpdateSomeProcStartTime(It.IsAny<int>()))
.Returns(Task.Factory.StartNew(() => { }));
_SomeRepositoryMock.Setup(
x => x.UpdateSomeProcEndTime(It.IsAny<int>()))
.Returns(Task.Factory.StartNew(() => { }));
}
[Test]
public async Task ProcessMessage_MethodCalledWithSomeCondition_MessageSent()
{
//Arrange
_SomeRepositoryMock.Setup(x => x.GetAsync(It.IsAny<int>())).ReturnsAsync(new Entity
{
Property1 = true,
SomeID = 12345
});
await _harness.InputQueueSendEndpoint.Send(new SomeCommand
{
MessageType = MessageTypeEnum.SomeMessgae,
SomeID = 12345
});
//Assert
_harness.Sent.Select<ISomeCommand>().Any().Should().BeTrue();
}
[Test]
public async Task ProcessMessage_MethodCalledWithSomeCondition_CorrectNextStepReturned()
{
//Arrange
_SomeRepositoryMock.Setup(x => x.GetAsync(It.IsAny<int>())).ReturnsAsync(new Control()
{
Property1 = true,
SomeID = 12345
});
await _harness.InputQueueSendEndpoint.Send(new SomeCommand
{
MessageType = MessageTypeEnum.SomeMessgae,
SomeID = 12345
});
//Assert
_harness.Consumed.Select<ISomeCommand>().Any().Should().BeTrue();
_harness.Consumed
.Select<ISomeCommand>()
.First()
.Context
.Message
.SomeID
.Should()
.Be(12345);
_harness.Consumed
.Select<ISomeCommand>()
.First()
.Context
.Message
.MessageProcessingResult
.Should()
.Be(MessageProcessingResult.DeferProcessing);
}
[OneTimeTearDown]
public async Task Teardown()
{
await _harness.Stop();
}
}
And the code that is being hit in the consumer is:
await context.Defer(TimeSpan.FromMinutes(1));
Basically, what am I missing, is it even an issue?
This is happening because you are using the in-memory test harness with a feature (Defer) that is supported by RabbitMQ. Defer tries to use the RabbitMQ model from the consumer to defer the message, and it isn't there, because in-memory doesn't know anything about it.
If you want to use a more generic solution, use Redeliver instead. You'll need to use the QuartzIntegration library with the in-memory test harness, but it does in-memory message redelivery using that scheduler.
You'll also need to update your RabbitMQ bus configuration to include the cfg.UseDelayedExchangeMessageScheduler(); so that RabbitMQ is used for message scheduling.
I want to implement the consumer/producer pattern using the BufferBlock that runs continuously similar to the question here and the code here.
I tried to use an ActionBlock like the OP, but if the bufferblock is full and new messages are in it's queue then the new messages never get added to the ConcurrentDictionary _queue.
In the code below the ConsumeAsync method never gets called when a new message is added to the bufferblock with this call:_messageBufferBlock.SendAsync(message)
How can I correct the code below so that the ConsumeAsync method is called every time a new message is added using _messageBufferBlock.SendAsync(message)?
public class PriorityMessageQueue
{
private volatile ConcurrentDictionary<int,MyMessage> _queue = new ConcurrentDictionary<int,MyMessage>();
private volatile BufferBlock<MyMessage> _messageBufferBlock;
private readonly Task<bool> _initializingTask; // not used but allows for calling async method from constructor
private int _dictionaryKey;
public PriorityMessageQueue()
{
_initializingTask = Init();
}
public async Task<bool> EnqueueAsync(MyMessage message)
{
return await _messageBufferBlock.SendAsync(message);
}
private async Task<bool> ConsumeAsync()
{
try
{
// This code does not fire when a new message is added to the buffereblock
while (await _messageBufferBlock.OutputAvailableAsync())
{
// A message object is never received from the bufferblock
var message = await _messageBufferBlock.ReceiveAsync();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
private async Task<bool> Init()
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 50
};
var prioritizeMessageBlock = new ActionBlock<MyMessage>(msg =>
{
SetMessagePriority(msg);
}, executionDataflowBlockOptions);
_messageBufferBlock = new BufferBlock<MyMessage>();
_messageBufferBlock.LinkTo(prioritizeMessageBlock, new DataflowLinkOptions { PropagateCompletion = true, MaxMessages = 50});
return await ConsumeAsync();
}
}
EDIT
I have removed all the extra code and added comments.
I'm still not completely certain what you're trying to accomplish but I'll try to point you in the right direction. Most of the code in the example isn't strictly necessary.
I need to know when a new message arrives
If this is your only requirement then I'll assume you just need to run some arbitrary code whenever a new message is passed in. The easiest way to do that in dataflow is to use a TransformBlock and set that block as the initial receiver in your pipeline. Each block has it's own buffer so unless you have need for another buffer you can leave it out.
public class PriorityMessageQueue {
private TransformBlock<MyMessage, MyMessage> _messageReciever;
public PriorityMessageQueue() {
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions {
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 50
};
var prioritizeMessageBlock = new ActionBlock<MyMessage>(msg => {
SetMessagePriority(msg);
}, executionDataflowBlockOptions);
_messageReciever = new TransformBlock<MyMessage, MyMessage>(msg => NewMessageRecieved(msg), executionDataflowBlockOptions);
_messageReciever.LinkTo(prioritizeMessageBlock, new DataflowLinkOptions { PropagateCompletion = true });
}
public async Task<bool> EnqueueAsync(MyMessage message) {
return await _messageReciever.SendAsync(message);
}
private MyMessage NewMessageRecieved(MyMessage message) {
//do something when a new message arrives
//pass the message along in the pipeline
return message;
}
private void SetMessagePriority(MyMessage message) {
//Handle a message
}
}
Of course the other option you have would be to do whatever it is you need to immediately within EnqueAsync before returning the task from SendAsync but the TransformBlock gives you extra flexibility.
We are using MassTransit asynchronous messaging (on top of RabbitMQ) for our microservice architecture.
We ran into issues testing consumers that in turn make asynchronous calls.
The example below shows a simple MassTransit consumer that uses RestSharp to make an outbound call and utilized the ExecuteAsync asynchronous method.
public class VerifyPhoneNumberConsumer : Consumes<VerifyPhoneNumber>.Context
{
IRestClient _restClient;
RestRequest _request;
PhoneNumber _phoneNumber;
PhoneNumberVerificationResponse _responseData;
public VerifyPhoneNumberConsumer(IRestClient client)
{
_restClient = client;
}
public void Consume(IConsumeContext<VerifyPhoneNumber> context)
{
try
{
//we can do some standard message verification/validation here
_restClient.ExecuteAsync<PhoneNumberVerificationResponse>(_request, (response) =>
{
//here we might do some standard response verification
_responseData = response.Data;
_phoneNumber = new PhoneNumber()
{
Number = _responseData.PhoneNumber
};
context.Respond(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
}
A sample unit test for this might look like the following:
[TestFixture]
public class VerifyPhoneNumberConsumerTests
{
private VerifyPhoneNumberConsumer _consumer;
private PhoneNumber _phoneNumber;
private RestResponse _response;
private VerifyPhoneNumber _command;
private AutoResetEvent _continuationEvent;
private const int CONTINUE_WAIT_TIME = 1000;
[SetUp]
public void Initialize()
{
_continuationEvent = new AutoResetEvent(false);
_mockRestClient = new Mock<IRestClient>();
_consumer = new VerifyPhoneNumberConsumer(_mockRestClient.Object);
_response = new RestResponse();
_response.Content = "Response Test Content";
_phoneNumber = new PhoneNumber()
{
Number = "123456789"
};
_command = new VerifyPhoneNumber(_phoneNumber);
}
[Test]
public void VerifyPhoneNumber_Succeeded()
{
var test = TestFactory.ForConsumer<VerifyPhoneNumberConsumer>().New(x =>
{
x.ConstructUsing(() => _consumer);
x.Send(_command, (scenario, context) => context.SendResponseTo(scenario.Bus));
});
_mockRestClient.Setup(
c =>
c.ExecuteAsync(Moq.It.IsAny<IRestRequest>(),
Moq.It
.IsAny<Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>()))
.Callback<IRestRequest, Action<IRestResponse<PhoneNumberVerificationResponse>, RestRequestAsyncHandle>>((
request, callback) =>
{
var responseMock = new Mock<IRestResponse<PhoneNumberVerificationResponse>>();
responseMock.Setup(r => r.Data).Returns(GetSuccessfulVericationResponse());
callback(responseMock.Object, null);
_continuationEvent.Set();
});
test.Execute();
_continuationEvent.WaitOne(CONTINUE_WAIT_TIME);
Assert.IsTrue(test.Sent.Any<VerifyPhoneNumberSucceeded>());
}
private PhoneNumberVerificationResponse GetSuccessfulVericationResponse()
{
return new PhoneNumberVerificationResponse
{
PhoneNumber = _phoneNumber
};
}
}
Because of the invocation of the ExecuteAsync method in the consumer, this test method would fall through if we did not put something to block it until it was signaled (or timed out). In the sample above, we are using AutoResetEvent to signal from the callback to continue and run assertions.
THIS IS A TERRIBLE METHOD and we are exhausting all resources to try to find out alternatives. If its not obvious, this can potentially cause false failures and race conditions during testing. Not too mention potentially crippling automated testing times.
What alternatives do we have that are BETTER than what we currently have.
EDIT Here is a source that I originally used for how to mock RestSharp asynchronous calls.
How to test/mock RestSharp ExecuteAsync(...)
Honestly, the complexity of doing asynchronous methods is one of the key drivers of MassTransit 3. While it isn't ready yet, it makes asynchronous method invocation from consumers so much better.
What you're testing above, because you are calling ExecuteAsync() on your REST client, and not waiting for the response (using .Result, or .Wait) in the consumer, the HTTP call is continuing after the message consumer has returned. So that might be part of your problem.
In MT3, this consumer would be written as:
public async Task Consume(ConsumeContext<VerifyPhoneNumber> context)
{
try
{
var response = await _restClient
.ExecuteAsync<PhoneNumberVerificationResponse>(_request);
var phoneNumber = new PhoneNumber()
{
Number = response.PhoneNumber
};
await context.RespondAsync(new VerifyPhoneNumberSucceeded(context.Message)
{
PhoneNumber = _phoneNumber
});
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
I was able to come up with the following solution which seems far more elegant and proper. Feel free to correct me if I am wrong in assuming this.
I modified the RestSharp execution in my consumer so my consumer looks like the following:
public class VerifyPhoneNumberConsumer : Consumes.Context
{
IRestClient _restClient;
RestRequest _request;
PhoneNumber _phoneNumber;
PhoneNumberVerificationResponse _responseData;
public VerifyPhoneNumberConsumer(IRestClient client)
{
_restClient = client;
}
public void Consume(IConsumeContext<VerifyPhoneNumber> context)
{
try
{
//we can do some standard message verification/validation here
var response = await _restClient.ExecuteGetTaskAsync<PhoneNumberVerificationResponse>(_request);
_responseData = response.Data;
_phoneNumber = new PhoneNumber()
{
Number = _responseData.PhoneNumber
};
}
catch (Exception exception)
{
context.Respond(new VerifyPhoneNumberFailed(context.Message)
{
PhoneNumber = context.Message.PhoneNumber,
Message = exception.Message
});
}
}
}
This utilizes the TPL async capabilities of RestSharp so that I don't have to do it myself.
Because of this, I am able to change my test code to the following:
[Test]
public void VerifyPhoneNumber_Succeeded()
{
var test = TestFactory.ForConsumer<VerifyPhoneNumberConsumer>().New(x =>
{
x.ConstructUsing(() => _consumer);
x.Send(_command, (scenario, context) => context.SendResponseTo(scenario.Bus));
});
var response = (IRestResponse<PhoneNumberVerificationResponse>)new RestResponse<PhoneNumberVerificationResponse>();
response.Data = GetSuccessfulVericationResponse();
var taskResponse = Task.FromResult(response);
Expect.MethodCall(
() => _client.ExecuteGetTaskAsync<PhoneNumberVerificationResponse>(Any<IRestRequest>.Value.AsInterface))
.Returns(taskResponse);
test.Execute();
Assert.IsTrue(test.Sent.Any<VerifyPhoneNumberSucceeded>());
}
ViewModel
public class MyViewModel:ReactiveObject, IRoutableViewModel{
private ReactiveList<string> _appExtensions;
public MyViewModel(IScreen screen){
HostScreen = screen;
AppExtensions = new ReactiveList<string>();
GetApplicationExtensions =
ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable<string>>
GetApplicationExtensions
.ObserveOn(RxApp.MainThreadScheduler)
.SubscribeOn(RxApp.TaskpoolScheduler)
.Subscribe(p =>
{
using (_appExtensions.SuppressChangeNotifications())
{
_appExtensions.Clear();
_appExtensions.AddRange(p);
}
});
GetApplicationExtensions.ThrownExceptions.Subscribe(
ex => Console.WriteLine("Error during fetching of application extensions! Err: {0}", ex.Message));
}
// bound to a ListBox
public ReactiveList<string> AppExtensions
{
get { return _appExtensions; }
set { this.RaiseAndSetIfChanged(ref _appExtensions, value); }
}
public ReactiveCommand<IEnumerable<string>> GetApplicationExtensions { get; protected set; }
}
and the View has a <Button Command="{Binding GetApplicationExtensions}"></Button>.
implentation of GetApplicationExtensions
public async Task<IEnumerable<string>> GetApplicationExtensions()
{
IEnumerable<string> extensions = null;
using (var client = new HttpClient())
{
client.BaseAddress = BaseAddress;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var response = await client.GetAsync("applications");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
extensions = JsonConvert.DeserializeObject<IEnumerable<string>>(json);
}
}
return extensions;
}
From everything I've read about ReactiveUI and all the examples I've seen (althought there are extremely few for the new 6.0+ versions), this should make my async call (which makes an async HTTP request via HttpClient) run on a background thread and update a ListBox in my view when the results are returned from it. However, this is not the case - the UI gets locked up for the duration of the async call. What am I doing wrong?
UPDATE
If I wrapped my HTTP call in a Task then everything worked as intended - the UI did not hang up at all. So the new implementation of my service call is this:
public Task<IEnumerable<string>> GetApplicationExtensions()
{
var extensionsTask = Task.Factory.StartNew(async () =>
{
IEnumerable<string> extensions = null;
using (var client = new HttpClient())
{
client.BaseAddress = BaseAddress;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var response = await client.GetAsync("applications");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
extensions = JsonConvert.DeserializeObject<IEnumerable<string>>(json);
}
}
return extensions;
}
return extensionsTask.Result;
}
Also, with this change to my async service call, I could remove the ObserveOn and SubscribeOn from my ReactiveCommand like #PaulBetts suggessted. So my ReactiveCommand implementation in my view model's constructor became this:
GetApplicationExtensions =
ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable<string>>
GetApplicationExtensions
.Subscribe(p =>
{
using (_appExtensions.SuppressChangeNotifications())
{
_appExtensions.Clear();
_appExtensions.AddRange(p);
}
});
Can you show the implementation of _schemaService.GetApplicationExtensions()?
Depending on how it is implemented it might not actually be on another thread. Arguably, ReactiveCommand should guarantee that even async operations that accidentally burn CPU before running an async op are forced onto background threads, but efficiency is trumping defensive programming in this case.
You shouldn't need either SubscribeOn or ObserveOn, ReactiveCommand already guarantees that values will be returned on the UI thread. Otherwise, this code is looking good!
Change
GetApplicationExtensions
.ObserveOn(RxApp.MainThreadScheduler)
.SubscribeOn(RxApp.TaskpoolScheduler)
to
GetApplicationExtensions
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
ObserveOn should be after SubscribeOn
I am new writer to SO, pls bear with me.
I have a WCF service with a duplex service contract. This service contract has an operation contact that suppose to do long data processing. I am constrained to limit the number of concurrent data processing to let's say max 3. My problem is that after the data processing I need to get back to the same service instance context so I call back my initiator endpoint passing the data processing result. I need to mention that due to various reasons I am constrained to TPL dataflows and WCF duplex.
Here is a demo to what I wrote so far
In a console library I simulate WCF calls
class Program
{
static void Main(string[] args)
{
// simulate service calls
Enumerable.Range(0, 5).ToList().ForEach(x =>
{
new System.Threading.Thread(new ThreadStart(async () =>
{
var service = new Service();
await service.Inc(x);
})).Start();
});
}
}
Here is what suppose to be the WCF service
// service contract
public class Service
{
static TransformBlock<Message<int>, Message<int>> transformBlock;
static Service()
{
transformBlock = new TransformBlock<Message<int>, Message<int>>(x => Inc(x), new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 3
});
}
static Message<int> Inc(Message<int> input)
{
System.Threading.Thread.Sleep(100);
return new Message<int> { Token = input.Token, Data = input.Data + 1 };
}
// operation contract
public async Task Inc(int id)
{
var token = Guid.NewGuid().ToString();
transformBlock.Post(new Message<int> { Token = token, Data = id });
while (await transformBlock.OutputAvailableAsync())
{
Message<int> message;
if (transformBlock.TryReceive(m => m.Token == token, out message))
{
// do further processing using initiator service instance members
// something like Callback.IncResult(m.Data);
break;
}
}
}
}
public class Message<T>
{
public string Token { get; set; }
public T Data { get; set; }
}
The operation contract is not really necessary to be async, but I needed the OutputAvailableAsync notification.
Is this a good approach or is there a better solution for my scenario?
Thanks in advance.
First, I think you shouldn't use the token the way you do. Unique identifiers are useful when communicating between processes. But when you're inside a single process, just use reference equality.
To actually answer your question, I think the (kind of) busy loop is not a good idea.
A simpler solution for asynchronous throttling would be to use SemaphoreSlim. Something like:
static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(3);
// operation contract
public async Task Inc(int id)
{
await Semaphore.WaitAsync();
try
{
Thread.Sleep(100);
var result = id + 1;
// do further processing using initiator service instance members
// something like Callback.IncResult(result);
}
finally
{
Semaphore.Release();
}
}
If you really want to (or have to?) use dataflow, you can use TaskCompletionSource for synchronization between the operation and the block. The operation method would wait on the Task of the TaskCompletionSource and the block would set it when it finished computation for that message:
private static readonly ActionBlock<Message<int>> Block =
new ActionBlock<Message<int>>(
x => Inc(x),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 3
});
static void Inc(Message<int> input)
{
Thread.Sleep(100);
input.TCS.SetResult(input.Data + 1);
}
// operation contract
public async Task Inc(int id)
{
var tcs = new TaskCompletionSource<int>();
Block.Post(new Message<int> { TCS = tcs, Data = id });
int result = await tcs.Task;
// do further processing using initiator service instance members
// something like Callback.IncResult(result);
}