I'm making bot for online game.
It works, but it is singlethread application.
I want to make it multithread application.
I know how background worker works.
To all my tasks I use one WebClient with added Cookie support.
My for example needs to open one page, wait 10 min and do next instruction.
I also want to be able to stop bot at any time.
Do I have to pass my WebClient object to background worker to work with?
What is the best way to update controls on my Form?
I have one class that has all the values that I want to show on Main Form.
Should I fire some event when property changes? If yes, can you give me example?
UPDATE:
This is my Special WebClient:
using System;
using System.Net;
namespace Game_Bot
{
class WebClientEx : WebClient
{
public CookieContainer CookieContainer { get; private set; }
public WebClientEx()
{
CookieContainer = new CookieContainer();
}
public void ClearCookies()
{
CookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = CookieContainer;
}
return request;
}
}
}
Is this good way of updating UI? Or is there any beter?
public void SetStatus(string status)
{
if (TransferLeftLabel.Dispatcher.Thread == Thread.CurrentThread)
{
TransferLeftLabel.Text = status;
}
else
{
TransferLeftLabel.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => { SetStatus(string status); }));
}
}
This is how I would do it:
First:
I like to manage threads manually instead of using the BackgroundWorker control when making multithreads applications like the one you want to modify.
To start a new thread, it is as simple as:
public void SomeMethod() {
var thread = new Thread(MyMethod);
thread.Start(); //Will start the method
}
public void MyMethod() {
//Do whatever you want inside the thread here
}
You can get as many Thread instances as you want, store them in a list, and manage how you prefer. However, it isn't true that the more threads the better. Search in Google.
About opening pages and keeping Cookies.
I think you could have an instance of a class in your Form, or where you have the logic (some place that threads can access), (let's name it WebUtils) with a method like: GoToUrl(<url here>) or something like that, and a CookieCollection as a field in that class to keep cookies.
Something you should take in count:
When calling GoToUrl, you might need to do lock when accessing the cookies variable, to avoid inconsistency.
About updating controls:
You can create an event inside the class WebUtils, and everytime the page is accessed you can fire this event. Before starting the threads, you must subscribe to the event in your Form, you can do something similar with lock when updating/accessing/modifying controls in your form.
Now, how to avoid the message Control ____ accessed from a thread other than the thread it was created...?
Here's an example:
If you want to modify property Text of the control textBox1, instead of just doing:
textBox1.Text = "Ey, I accessed the site
you can do:
MethodInvoker m = () => { textBox1.Text = "Ey, I accessed the site" };
if (InvokeRequired)
BeginInvoke(m);
else
m.Invoke()
Make sure all the modifications are done like that.
This is just an overview. I'm not a thread expert.
Here is good reference about threadings in general: Threading in C#
Edit:
Take a look at the IsBackground property of threads. That could be the cause of application freezes when you just want to cose it.
I suggested creating a class WebUtils, or however you want to name, because that's how I've created it in the past.
Something like:
public class WebUtils {
CookieContainer _cookies;
public WebUtils() {
_cookies = new CookieContainer();
}
public void AccessPage(string url) {
//Here I create a new instance of a HttpWebRequest class, and assign `_cookies` to its `Cookie` property.
//Don't really know if `WebClient` has something similar
}
}
Related
Quite a few questions/answers on this topic (only listing a couple that I found. There were many more).
C# Parallel - Adding items to the collection being iterated over, or equivalent?
ConcurrentQueue with multithreading
Thanks to many of them I've come up with what I'm hoping is a possible solution for my problem. I may also be overthinking it. I have an api that needs to write to a text file for logging purposes. Now the api is called N+ times and during each call, it needs to log the request. What I don't want to do is to stop the request from having to wait on the log to be recorded before returning the requested data. Now, the logs cannot just be dropped so it must also stack up on each request if the file is currently in use, using ReaderWriterLock for this. Then when the file isn't locked, I want to write the stacked logs.
I have come up with this in the hopes that it would satisfy the requirements but I think it will still cause a wait.
var wid = WindowsIdentity.GetCurrent().Token;
//add new log items
logs.Enqueue(helpers.createNewLog(requests));
string op;
while (logs.TryDequeue(out op))
{
using (WindowsIdentity.Impersonate(wid))
{
//write to text file, location on shared drive
var wrote = writers.WriteLog(op);
//item cannot be written since file locked, add back to queue to try again
if (!wrote)
{
logs.Enqueue(op);
}
}
}
Logs is a global like so
private static ConcurrentQueue<string> logs = new ConcurrentQueue<string>();
I feel like something isn't right but I'm struggling with what it is and which would be the best way in order for the requirements to be meet and still work in a web farm.
In my opinion, you should use a BlockingCollection instead of the ConcurrentQueue, here is an example of how you can use it as a Producer-Consumer is the same thing you are trying to do.
Now with ASP.Net you can insert modules to intercept every request, if you want to save a log, I suggest you register a module instead of going with your approach. On your Global.asax.cs you have a Register method
public class MvcApplication : System.Web.HttpApplication
{
public static void Register()
{
//registering an HttpModule
HttpApplication.RegisterModule(typeof(LogModule));
}
....
}
public class LogModule: IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.LogRequest += LogEvent;
}
private void LogEvent(object src, EventArgs args)
{
if (HttpContext.Current.CurrentNotification == RequestNotification.LogRequest)
{
if ((MvcHandler)HttpContext.Current.Handler != null)
{
Debug.WriteLine("This was logged!");
//Save the information to your file
}
}
}
}
Hope this helps
I have two methods in a C# business logic class. I need a flag mechanism so that one method can update the flag and the other method will react when the flag is updated. Below I will paste my situation, which is very simple:
// BusinessLogic.cs
bool photoResizingFinished = false;
public int SavePhoto() {
while (!photoResizingFinished) {
System.Threading.Thread.Sleep(100);
Trace.TraceInformation("PhotoResizingWorkerRole has not finnished yet.");
} }
public bool UpdateStatus(bool statusUpdate) {
photoResizingFinished = statusUpdate;
return true;
}
The two methods above live in the same class BusinessLogic.cs.
The only thing I need is to be able to have SavePhoto() react when
the bool photoResizingFinished is updated by UpdateStatus(bool statusUpdate)
You can use the class as a webservice and implement callback function that called when the ws finishes its work.
example code:
<script>
var timerID = setTimeout(CallWS, 1000)//call a js func which calls the WevService
function CallWS()
{
clearTimeout(timerID)//to stop the calling...
WSClassName.WSFuncName(param1,param2,....,callBackSuccess,callBackFailur)
///the param1,param2 are according to the parameter the function is expected to get.
}
function callBackSuccess(result,eventArgs)
{
//When the WS function finished successfuly
//**set flag to true.**
}
function callBackFailur(result,eventArgs)
{
//when error occured in the WS function
alert(result.get_message()).
}
</script>
Let me know if you need more help...
goodluck!
You could try using the Task class from .Net 4. It allows you to queue up tasks, so your SavePhoto() code would wait until the PhotoResizing() method finished.
Here's a nice article on the Task namespace if you want more details: http://www.codethinked.com/net-40-and-systemthreadingtasks
using System.Threading.Tasks;
public void SavePhoto(CancellationTokenSource taskCancellationTokenSource){
// preliminary code
// start resize
Task resizeTask = Task.Factory.StartNew( ResizePhoto, taskCancellationTokenSource ) ;
// queue up final save method
Task finalTask = resizeTask.ContinueWith(t => {
if (!t.IsFaulted && !t.IsCancelled){
FinishSaving();
}
});
// Wait for everything to finish
finalTask.Wait(taskCancellationTokenSource);
}
public void ResizePhoto(){
// code
}
public void FinishSaving(){
// code
}
I'd change the bool like this:
bool _photoResizingFinished=false;
bool photoResizingFinished
{
get{return _photoResizingFinished;}
set
{
if(value) SavePhoto();
_photoResizingFinished=value;
}
}
Or, you can make UpdatePhoto() call SavePhoto() after updating the bool. Might be a better solution.
Maybe I have found a solution to my problem using a Multithreaded Singleton
http://msdn.microsoft.com/en-us/library/ff650316.aspx
Here are some attempts of implementation:
http://forums.asp.net/t/1783765.aspx/2/10?How+to+have+two+methods+of+the+same+class+flag+to+eachother+
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/abd53523-658b-442a-bac0-1c74c1d90a90
I don't understand the mecanics of this myself totally, but I hope it's ok.
I'm using a WebBrowser control to automate management of a web page. When I start my WPF application, it shows the webpage ant lets me login. Then my application starts to do some automated tasks by going to a page, filling a form and submitting (it’s a POST-form). It submits the same form ~100 times with different values.
Right now my code is as follows:
void webBrowser1_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var doc = (HTMLDocument) webBrowser1.Document;
var form = doc.getElementById("theForm");
SetValueOfFormInput(doc, "id", Foo.ID);
SetValueOfFormInput(doc, "item1", Foo.Item1);
SetValueOfFormInput(doc, "item2", Foo.Item2);
form.all.item("submit").click();
}
private static void SetValueOfFormInput(HTMLDocument doc, string name, string value)
{
var item = doc.all.item(name);
item.setAttribute("value", value);
}
Can I do this on a better way and can I do it in a MVVM way?
And no, I can't modify the the webpage to do the management easier :-(
Edit:
Ideally, I would be able to do this without having to use the WebBrowser control. The program logon to the website and performs all tasks without having to modify the forms in the html pages
Why not using the WebClient or WebRequest classes?
For the webclient, you can use the UploadValues method which will do exactly what you want (http://msdn.microsoft.com/en-us/library/9w7b4fz7.aspx) and you can also simply addapt the class to use cookies so your login will be "permanent" (http://stackoverflow.com/questions/1777221/c-using-cookiecontainer-with-webclient-class)
If you like to do it even more model driven, i would use the WebRequest (has allready a cookiecontainer) and have some class with the needed data. This one would derive from a class, which can serialize all needed properties into a simple string you would post to the server - AFAIK it's same like the getter-parameters (param1=val1¶m2=val2&...)
so basically:
class Data : Postable { public string Param1{get;set;} public string Param2{get;set;} ...}
class Postable
{
public override string ToString()
{
StringBuilder ret = new StringBuilder();
foreach(Property p in GetType().GetProperties())
{
ret.Append("{0}={1}&", p.Name, p.<GetValue>);
}
return ret.ToString();
}
}
Suppose I have the following class:
Public class FooBar
{
List<Items> _items = new List<Items>();
public List<Items> FetchItems(int parentItemId)
{
FetchSingleItem(int itemId);
return _items
}
private void FetchSingleItem(int itemId)
{
Uri url = new Uri(String.Format("http://SomeURL/{0}.xml", itemId);
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.BeginGetResponse(ReceiveResponseCallback, webRequest);
}
void ReceiveResponseCallback(IAsyncResult result)
{
// End the call and extract the XML from the response and add item to list
_items.Add(itemFromXMLResponse);
// If this item is linked to another item then fetch that item
if (anotherItemIdExists == true)
{
FetchSingleItem(anotherItemId);
}
}
}
There could be any number of linked items that I will only know about at runtime.
What I want to do is make the initial call to FetchSingleItem and then wait until all calls have completed then return List<Items> to the calling code.
Could someone point me in the right direction? I more than happy to refactor the whole thing if need be (which I suspect will be the case!)
Getting the hang of asynchronous coding is not easy especially when there is some sequential dependency between one operation and the next. This is the exact sort of problem that I wrote the AsyncOperationService to handle, its a cunningly short bit of code.
First a little light reading for you: Simple Asynchronous Operation Runner – Part 2. By all means read part 1 but its a bit heavier than I had intended. All you really need is the AsyncOperationService code from it.
Now in your case you would convert your fetch code to something like the following.
private IEnumerable<AsyncOperation> FetchItems(int startId)
{
XDocument itemDoc = null;
int currentId = startId;
while (currentID != 0)
{
yield return DownloadString(new Uri(String.Format("http://SomeURL/{0}.xml", currentId), UriKind.Absolute),
itemXml => itemDoc = XDocument.Parse(itemXml) );
// Do stuff with itemDoc like creating your item and placing it in the list.
// Assign the next linked ID to currentId or if no other items assign 0
}
}
Note the blog also has an implementation of DownloadString which in turn uses WebClient which simplifies things. However the principles still apply if for some reason you must stick with HttpWebRequest. (Let me know if you are having trouble creating an AsyncOperation for this)
You would then use this code like this:-
int startId = GetSomeIDToStartWith();
Foo myFoo = new Foo();
myFoo.FetchItems(startId).Run((err) =>
{
// Clear IsBusy
if (err == null)
{
// All items are now fetched continue doing stuff here.
}
else
{
// "Oops something bad happened" code here
}
}
// Set IsBusy
Note that the call to Run is asynchronous, code execution will appear to jump past it before all the items are fetched. If the UI is useless to the user or even dangerous then you need to block it in a friendly way. The best way (IMO) to do this is with the BusyIndicator control from the toolkit, setting its IsBusy property after the call to Run and clearing it in the Run callback.
All you need is a thread sync thingy. I chose ManualResetEvent.
However, I don't see the point of using asynchronous IO since you always wait for the request to finish before starting a new one. But the example might not show the whole story?
Public class FooBar
{
private ManualResetEvent _completedEvent = new ManualResetEvent(false);
List<Items> _items = new List<Items>();
public List<Items> FetchItems(int parentItemId)
{
FetchSingleItem(itemId);
_completedEvent.WaitOne();
return _items
}
private void FetchSingleItem(int itemId)
{
Uri url = new Uri(String.Format("http://SomeURL/{0}.xml", itemId);
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.BeginGetResponse(ReceiveResponseCallback, webRequest);
}
void ReceiveResponseCallback(IAsyncResult result)
{
// End the call and extract the XML from the response and add item to list
_items.Add(itemFromXMLResponse);
// If this item is linked to another item then fetch that item
if (anotherItemIdExists == true)
{
FetchSingleItem(anotherItemId);
}
else
_completedEvent.Set();
}
}
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 5 years ago.
I'm new with C# and I'm trying to make a simple client server chat application.
I have RichTextBox on my client windows form and I am trying to update that control from server which is in another class. When I try to do it I get the error: "Cross-thread operation not valid: Control textBox1 accessed from a thread other than the thread it was created on".
Here the code of my Windows form:
private Topic topic;
public RichTextBox textbox1;
bool check = topic.addUser(textBoxNickname.Text, ref textbox1, ref listitems);
Topic class:
public class Topic : MarshalByRefObject
{
//Some code
public bool addUser(string user, ref RichTextBox textBox1, ref List<string> listBox1)
{
//here i am trying to update that control and where i get that exception
textBox1.Text += "Connected to server... \n";
}
So how to do that? How can I update the textbox control from another thread?
I'm trying to make some basic chat client/server application using .net remoting.
I want to make windows form client application and console server application as separate .exe files. Here im trying to call server function AddUser from client and i want to AddUser function update my GUI. Ive modified code as you suggested Jon but now instead of cross-thread exception i've got this exception ... "SerializationException: Type Topic in Assembly is not marked as serializable".
Ill post my whole code bellow, will try to keep it simple as possible.
Any suggestion is welcome. Many thanks.
Server:
namespace Test
{
[Serializable]
public class Topic : MarshalByRefObject
{
public bool AddUser(string user, RichTextBox textBox1, List<string> listBox1)
{
//Send to message only to the client connected
MethodInvoker action = delegate { textBox1.Text += "Connected to server... \n"; };
textBox1.BeginInvoke(action);
//...
return true;
}
public class TheServer
{
public static void Main()
{
int listeningChannel = 1099;
BinaryServerFormatterSinkProvider srvFormatter = new BinaryServerFormatterSinkProvider();
srvFormatter.TypeFilterLevel = TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clntFormatter = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = listeningChannel;
HttpChannel channel = new HttpChannel(props, clntFormatter, srvFormatter);
// Register the channel with the runtime
ChannelServices.RegisterChannel(channel, false);
// Expose the Calculator Object from this Server
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Topic),
"Topic.soap",
WellKnownObjectMode.Singleton);
// Keep the Server running until the user presses enter
Console.WriteLine("The Topic Server is up and running on port {0}", listeningChannel);
Console.WriteLine("Press enter to stop the server...");
Console.ReadLine();
}
}
}
}
Windows form client:
// Create and register a channel to communicate to the server
// The Client will use the port passed in as args to listen for callbacks
BinaryServerFormatterSinkProvider srvFormatter = new BinaryServerFormatterSinkProvider();
srvFormatter.TypeFilterLevel = TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clntFormatter = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 0;
channel = new HttpChannel(props, clntFormatter, srvFormatter);
//channel = new HttpChannel(listeningChannel);
ChannelServices.RegisterChannel(channel, false);
// Create an instance on the remote server and call a method remotely
topic = (Topic)Activator.GetObject(typeof(Topic), // type to create
"http://localhost:1099/Topic.soap" // URI
);
private Topic topic;
public RichTextBox textbox1;
bool check = topic.addUser(textBoxNickname.Text,textBox1, listitems);
You need to either use BackgroundWorker, or Control.Invoke/BeginInvoke. Anonymous functions - either anonymous methods (C# 2.0) or lambda expressions (C# 3.0) make this easier than it was before.
In your case, you can change your code to:
public bool AddUser(string user, RichTextBox textBox1, List listBox1)
{
MethodInvoker action = delegate
{ textBox1.Text += "Connected to server... \n"; };
textBox1.BeginInvoke(action);
}
A few things to note:
To conform with .NET conventions, this should be called AddUser
You don't need to pass the textbox or listbox by reference. I suspect you don't quite understand what ref really means - see my article on parameter passing for more details.
The difference between Invoke and BeginInvoke is that BeginInvoke won't wait for the delegate to be called on the UI thread before it continues - so AddUser may return before the textbox has actually been updated. If you don't want that asynchronous behaviour, use Invoke.
In many samples (including some of mine!) you'll find people using Control.InvokeRequired to see whether they need to call Invoke/BeginInvoke. This is actually overkill in most cases - there's no real harm in calling Invoke/BeginInvoke even if you don't need to, and often the handler will only ever be called from a non-UI thread anyway. Omitting the check makes the code simpler.
You can also use BackgroundWorker as I mentioned before; this is particularly suited to progress bars etc, but in this case it's probably just as easy to keep your current model.
For more information on this and other threading topics, see my threading tutorial or Joe Albahari's one.
Use Invoke method
// Updates the textbox text.
private void UpdateText(string text)
{
// Set the textbox text.
yourTextBox.Text = text;
}
Now, create a delegate that has the same signature as the method that was previously defined:
public delegate void UpdateTextCallback(string text);
In your thread, you can call the Invoke method on yourTextBox, passing the delegate to call, as well as the parameters.
yourTextBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[]{”Text generated on non-UI thread.”});