I'm trying to create sample router with two remote actors.
Here's my code
class Program
{
public const string AkkaConfig = #"{
akka {
actor {
provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
deployment {
/remoteecho1 {
remote = ""akka.tcp://Target#my1.lan:8090""
}
/remoteecho2 {
remote = ""akka.tcp://Target#my2.lan:8090""
}
}
remote{
helios.tcp{
port = 0
hostname = localhost
}
}
}
}";
static void Main(string[] args)
{
using (var system = ActorSystem.Create("Deployer", AkkaConfig))
{
var remoteEcho1 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho1");
var remoteEcho2 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho2");
var roundRobinGroup = new RoundRobinGroup(new[]
{
remoteEcho1,
remoteEcho2
});
var coordinator = system.ActorOf(Props.Empty.WithRouter(roundRobinGroup),"coordinator");
system.ActorOf(Props.Create(() => new HelloActor(coordinator)), "localactor");
system.ActorSelection("/user/localactor").Tell(new SayHelloMessage());
Console.ReadKey();
}
}
}
public class HelloActor:ReceiveActor
{
private readonly IActorRef remoteActor;
public HelloActor(IActorRef remoteActor)
{
this.remoteActor = remoteActor;
Context.Watch(remoteActor);
Receive<HelloMessage>(m =>
{
Console.WriteLine("Pingback from {1}: {0}", m.MessageText, Sender.Path);
});
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
}
protected override void PreStart()
{
Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1), Context.Self, new SayHelloMessage(), ActorRefs.NoSender);
}
}
public class SayHelloMessage
{
}
The problem is that remoteActor.Tell(newMessage) in the code below doesn't send message to my actor
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
When I pass remoteEcho actor to HelloActor constructor instead of router instance everything works fine. How to make that example work with Router?
Related
I am using #aspnet/signalr to connect to a hub and from the hub i am calling the method to return me some data.
When i first initialize the server the connection is established normally, but if i refresh the window 3 or 4 times the client stop sending connection request to the server.
I tried logging the HubConnection, the connectionState at first is equal to 1 but after the problem accrues the connectionState is alwase equal 0
Here is how i am building the hubConnection:
buildConnection() {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.tradesService.getStockQuotationsHubUrl())
.build();
this.hubConnection.serverTimeoutInMilliseconds = 1000 * 10;
this.hubConnection.onclose(() => setTimeout(() => this.startSignalRConnection(), 2000));}
Here is how i am starting the hubConnection:
startConnection() {
this.hubConnection
.start()
.then(() => {
this.hubConnection.on('updateMethod', (data: any) => {
this.store.push([
{ type: 'update', key: data.stockID, data },
]);
});
this.dataSource = new DataSource({
store: this.store,
reshapeOnPush: true,
});
});}
Note: I am listing to 5 hubs at once in my page but the only one having problems is this one.
[Update]
The problem is from the server because when i restart the server the connection is reestablished between the client and the server, but if the client refresh or quit the page for multiple times the hub does not even try to connect to the client
public class StockQuotationsHub : Microsoft.AspNetCore.SignalR.Hub
{
private string SectorID { get; set; }
private int TradingSession { get; set; }
private int MarketID { get; set; }
public static StockQuotationExt stockQuotationExt { get; set; }
private readonly StockQuotationTicker _stockTicker;
public StockQuotationsHub(StockQuotationTicker stockTicker){
_stockTicker = stockTicker;
}
public override Task OnConnectedAsync(){
return base.OnConnectedAsync();
}
public IEnumerable<StockQuotation> GetAllStockQuotations(string[] stockID, string sectorID, int tradingSession, int marketType){
return _stockTicker.
GetAllStocks(Context.ConnectionId, stockID, sectorID, tradingSession, marketType);
}
public override async Task OnDisconnectedAsync(Exception exception){
await base.OnDisconnectedAsync(exception);
}
and here is my stock ticker class:
public IEnumerable<StockQuotation> GetAllStocks(string connectionId, string[] stockID, string sectorID, int tradingSession, int marketType)
{
_stocks = new List<StockQuotation>();
_stocks = Task.Run(async () => await GetStockQuotationModelAsync("", 0, 1, 0)).Result.ToList();
this.MaxTimeStamp = _stocks.Max(s => s.TStamp);
this.SectorID = sectorID;
this.TradingSession = tradingSession;
this.MarketID = marketType;
AddToGroups(connectionId, stockID);
if (_timer==null)
_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
if (stockID.Length == 0)
{
return _stocks;
}
else
{
var stocksList = new List<StockQuotation>();
foreach (var stock in stockID)
{
stocksList.AddRange(_stocks.Where(s => s.StockID == stock).ToList());
}
return stocksList;
}
}
private void AddToGroups(string connectionId, string[] stockID)
{
if (_stocks.Count > 0)
{
if (stockID.Length == 0)
{
Hub.Groups.AddToGroupAsync(connectionId, "ALL");
}
else
{
foreach (var stock in stockID)
{
Hub.Groups.AddToGroupAsync(connectionId, stock);
var s = _stocks.FirstOrDefault(s => s.StockID == stock);
if(s != null)
{
s.Snapshots = new List<double>(GetStockQuotationSnapshots(stock));
}
}
}
}
}
private void AddToGroups(string connectionId, string[] stockID)
{
if (_stocks.Count > 0)
{
if (stockID.Length == 0)
{
Hub.Groups.AddToGroupAsync(connectionId, "ALL");
}
else
{
foreach (var stock in stockID)
{
Hub.Groups.AddToGroupAsync(connectionId, stock);
var s = _stocks.FirstOrDefault(s => s.StockID == stock);
if(s != null)
{
s.Snapshots = new List<double>(GetStockQuotationSnapshots(stock));
}
}
}
}
}
I really appreciated the help.
Eventually the problem was that the project type was MVC, so I changed it to be webApi
and everything worked successfully
Even if you fix it I would like to recommend you to add the following code in order to know exactly the root cause of disconnection.
First of all enable the extended debug info in the service configuration:
services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
});
Furthermore, you need to attach to the event Closed in HubConnection like that:
hubConnection.Closed += (exception) =>
{
if (exception == null)
{
Console.WriteLine("Connection closed without error.");
}
else
{
Console.WriteLine($"Connection closed due to an error: {exception}");
}
return null;
};
I have a class as below :
public class CosmosRepository: ICosmosRepository
{
private ICosmoDBSettings cosmoDbSettings;
private CosmosClient cosmosClient;
private static readonly object syncLock = new object();
// The database we will create
private Database database;
public CosmosRepository(ICosmoDBSettings cosmoDBSettings)
{
this.cosmoDbSettings = cosmoDBSettings;
this.InitializeComponents();
}
private void InitializeComponents()
{
try
{
if (cosmosClient != null)
{
return;
}
lock (syncLock)
{
if (cosmosClient != null)
{
return;
}
this.cosmosClient = new CosmosClient(
cosmoDbSettings.CosmosDbUri
, cosmoDbSettings.CosmosDbAuthKey
, new CosmosClientOptions
{
ConnectionMode = ConnectionMode.Direct
}
);
this.database = this.cosmosClient.CreateDatabaseIfNotExistsAsync(cosmoDbSettings.DocumentDbDataBaseName).Result;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
I have my repository method as:
Don't bother about hardcoded values.
public async Task<Employee> GetById()
{
var container = this.database.GetContainer("Employees");
var document = await container.ReadItemAsync<Employee>("44A85B9E-2522-4BDB-891A-
9EA91F6D4CBF", new PartitionKey("PartitionKeyValue"));
return document.Response;
}
Note
How to write Unit Test(MS Unit tests) in .NET Core with respect to Cosmos Database?
How to mock CosmosClient and all its methods.
Could someone help me with this issue?
My UnitTests looks like:
public class UnitTest1
{
private Mock<ICosmoDBSettings> cosmoDbSettings;
private Mock<CosmosClient> cosmosClient;
private Mock<Database> database;
[TestMethod]
public async Task TestMethod()
{
this.CreateSubject();
var databaseResponse = new Mock<DatabaseResponse>();
var helper = new CosmosDBHelper(this.cosmoDbSettings.Object);
this.cosmosClient.Setup(d => d.CreateDatabaseIfNotExistsAsync("TestDatabase", It.IsAny<int>(), It.IsAny<RequestOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(databaseResponse.Object);
var mockContainer = new Mock<Container>();
this.database.Setup(x => x.GetContainer(It.IsAny<string>())).Returns(mockContainer.Object);
var mockItemResponse = new Mock<ItemResponse<PortalAccount>>();
mockItemResponse.Setup(x => x.StatusCode).Returns(It.IsAny<HttpStatusCode>);
var mockPortalAccount = new PortalAccount { PortalAccountGuid = Guid.NewGuid() };
mockItemResponse.Setup(x => x.Resource).Returns(mockPortalAccount);
mockContainer.Setup(c => c.ReadItemAsync<PortalAccount>(It.IsAny<string>(),It.IsAny<PartitionKey>(), It.IsAny<ItemRequestOptions>(), It.IsAny<CancellationToken>())).ReturnsAsync(mockItemResponse.Object);
var pas = helper.GetById().Result;
Assert.AreEqual(pas.PortalAccountGuid, mockPortalAccount.PortalAccountGuid);
}
public void CreateSubject(ICosmoDBSettings cosmoDBSettings = null)
{
this.cosmoDbSettings = cosmoDbSettings ?? new Mock<ICosmoDBSettings>();
this.cosmoDbSettings.Setup(x => x.CosmosDbUri).Returns("https://localhost:8085/");
this.cosmoDbSettings.Setup(x => x.CosmosDbAuthKey).Returns("C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==");
this.cosmoDbSettings.Setup(x => x.DocumentDbDataBaseName).Returns("TestDatabase");
this.database = new Mock<Database>();
this.cosmosClient = new Mock<CosmosClient>();
}
}
Note:
Exception:
Response status code does not indicate success: 404 Substatus: 0 Reason: (Microsoft.Azure.Documents.DocumentClientException: Message: {"Errors":["Resource Not Found"]}
I'm not creating a document. directly I'm fetching the document because I'm returning the mock response only. Is it correct??
I am trying to implement a simple example/demo for a state machine using Automatonymous with RabbitMQ. Unfortunately I could not find one to rebuild / learn from (I found the ShoppingWeb, but in my eyes it's anything but simple). Also in my opinion the documentation is lacking information.
This is the state machine example I thought of (sorry, it's pretty ugly):
Please note that this example is completely made up and it's not important if it makes sense or not. This project's purpose is to get "warm" with Automatonymous.
What I want to do / to have is:
Four applications running:
The state machine itself
The "requester" sending requests to be interpreted
The "validator" or "parser" checking if the provided request is valid
The "interpreter" interpreting the given request
An example of this could be:
Requester sends "x=5"
Validator checks if a "=" is contained
Intepreter says "5"
My implementation of the state machine looks like this:
public class InterpreterStateMachine : MassTransitStateMachine<InterpreterInstance>
{
public InterpreterStateMachine()
{
InstanceState(x => x.CurrentState);
Event(() => Requesting, x => x.CorrelateBy(request => request.Request.RequestString, context => context.Message.Request.RequestString)
.SelectId(context => Guid.NewGuid()));
Event(() => Validating, x => x.CorrelateBy(request => request.Request.RequestString, context => context.Message.Request.RequestString));
Event(() => Interpreting, x => x.CorrelateBy(request => request.Request.RequestString, context => context.Message.Request.RequestString));
Initially(
When(Requesting)
.Then(context =>
{
context.Instance.Request = new Request(context.Data.Request.RequestString);
})
.ThenAsync(context => Console.Out.WriteLineAsync($"Request received: {context.Data.Request.RequestString}"))
.Publish(context => new ValidationNeededEvent(context.Instance))
.TransitionTo(Requested)
);
During(Requested,
When(Validating)
.Then(context =>
{
context.Instance.Request.IsValid = context.Data.Request.IsValid;
if (!context.Data.Request.IsValid)
{
this.TransitionToState(context.Instance, Error);
}
else
{
this.TransitionToState(context.Instance, RequestValid);
}
})
.ThenAsync(context => Console.Out.WriteLineAsync($"Request '{context.Data.Request.RequestString}' validated with {context.Instance.Request.IsValid}"))
.Publish(context => new InterpretationNeededEvent(context.Instance))
,
Ignore(Requesting),
Ignore(Interpreting)
);
During(RequestValid,
When(Interpreting)
.Then((context) =>
{
//do something
})
.ThenAsync(context => Console.Out.WriteLineAsync($"Request '{context.Data.Request.RequestString}' interpreted with {context.Data.Answer}"))
.Publish(context => new AnswerReadyEvent(context.Instance))
.TransitionTo(AnswerReady)
.Finalize(),
Ignore(Requesting),
Ignore(Validating)
);
SetCompletedWhenFinalized();
}
public State Requested { get; private set; }
public State RequestValid { get; private set; }
public State AnswerReady { get; private set; }
public State Error { get; private set; }
//Someone is sending a request to interprete
public Event<IRequesting> Requesting { get; private set; }
//Request is validated
public Event<IValidating> Validating { get; private set; }
//Request is interpreted
public Event<IInterpreting> Interpreting { get; private set; }
class ValidationNeededEvent : IValidationNeeded
{
readonly InterpreterInstance _instance;
public ValidationNeededEvent(InterpreterInstance instance)
{
_instance = instance;
}
public Guid RequestId => _instance.CorrelationId;
public Request Request => _instance.Request;
}
class InterpretationNeededEvent : IInterpretationNeeded
{
readonly InterpreterInstance _instance;
public InterpretationNeededEvent(InterpreterInstance instance)
{
_instance = instance;
}
public Guid RequestId => _instance.CorrelationId;
}
class AnswerReadyEvent : IAnswerReady
{
readonly InterpreterInstance _instance;
public AnswerReadyEvent(InterpreterInstance instance)
{
_instance = instance;
}
public Guid RequestId => _instance.CorrelationId;
}
}
Then I have services like this:
public class RequestService : ServiceControl
{
readonly IScheduler scheduler;
IBusControl busControl;
BusHandle busHandle;
InterpreterStateMachine machine;
InMemorySagaRepository<InterpreterInstance> repository;
public RequestService()
{
scheduler = CreateScheduler();
}
public bool Start(HostControl hostControl)
{
Console.WriteLine("Creating bus...");
machine = new InterpreterStateMachine();
repository = new InMemorySagaRepository<InterpreterInstance>();
busControl = Bus.Factory.CreateUsingRabbitMq(x =>
{
IRabbitMqHost host = x.Host(new Uri(/*rabbitMQ server*/), h =>
{
/*credentials*/
});
x.UseInMemoryScheduler();
x.ReceiveEndpoint(host, "interpreting_answer", e =>
{
e.PrefetchCount = 5; //?
e.StateMachineSaga(machine, repository);
});
x.ReceiveEndpoint(host, "2", e =>
{
e.PrefetchCount = 1;
x.UseMessageScheduler(e.InputAddress);
//Scheduling !?
e.Consumer(() => new ScheduleMessageConsumer(scheduler));
e.Consumer(() => new CancelScheduledMessageConsumer(scheduler));
});
});
Console.WriteLine("Starting bus...");
try
{
busHandle = MassTransit.Util.TaskUtil.Await<BusHandle>(() => busControl.StartAsync());
scheduler.JobFactory = new MassTransitJobFactory(busControl);
scheduler.Start();
}
catch (Exception)
{
scheduler.Shutdown();
throw;
}
return true;
}
public bool Stop(HostControl hostControl)
{
Console.WriteLine("Stopping bus...");
scheduler.Standby();
if (busHandle != null) busHandle.Stop();
scheduler.Shutdown();
return true;
}
static IScheduler CreateScheduler()
{
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
IScheduler scheduler = MassTransit.Util.TaskUtil.Await<IScheduler>(() => schedulerFactory.GetScheduler()); ;
return scheduler;
}
}
My questions are:
How do I send the "intial" request, so that the state machine will transition to my initial state
How do I "react" within the consumers to check the data that were sent and then send new data like in 1?
Okay I figured it out. I probably had problems because I'm not only new to Masstransit/Automatonymous and RabbitMQ, but also don't have much experience with C# yet.
So if anyone ever will have the same problem, here is what you need:
Given the above example there are three different types plus some small interfaces needed:
A sender (in this case the "requester") including a specific consumer
A service that consumes specific message types (the "validator" and "interpreter")
A service that holds the state machine without a specific consumer
Some "contracts", which are interfaces defining the type of message that's sent/consumed
1) This is the sender:
using InterpreterStateMachine.Contracts;
using MassTransit;
using System;
using System.Threading.Tasks;
namespace InterpreterStateMachine.Requester
{
class Program
{
private static IBusControl _busControl;
static void Main(string[] args)
{
var busControl = ConfigureBus();
busControl.Start();
Console.WriteLine("Enter request or quit to exit: ");
while (true)
{
Console.Write("> ");
String value = Console.ReadLine();
if ("quit".Equals(value,StringComparison.OrdinalIgnoreCase))
break;
if (value != null)
{
String[] values = value.Split(';');
foreach (String v in values)
{
busControl.Publish<IRequesting>(new
{
Request = new Request(v),
TimeStamp = DateTime.UtcNow
});
}
}
}
busControl.Stop();
}
static IBusControl ConfigureBus()
{
if (null == _busControl)
{
_busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri(/*rabbitMQ server*/), h =>
{
/*credentials*/
});
cfg.ReceiveEndpoint(host, "answer_ready", e =>
{
e.Durable = true;
//here the consumer is registered
e.Consumer<AnswerConsumer>();
});
});
_busControl.Start();
}
return _busControl;
}
//here comes the actual logic of the consumer, which consumes a "contract"
class AnswerConsumer : IConsumer<IAnswerReady>
{
public async Task Consume(ConsumeContext<IAnswerReady> context)
{
await Console.Out.WriteLineAsync($"\nReceived Answer for \"{context.Message.Request.RequestString}\": {context.Message.Answer}.");
await Console.Out.WriteAsync(">");
}
}
}
}
2) This is the service (here it is the validation sercive)
using InterpreterStateMachine.Contracts;
using MassTransit;
using MassTransit.QuartzIntegration;
using MassTransit.RabbitMqTransport;
using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;
using Topshelf;
namespace InterpreterStateMachine.Validator
{
public class ValidationService : ServiceControl
{
readonly IScheduler _scheduler;
static IBusControl _busControl;
BusHandle _busHandle;
public static IBus Bus => _busControl;
public ValidationService()
{
_scheduler = CreateScheduler();
}
public bool Start(HostControl hostControl)
{
Console.WriteLine("Creating bus...");
_busControl = MassTransit.Bus.Factory.CreateUsingRabbitMq(x =>
{
IRabbitMqHost host = x.Host(new Uri(/*rabbitMQ server*/), h =>
{
/*credentials*/
});
x.UseInMemoryScheduler();
x.UseMessageScheduler(new Uri(RabbitMqServerAddress));
x.ReceiveEndpoint(host, "validation_needed", e =>
{
e.PrefetchCount = 1;
e.Durable = true;
//again this is how the consumer is registered
e.Consumer<RequestConsumer>();
});
});
Console.WriteLine("Starting bus...");
try
{
_busHandle = MassTransit.Util.TaskUtil.Await<BusHandle>(() => _busControl.StartAsync());
_scheduler.JobFactory = new MassTransitJobFactory(_busControl);
_scheduler.Start();
}
catch (Exception)
{
_scheduler.Shutdown();
throw;
}
return true;
}
public bool Stop(HostControl hostControl)
{
Console.WriteLine("Stopping bus...");
_scheduler.Standby();
_busHandle?.Stop();
_scheduler.Shutdown();
return true;
}
static IScheduler CreateScheduler()
{
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
IScheduler scheduler = MassTransit.Util.TaskUtil.Await<IScheduler>(() => schedulerFactory.GetScheduler());
return scheduler;
}
}
//again here comes the actual consumer logic, look how the message is re-published after it was checked
class RequestConsumer : IConsumer<IValidationNeeded>
{
public async Task Consume(ConsumeContext<IValidationNeeded> context)
{
await Console.Out.WriteLineAsync($"(c) Received {context.Message.Request.RequestString} for validation (Id: {context.Message.RequestId}).");
context.Message.Request.IsValid = context.Message.Request.RequestString.Contains("=");
//send the new message on the "old" context
await context.Publish<IValidating>(new
{
Request = context.Message.Request,
IsValid = context.Message.Request.IsValid,
TimeStamp = DateTime.UtcNow,
RequestId = context.Message.RequestId
});
}
}
}
The validator consumes the contract "IValidationNeeded" and then publishes the contract "IValidating", which then will be consumed by the state machine itself (the "Validating" event).
3) The difference between a consumer service and the sate machine service lies withing the "ReceiveEndpoint". Here is no consumer registered, but the state machine is set:
...
InterpreterStateMachine _machine = new InterpreterStateMachine();
InMemorySagaRepository<InterpreterInstance> _repository = new InMemorySagaRepository<InterpreterInstance>();
...
x.ReceiveEndpoint(host, "state_machine", e =>
{
e.PrefetchCount = 1;
//here the state machine is set
e.StateMachineSaga(_machine, _repository);
e.Durable = false;
});
4) Last but not least, the contracts are pretty small and look like this:
using System;
namespace InterpreterStateMachine.Contracts
{
public interface IValidationNeeded
{
Guid RequestId { get; }
Request Request { get; }
}
}
So overall it's pretty straightforward, I just had to use my brain :D
I hope this will help someone.
enter code hereI have following method where i need to write unit test case to test this method.
public void ProcessDormantApplications()
{
List<long> dormantApplicationIDs = new List<long>();
dormantApplicationIDs = service.GetDormantApplications();
if (dormantApplicationIDs.Count > 0)
{
foreach (long dormantID in dormantApplicationIDs)
{
string msg = service.UpdateDormantApplications(dormantID);
}
}
}
}
and this is the TEST method i wrote.
[TestClass]
public class DormantApplicationsTest
{
ILogger logger;
IService Service;
[TestInitialize]
public void SetUp()
{
logger = MockRepository.GenerateStub<ILogger>();
Service = MockRepository.GenerateStub<IService>();
}
[TestMethod]
public void TESTProcessDormantApplications()
{
////arrange
////act
var target = new BLogic(service, logger);
target.ProcessDormantApplications();
////assert
// service.AssertWasCalled(x => x.
}
}
The actual method calls another service layer which inturn invokes web service to get data. In this scenario I am not sure what to ASSERT in this situation.
[TestMethod]
public void CheckProcessDormantApplications_InBetweenApplicationFailedToUpdate()
{
////arrange
var applicationIds = new List<long>()
{
1,2,3
};
UpdateResponse.isSuccess = true;
UpdateResponse.errorMessage = string.Empty;
Service.Stub(x => x.GetDormantApplications()).Return(applicationIds);
for(int i=0; i <= applicationIds.Count-1; i++)
{
if (i == 1) //set this application id response to FALSE so it should continnue with next record as well
{
UpdateResponse.isSuccess = false;
UpdateResponse.errorMessage = "making it fail for test";
}
Service.Stub(x =>x.UpdateDormantApplications(applicationIds[i])).Return(UpdateResponse);
}
////act
var target = new BLogic(Service, logger);
target.ProcessDormantApplications();
////assert
foreach (long id in applicationIds)
{
Service.AssertWasCalled(x => x.UpdateDormantApplications(id));
}
}
}
Based on the code you provide you have to set a behavior on GetDormantApplications which return some ids, then verify that UpdateDormantApplications was called for each id:
[TestMethod]
public void Check_ProcessDormantApplications()
{
////arrange
var applicationId = new List<long>()
{
//put here some ids
};
DormantServiceAdapter.Stub(x => x.GetDormantApplications()).Return(applicationId);
var target = new DormantApplicationsBusinessLogic(DormantServiceAdapter, logger);
////act
target.ProcessDormantApplications();
////assert
foreach (var id in applicationId)
{
DormantServiceAdapter.AssertWasCalled(x => x.UpdateDormantApplications(id));
}
}
We have today an event based application centered completely on desktop. We want to move to web and drive events using Web Sockets using Fleck. I was unable to figure out how to send message asynchronously from server to client in fleck. Below is the sample for what I am trying to achieve
public class Program
{
static readonly WebSocketServer _webSocketServer = new WebSocketServer("ws://127.0.0.1:8181");
static readonly List<IWebSocketConnection> SocketClients = new List<IWebSocketConnection>();
static void Main(string[] args)
{
_webSocketServer.Start(socket =>
{
socket.OnOpen = () =>
{
SocketClients.Add(socket);
OnOpening(socket.ConnectionInfo.Id);
};
socket.OnClose = () =>
{
OnClosing(socket.ConnectionInfo.Id);
SocketClients.Remove(socket);
};
socket.OnMessage = message => OnMessage(message, socket.ConnectionInfo.Id);
});
Console.ReadLine();
}
private static void OnMessage(string message, Guid id)
{
Console.WriteLine("<i> Recived message " + message + " from Client Id : " + id + " </i>");
}
private static void OnClosing(Guid id)
{
Console.WriteLine("<i> Client Left With Id : " + id + "</i>");
}
private static void OnOpening(Guid id)
{
//Do Something
}
// CALL THIS METHOD FROM MY APPLICATION AND SEND THE MESSAGE TO CLIENT BASED ON THE ID
private static void SendMessage(string message, Guid id)
{
// HOW TO DO SOMETHING LIKE BELOW SEND MESSAGE ASYNC
//_webSocketServer.Start(socket =>
//{
// var clientToSend = SocketClients.Find(client => client.ConnectionInfo.Id == id);
// socket.Send(message);
//});
}
}
You have a similar example in their GitHub: https://github.com/statianzo/Fleck/blob/master/src/Samples/ConsoleApp/Server.cs
I just added the SendToSocketById method>
class Server
{
static void Main()
{
FleckLog.Level = LogLevel.Debug;
var allSockets = new List<IWebSocketConnection>();
var server = new WebSocketServer("ws://0.0.0.0:8181");
server.Start(socket =>
{
socket.OnOpen = () =>
{
Console.WriteLine("Open!");
allSockets.Add(socket);
};
socket.OnClose = () =>
{
Console.WriteLine("Close!");
allSockets.Remove(socket);
};
socket.OnMessage = message =>
{
Console.WriteLine(message);
allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
};
});
var input = Console.ReadLine();
while (input != "exit")
{
foreach (var socket in allSockets.ToList())
{
socket.Send(input);
}
input = Console.ReadLine();
}
}
static void SendToSocketById(String input, Guid id)
{
var socket = allSockets.Find(client => client.ConnectionInfo.Id == id);
socket.Send(input);
}
}