In my Solution I've 3 main projects (Server, Client and Special Client). In my test environment, (1) Special Client just displays a count of Buy/Sell/Executed orders every 5 seconds, (2) Client submits Buy/Sell order and (3) Server processes the order client submitted and send back to Client and Special Client. If I launch all 3 Apps by hitting Ctrl+F5 and let Client submit an order every 10 millisecond, all those app work without any problem and on Windows Task Manager I've observed that the memory usage by Client fluctuates between 115MB and 320MB, none of those crash (I've tested for long time).
If I launch 2 more Client from ../Client/bin/Debug/... (3 instances of Client altogether, 1 Special Client and 1 Server) and let each Client submit 20 orders a second, it also works fine (not sure BUT probably performance of each Client deteriorates slightly). If I, however, launch 4th Client from ../Client/bin/Debug/... and let each of them submit 20 orders a second, I eventually get the StackOverflow exception on one of those Client.
So, in a nutshell, a single Client can submit 100 orders/second and get all those back from Server and present info on a moderately complex UI without trouble on a single Computer, 3 Client together can handle 60 orders/second BUT 4 Client together can't handle 80 orders/second!
Why?
EDIT
This is the message I get in Call Stack window:
[External Code]
> Client.dll!Client.AsyncObsetion<Data.AllOrder>.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e) Line 29 C#
[External Code]
Client.dll!Client.ClientCode.UpdateOrderOnExecution(Data.AllOrderStruct order) Line 431 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 390 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
.
.
.
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
[External Code]
Line 29 C# refers to this line else context.Send(RaisePropertyChanged, e); of this piece of code:
public class AsyncObsetion<T> : ObservableCollection<T>
{
SynchronizationContext context = SynchronizationContext.Current;
readonly object _lock = new object();
public AsyncObsetion() { BindingOperations.EnableCollectionSynchronization(this, _lock); }
public AsyncObsetion(IEnumerable<T> list) : base(list) { BindingOperations.EnableCollectionSynchronization(this, _lock); }
void RaiseCollectionChanged(object param) => base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
void RaisePropertyChanged(object param) => base.OnPropertyChanged((PropertyChangedEventArgs)param);
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaiseCollectionChanged(e);
else context.Send(RaiseCollectionChanged, e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaisePropertyChanged(e);
else context.Send(RaisePropertyChanged, e);
}
public void InsertRange(IEnumerable<T> items)
{
CheckReentrancy();
foreach (var item in items) Items.Add(item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
BUT I don't have any subscriber in my code for that event! Line 431 refers to this line if (order.ExType == ExecutionType.Full) list.Remove(o); this piece of code:
void UpdateOrderOnExecution(AllOrderStruct order)
{
bool buyOrder = order.OrderType == OrderType.Buy;
var list = buyOrder ? BuyOrders : SellOrders;
var o = buyOrder ? list.Where(x => x.BuyOrderNo == order.BuyOrderNo).First() : list.Where(x => x.SellOrderNo == order.SellOrderNo).First();
o.ExType = order.ExType;
if (order.ExType == ExecutionType.Full) list.Remove(o);
else
{
var index = list.IndexOf(o);
o.Quantity -= order.QtyTraded;
list[index] = o;
}
AddExecutedOrder(order);
if (order.BrokerBought == BrokerName || order.BrokerSold == BrokerName) UpDatePendingOrders(o);
App.Current.Dispatcher.Invoke(CommandManager.InvalidateRequerySuggested);
}
Line 390 refers to this Line case Data.Action.Execute: UpdateOrderOnExecution(order); break; and 402 refers to this line if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e); of this piece of code:
void Receive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
var data = PacMan<MessageHeader>.Unpack(e.Buffer);
if (data.Type == Message.Trade)
{
e.SetBuffer(orderBuffer, 0, orderBuffer.Length);
e.AcceptSocket.Receive(e.Buffer);
var order = PacMan<AllOrderStruct>.Unpack(e.Buffer);
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
else
{
SetBuffer(e, data.Size);
e.AcceptSocket.Receive(e.Buffer);
var array = e.Buffer.ToArray();
Task.Run(() => AddNews(array));
}
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e);
}
else Disconnect4mServer(null);
}
You should use multithreading approach i dont see any problem in your code because you are using 3 project at the same time try using multithreading and let the cpu handle it for you
That 'iterative' keyword of Charles gave me a hacky Idea. For anyone interested to solve this type of problem, here's my hacky approach with heap:
1) create these three variables in Client and Special Client:
Queue<byte[]> Orders = new Queue<byte[]>();
Timer orderProcessTimer;
bool OPTstarted;
2) make changes in Receive function in both of those projects to transfer orders to heap and start the orderProcessTimer there once by replacing that with these:
void Receive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
var data = PacMan<MessageHeader>.Unpack(e.Buffer);
if (data.Type == Message.Trade)
{
e.SetBuffer(orderBuffer, 0, orderBuffer.Length);
e.AcceptSocket.Receive(e.Buffer);
Orders.Enqueue(e.Buffer.ToArray());
}
else
{
SetBuffer(e, data.Size);
e.AcceptSocket.Receive(e.Buffer);
AddNews(e.Buffer.ToArray());
}
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!OPTstarted)
{
orderProcessTimer.Start();
OPTstarted = true;
}
if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e);
}
else Disconnect4mServer(null);
}
3) initialize the orderProcessTimer in constructor, set processing inverval and hook it into an order processing function:
orderProcessTimer = new Timer(500);
orderProcessTimer.Elapsed += ProcessOrder;
4) do the time consuming tasks in ProcessOrder function:
void ProcessOrder(object sender, EventArgs e)
{
orderProcessTimer.Stop();
var count = Orders.Count;
if(count > 0)
{
for (int i = 0; i < count; i++)
{
var order = PacMan<AllOrderStruct>.Unpack(Orders.Dequeue());
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
}
orderProcessTimer.Start();
}
UpdateOrderOnExecution takes the most of the time for processing a order and making a real time Price-Volume chart in order view.
It works BUT I probably will not go with this approach, I'll make the machine, that runs such type of app, a half-stack machine for the performance.
Related
private async void NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
{
if (_webViewDisposed > 0)
{
_logger.LogWarning("NavigationCompleted : WebViewDisposed");
OnWebViewFailure();
return;
}
if (!e.IsSuccess)
{
_logger.LogError($"NavigationCompleted: {e.WebErrorStatus}");
OnWebViewFailure();
return;
}
Here NavigationCompleted gets WebErrorStatus=ConnectionAborted
In the constructor I have WebView.NavigationCompleted += NavigationCompleted;
And on some other place I have WebView.CoreWebView2.NavigateToString(_viewModel.Content);
The content is valid HTML.
I have also successfuly initialzed Webview object here:
await WebView.EnsureCoreWebView2Async(WebViewHelper.Instance);
_logger.LogInfo($"Version: {WebView.CoreWebView2.Environment?.BrowserVersionString}, UserDataFolder: {WebView.CoreWebView2.Environment?.UserDataFolder}.");
await _baseWebViewMessageHandler.InjectScript();
It just fails sometimes. Can you hint what could be reason of WebErrorStatus=ConnectionAborted?
It turned out that WebView.CoreWebView2.NavigateToString(_viewModel.Content) was called twice on the same time.
I solve with this:
if (Interlocked.Increment(ref _navigateWebViewToContent) == 1)
{
WebView.CoreWebView2.NavigateToString(_viewModel.Content);
}
I am using the TAPI 2.0 wrapper from JulMar (https://atapi.codeplex.com/) and I'm having trouble with it.
The Initialization
void initTAPI()
{
myTAPI = new TapiManager("GetCaller");
if (!myTAPI.Initialize())
{
MessageBox.Show("FAILED!");
}else
{
name = myTAPI.Lines[0].Name;
lineName = (myTAPI != null && myTAPI.Lines.Length > 0 ? name : string.Empty);
foreach(TapiLine line in myTAPI.Lines)
{
line.NewCall += this.OnNewCall;
line.Ringing += this.OnRinging;
line.CallStateChanged += this.OnCallState;
line.CallInfoChanged += this.OnCallInfo;
}
MessageBox.Show(lineName);
}
}
So I get the lineName. When I now dial a number through the program, it fires
OnCallState
private void OnCallState(object sender, CallStateEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallStateEventArgs>(this.OnCallState), new object[] { sender, e });
return;
}
label1.Text = "Outgoing Call...";
}
But what I actually want to do is to get the number of an incoming call, but OnCallInfo does not get fired.
OnCallInfo
private void OnCallInfo(object sender, CallInfoChangeEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallInfoChangeEventArgs>(this.OnCallInfo), new object[] { sender, e });
return;
}
label1.Text = "Incoming Call...";
}
It says somehwere, that it only works with x86, so I changed the target but still no success.
PS: I have a call manager (ProCall) installed on the same machine, that tells me when someone calls, so I should be able to get the info in c# as well?
Here is the whole code if someone is interested: http://pastebin.com/Q5W5iGun
Depending on TSP, you may get call info messages, but TAPI does not force the driver to do this. So some TSP make you get the info yourself. In the Win32 API this is done via lineGetCallInfo.
After a quick look in this atapi wrapper, this happens in the GatherCallInfo method of the TapiCall class. However I can see no way to trigger this manually in this wrapper. You would need to modify the atapi source to make this a public method.
You can use example from TAPI which do the same. The only difference is new line.Monitor() method
foreach (TapiLine line in tapiManager.Lines)
{
try
{
line.NewCall += OnNewCall;
line.CallStateChanged += OnCallStateChanged;
line.CallInfoChanged += OnCallInfoChanged;
line.Monitor();
}
catch (TapiException ex)
{
LogError(ex.Message);
}
}
For further reading read this https://atapi.codeplex.com/SourceControl/latest#Atapi/trunk/source/test/TcMon/TapiMonitorForm.cs
In my Silverlight application, I put the WCF call in my ViewModel class.
DateTime CurrentDateTime;
internal void GetDateTime()
{
var client = new WcfClient();
client.GetCurrentDateTimeCompleted += GetCurrentDateTimeCompleted;
client.GetCurrentDateTimeAsync();
}
private void GetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
try
{
CurrentDateTime = args.Result;
}
Then in my code behind code some.xaml.cs file. I have a checkbox clicked event.
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var msgBoxControl = new MessageBoxControl();
msgBoxControl.Closed -= MessageBoxYesNo_Closed;
msgBoxControl.Closed += MessageBoxYesNo_Closed;
Inside the method MessageBoxYesNo_Closed, I call the method in the ViewModel class.
private void MessageBoxYesNo_Closed(object sender, EventArgs e)
{
try
{
this.ViewModel.GetDateTime();
curDateTime = this.ViewModel.CurrentDateTime;
My question is that sometimes the line curDateTime = this.ViewModel.CurrentDateTime; is executed before wcf call completed method, so I can't get the right value.
I guess that it may be there are two threads, one is in UI, the other one is in service call? Please don't use async/await as I have to use Visual Studio 2010.
Thanks
Get the solution, just add a while loop:
this.ViewModel.GetDateTime();
while (true)
{
this.ViewModel.CurrentDateTime = DateTime.Now;
if (this.ViewModel.CurrentDateTime != DateTime.MinValue)
break;
}
curDateTime = this.ViewModel.CurrentDateTime;
I am trying to make a program that, at the same time, displays text that the user inputted and writes to a text file of that same user input data. I've tried wrapping the the code with Task.Run:
private void button_Click(object sender, RoutedEventArgs e)
{
show.Text = inputText.Text;
//Debug.WriteLine(check1_cont.ToString());
//Debug.WriteLine(check2_cont.ToString());
if (check1_cont && check2_cont == true )
{
show2.Text = inputText.Text;
Task.Run(() => File.WriteAllText(#"A:\temp\name.txt", inputText.Text));
}
}
But I get an exception error after the second text (the one in the if statement) when I press the button:
An exception of type 'System.Exception' occurred in normieap.exe but
was not handled in user code
Additional information: The application called an interface that was
marshalled for a different thread. (Exception from HRESULT: 0x8001010E
(RPC_E_WRONG_THREAD))
I try using StreamWriter:
private void button_Click(object sender, RoutedEventArgs e)
{
show.Text = inputText.Text;
//Debug.WriteLine(check1_cont.ToString());
//Debug.WriteLine(check2_cont.ToString());
if (check1_cont && check2_cont == true )
{
show2.Text = inputText.Text;
using (StreamWriter writer = new StreamWriter(#"A:\temp\name.txt"))
{
writer.WriteLine(inputText.Text);
}
}
}
But I get an error on the line:
using (StreamWriter writer = new StreamWriter(#"A:\temp\name.txt"))
Because '#"A:\temp\name.txt"' cannot convert from 'string' to 'System.IO.Stream'
And when I try just the normal way without any wrappers I get a synchronous error. Any solutions to this problem would be much appreciated.
When you run a task asyncrounously, it isn't guaranteed to run on the UI thread. Take your first example and try this:
private void button_Click(object sender, RoutedEventArgs e)
{
show.Text = inputText.Text;
//Debug.WriteLine(check1_cont.ToString());
//Debug.WriteLine(check2_cont.ToString());
if (check1_cont && check2_cont == true )
{
show2.Text = inputText.Text;
// Copy the text to output
string outputToWrite = inputText.Text;
// use the copied text
Task.Run(() => File.WriteAllText(#"A:\temp\name.txt", outputToWrite));
}
}
What's going on here is that a background thread is trying to access a GUI element. That's generally not allowed in singled threaded UI libraries like Windows Forms, so you need to copy the data out of the control before sending it back to the background thread, otherwise the code will fail as you have seen.
I am trying to login to my website automatically using webBrowser control in my C# application. The webpage checks the time required to fill and submit the login form. If the time taken is less than 2 seconds, then it shows an 'error page' saying 'Robots not allowed'.
Now my application is also getting that 'error page' just because the login form is getting filled within 2 seconds. How can I add a delay before firing the 'InvokeMember("click")' so that the time calculated by the webpage to fill the form be more than 2 seconds.
Here is my code
HtmlElement ele = WebBrowser1.Document.GetElementById("username");
if (ele != null)
{
ele.InnerText = "myUsrname";
}
ele = webBrowser1.Document.GetElementById("password");
if (ele != null)
{
ele.InnerText = "myPasswrd";
}
ele = webBrowser1.Document.GetElementById("submit");
if (ele != null)
{
// I want to add a delay of 3 seconds here
ele.InvokeMember("click");
}
Note : I used "Task.Delay(3000);" but it doesn't seems to work.
Edit : This is what I am using now and is working for me.
async void webBrowser1_DocumentCompleted_1(object sender, WebBrowserDocumentCompletedEventArgs e)
{
......//my code
await Task.Delay(3000);// this is where I wanted to put a delay
....
}
But I would like to, Is this a correct way to use it ?
If you want to don't freeze UI when waiting, Consider this sample:
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(async () =>
{
await Task.Delay(3000);
MessageBox.Show("1");
button1.Invoke(new Action(() => { this.button1.Text = "1"; }));
});
MessageBox.Show("2");
button1.Invoke(new Action(() => { this.button1.Text = "2"; }));
}
The sample is self describing.
You could use this:
int milliseconds = 2000;
Thread.Sleep(milliseconds)
Greetings,
ST