Problem with Delegates in C#, forms and multiple solutions - c#

EDIT: this is a winform application, sorry for the inconvenience
Disclaimer: this is an assignment we got in college, and I'm stuck over this particular section of code.
I have 2 solutions in Visual Studio 2008, one for a Form and one for a DLL which the form can use for functionality. The idea is to send HTML mails from the client, and to use the Delegate to confirm this.
One class of the DLL contains nothing else but a single Delegate:
namespace Console.Grand
{
public delegate void ObserverDelegate(string info);
}
In a file called Delegate.cs
In the form, I have the following method which I will use for the Delegate:
private void Update(string info)
{
this.logBox.Text += Environment.NewLine + info;
}
The logBox variable is a TextArea on the form.
On transmitting, the following occurs(BL stands for "Business Layer"):
BL_MailOut bm = new BL_MailOut(s1,ListViewAdresses());
ObserverDelegate deleg = new ObserverDelegate(Update);
bm.SendMail(deleg);
The BL_MailOut constructor looks like this(we're in the DLL now):
public BL_MailOut(StandardPage page, List<MailAddress> list)
{
this.s = page;
this.adresslist = new List<MailAddress>();
foreach (MailAddress m in list)
{
this.adresslist.Add(m);
}
}
And the method SendMail:
public void SendMail(ObserverDelegate deleg)
{
IO_MailOut im = new IO_MailOut(s, adresslist, deleg);
Thread t = new Thread(new ThreadStart(im.Send));
t.Start();
}
And finally, we arrive at the method Send():
public void Send()
{
SmtpClient sc;
MailMessage msg;
string info;
foreach (MailAddress adress in this.list)
{
try
{
sc = new SmtpClient(HOST);
msg = new MailMessage(SENDER, adress.Address);
msg.IsBodyHtml = true;
msg.Subject = "test";
msg.Body = page.ToString();
sc.Send(msg);
info = "(" + DateTime.Now + ") MAIL SENT TO" + Environment.NewLine + adress.Address;
deleg(info);
}
}
I do catch the needed errors, I just left that out here to save room.
When deleg(info); is reached, expected behavior would be that the textBox receives the needed text. However, it does not. The instance of the delegate is preserved and the compiler gives no error. I've read the material on the MSDN site on Delegates, but nothing there helped.

Your Update method on the form is performing a cross-thread operation, which is not allowed.
Change your Update method on the form to this
private void Update(string info)
{
ObserverDelegate callBack = new ObserverDelegate((x) =>
{
this.logBox.Text += Environment.NewLine + info;
});
if (this.InvokeRequired)
this.Invoke(callBack, info);
else
callBack(info);
}

I do something similar to this in my program...here is how I did it.
public void setBoxText(string value)
{
if (InvokeRequired)
Invoke(new SetTextDelegate(setBoxText), value);
else
statusBox.Text += value;
}
delegate void SetTextDelegate(string value);
I then call setBoxText whenever I want to append text to the box.

Related

How to implement custom command line & execution

I'm trying to build a custom commandline for my app, i have several basic commands, and i simply use bunch of "if" statements to check what the command is. currently it looks something like this
public void ExecuteCommand()
{
string input = ReadLine(); //gets last string from input
bool isDone = false; //need bool to check whether command was executed or no, by default false.
Match result = Regex.Match(input, #"([^\s]+)"); //to get command name
string commandName = result.Value.ToLower();
string value = Regex.Match(input, #"\s(.*)").Value; //to get its parameter. currently everything after ' ' space.
if (commandName == "close")
{
Close(); isDone = true;
}
//so commandline is separate window, and appendedForm is a main form. in which some functions are executed.
if (commandName == "exit")
{
appendedForm.Close();
}
if (commandName == "spoof")
{
appendedForm.Fn_Spoof();
isDone = true;
}
if(commandName == "spoofstop")
{
appendedForm.Fn_StopCapture();
isDone = true;
}
if(commandName == "scan")
{
appendedForm.Fn_Scan(); isDone = true;
}
if(commandName == "clear")
{
output.Text = "";
WriteLine("Console cleared. Cache is empty.");
//data_lines.Clear();
isDone = true;
}
...
}
So that's basically it. I have a mainForm, and commandline form. string input is typed into commandline, then I check the name of command and execute some function from mainForm.
My question is, what is the best way of implementing such kind of thing? I surely can just continue writing bunch of "if"s, but something tells me that it's not the best way to make it.
I've thought of creating class "Command"
public class Command
{
public string name;
public string description;
public bool hasParameter;
Command()
{
}
}
And storing all commands in some sort of array, but I am not sure how would I use this to call a function from mainForm.
Any ideas are welcome!
You could stuff all commands into a Dictionary<string, someDelegate>; if you can live with all commands having the same return type.
I have used string and set up a few commands.
I make use of the params keyword to avoid the ugly new object[] on each call.
You still need to cast the arguments, unless you can make them all one type. (Which may actually be not such a bad idea, as they all come from an input string..)
Here is an example:
public delegate string cmdDel(params object[] args);
Dictionary<string, cmdDel> cmd = new Dictionary<string, cmdDel>();
Add a few functions:
cmd.Add("clear", cmd_clear);
cmd.Add("exit", cmd_exit);
cmd.Add("add", cmd_add);
cmd.Add("log", cmd_log);
With these bodies:
public string cmd_clear(params object[] args)
{
return "cleared";
}
public string cmd_exit(params object[] args)
{
return "exit";
}
public string cmd_add(params object[] args)
{
return ((int)args[0] + (int)args[1]).ToString();
}
public string cmd_log(params object[] args)
{
StringBuilder log = new StringBuilder();
foreach (object a in args) log.Append(a.ToString() + " ");
return log.ToString();
}
And test:
Console.WriteLine(cmd["clear"]());
Console.WriteLine(cmd["add"]( 23, 42));
Console.WriteLine(cmd["log"]( 23, "+" + 42, "=", cmd["add"]( 23, 42) ));
Console.WriteLine(cmd["exit"]());
cleared
65
23 + 42 = 65
exit
Of course you still need to use (at least) as many lines for setup as you have commands. And also need to do a similar amount of error checking.
But the command processing part can get pretty simple.

Suppress "yourdomain.com could not be found" dialog in GeckFX45

I am using GeckFX45 from NuGet to host a webpage for my OAuth2 login, During testing its behavior without internet connection I noticed that I get a dialog generated by the browser saying the URL could not be found. How can I suppress this to I can catch and handle the scenario in my app without alerting user?
My browser code is pretty standard, but for arguments sake included here anyway (Note I am using WPF not Win Forms hence the host control):
public OAuthLogin2(OAuthActions action, string args = null)
{
this.action = action;
Gecko.Xpcom.Initialize("Firefox");
host = new WindowsFormsHost();
browser = new GeckoWebBrowser();
browser.DocumentCompleted += Browser_DocumentCompleted;
browser.Navigating += Browser_Navigating;
browser.NavigationError += Browser_NavigationError;
browser.NSSError += Browser_NSSError;
InitializeComponent();
host.Child = browser;
GridWeb.Children.Add(host);
}
I can add a PromptService, but this may not work depending on language;
public class NoPromptService : PromptService
{
public override void Alert(string dialogTitle, string text)
{
log.Warn(dialogTitle, new Exception(text));
if (text.EndsWith("could not be found. Please check the name and try again."))
{
// Do Whatever
}
}
}
Add this in constructor:
PromptFactory.PromptServiceCreator = () => new NoPromptService();

Unable to get a string out of a method

I am really new to coding, never studied it or something similar, just learning it myself, never done it before, but I am trying to create my first real application right new.
However, I have some problems for 2 days which I just can't figure out, so I hope you can help me out.
Alright, so before the youtubedlCurrentWorker_Process() is created, I did define 'public string CurrentYouTubeDLVersion'.
How ever, when a button in my application executes the youtubedlCompareVersion_Process(), the CurrentYouTubeDLVersion string is empty, when it comes at the compare point.
Below is just a little part of my code.
Why is the string CurrentYouTubeDLVersion empty in the CompareVersion while the GetCurrentVersion ran before it?
Even if I double click "CurrentYouTubeDLVersion" in Visual Studio, it won't show a link to the one in the GetCurrentVersion_Process.
namespace MediaDownloader
{
public partial class updates : UserControl
{
public string LatestYoutubeDLVersion;
public string CurrentYouTubeDLVersion;
public void youtubedlGetCurrentVersion_Process()
{
if (File.Exists(YouTubeDLPath))
{
//Here I get the current version of youtube-dl.exe, to get the version number, we have to run youtube-dl.exe --version
Process youtubedl = new Process();
youtubedl.StartInfo.CreateNoWindow = true;
youtubedl.StartInfo.UseShellExecute = false;
youtubedl.StartInfo.RedirectStandardOutput = true;
youtubedl.StartInfo.RedirectStandardError = true;
youtubedl.StartInfo.FileName = YouTubeDLPath;
youtubedl.StartInfo.Arguments = " --version";
youtubedl.Start();
string CurrentYouTubeDLVersion = youtubedl.StandardOutput.ReadToEnd();
this.Dispatcher.Invoke((Action)(() =>
{
CurrentYouTubeDLVersionText.Text = "Current youtube-dl.exe version: " + CurrentYouTubeDLVersion;
YouTubeDLVersionStatusText.Text = null;
UpdateYouTubeDL.IsEnabled = false;
}));
}
public void youtubedlCompareVersion_Process()
{
youtubedlGetCurrentVersion_Process();
string LatestYoutubeDLVersion = WebClient.DownloadString("https://yt-dl.org/latest/version");
MessageBox.Show("Latest:" + LatestYoutubeDLVersion + "Current " + CurrentYouTubeDLVersion);
int YouTubeDLUptodate = CurrentYouTubeDLVersion.CompareTo(LatestYoutubeDLVersion);
if (YouTubeDLUptodate < 1)
{
YouTubeDLVersionStatusText.Text = "Your youtube-dl.exe is out of date, please click the button below to update.";
UpdateYouTubeDL.IsEnabled = true;
}
else
{
YouTubeDLVersionStatusText.Text = "youtube-dl.exe is up to date!";
UpdateYouTubeDL.IsEnabled = false;
}
}
}
Inside the youtubedlGetCurrentVersion_Process method, you're creating a new CurrentYouTubeDLVersion string, and it's completely separate from the public CurrentYouTubeDLVersion you added to the top of the class.
string CurrentYouTubeDLVersion = youtubedl.StandardOutput.ReadToEnd();
Assign to the class-level variable you made, instead of creating a new string:
CurrentYouTubeDLVersion = youtubedl.StandardOutput.ReadToEnd();
Then the value will be available to you in youtubedlCompareVersion_Process.
Take out the 'string' in front of CurrentYouTubeDLVersion and it should work
public youtubedlGetCurrentVersion_Process()
{
/* removed code to make easier to read */
//string CurrentYouTubeDLVersion = youtubedl.StandardOutput.ReadToEnd();
CurrentYouTubeDLVersion = youtubedl.StandardOutput.ReadToEnd();
/* removed code to make easier to read */
}

ClrZmq returning messages always to first started client

We're creating a WPF app in which we execute python scripts from different Test Stations and show the output in its corresponding output panel, To run the scripts in parallel we are using Task but when we run the scripts in parallel from the stations, We are getting the output of other stations also into the station that is started first, we're using the following code,
private void ZmqStatusListener(string endPoint)
{
using (Context context = new Context())
{
StatusPort = string.Empty;
TestResultPort = string.Empty;
using (Socket server = context.Socket(SocketType.REP))
{
try
{
if (isStatusContextActive == false || isPortChanged == true)
{
server.Bind(endPoint);
isStatusContextActive = true;
}
}
catch (ZMQ.Exception ex)
{
if (ex.Errno != 100)
{
string IPCPort = _globalParameters.GlbParam.GlbParamIpcStartPort;
if (IPCPort == string.Empty)
{
IPCPort = "0";
}
if (endPoint == EditorConstants.PortAddress.PortPrefix + IPCPort)
{
StatusPort = endPoint;
TestReultError = EditorConstants.CommonMessageTypes.TestReultError + ex.Message + EditorConstants.CommonMessageTypes.StackTraceMessage + ex.StackTrace;
}
StopExecOfScript(default(object));
isCancelledtask = true;
ScriptStatusDesc = new ScriptStatusDesc()
{
Status = "Failed",
statusDescription = "Failed"
};
}
}
while (true)
{
string message = server.Recv(Encoding.UTF8);
UpdateTestResults(message);
server.Send(" ACK", Encoding.UTF8);
// if (message == "Test Passed")
//break;
}
}
}
}
and for testing purpose we're breaking the while loop in this code based on a test message we kept in the python script, then we are able to get the output in the respective station correctly but this way we can only run in a synchronous fashion which we don't want as we require to run the test stations in parallel and the while loop should not break as it should be listening for the response.
We were able to solve the issue by getting clues doing a sample app to reproduce the issue and to first know whether our ClrZmq pattern was correct for us or not and it is correct. The resolution we followed is that when we needed to bind that data to its corresponding View's Model object in its ViewModel so had to retrieve View's DataContext which is of Type ISomeXViewModel for the particular TestStation using an Id of that TestStation we did this cos all of our TestStations are dynamically added and we even store it to be accessed wherever necessary. This issue was caused to due multiple instances of UserControls so we explicitly needed to update the TestStation manually with a little more effort.
Sample Code Snippet
private void BindTestResult(string xmlPayLoad)
{
// converting xmlPalLoad to a class/model object
ITestStationViewModel viewModel = (ITestStationViewModel)((IView)DynamicTestStationsGrid.Children[StationNumber].Content).DataContext;
// IView class has DataContext property so I am type casting the Content which is ContentControl to IView type first and later to ITestStationViewModel
viewModel.TestStationModel = xmlPayLoadModel;
}
Thanks.

Displaying Alert boxes in asp.net from code behind (does not always work)

I have a generic Alert function that display a message box in my asp.net app:
public void Alert(string sTitle, string sMessage)
{
StringBuilder sbScript = new StringBuilder();
sbScript.Append("<script language='Javascript'>");
sbScript.Append("var varDateNow = new Date();");
sbScript.Append("var varTimeNow = varDateNow.getTime();");
//sbScript.Append("var varAlertTime = document.getElementById('Master_cphAlertTime').value;");
sbScript.Append("var varAlertTime = document.getElementById('cphAlertTime').value;");
sbScript.Append("if(varTimeNow - varAlertTime < 1500)");
sbScript.Append("{alert('");
sbScript.Append(strMessage);
sbScript.Append("');}");
sbScript.Append("</script>");
ClientScript.RegisterStartupScript(this.GetType(), strTitle, sbScript.ToString());
}
The Alert box does not appear every time. What is confusing me is why does it appear sometime and not appear at other times? The times when it does not appear is when a page is about to get redirected (or server.transfer) to another page.
Any ideas why the random functionality?
you can implement this static class in your application
public class MessageBox
{
private static Hashtable m_executingPages = new Hashtable();
private MessageBox()
{ }
public static void Show(string sMessage)
{
// If this is the first time a page has called this method then
if (!m_executingPages.Contains(HttpContext.Current.Handler))
{
// Attempt to cast HttpHandler as a Page.
Page executingPage = HttpContext.Current.Handler as Page;
if (executingPage != null)
{
// Create a Queue to hold one or more messages.
Queue messageQueue = new Queue();
// Add our message to the Queue
messageQueue.Enqueue(sMessage);
// Add our message queue to the hash table. Use our page reference
// (IHttpHandler) as the key.
m_executingPages.Add(HttpContext.Current.Handler, messageQueue);
// Wire up Unload event so that we can inject
// some JavaScript for the alerts.
executingPage.Unload += new EventHandler(ExecutingPage_Unload);
}
}
else
{
// If were here then the method has allready been
// called from the executing Page.
// We have allready created a message queue and stored a
// reference to it in our hastable.
Queue queue = (Queue)m_executingPages[HttpContext.Current.Handler];
// Add our message to the Queue
queue.Enqueue(sMessage);
}
}
// Our page has finished rendering so lets output the
// JavaScript to produce the alert's
private static void ExecutingPage_Unload(object sender, EventArgs e)
{
// Get our message queue from the hashtable
Queue queue = (Queue)m_executingPages[HttpContext.Current.Handler];
if (queue != null)
{
StringBuilder sb = new StringBuilder();
// How many messages have been registered?
int iMsgCount = queue.Count;
// Use StringBuilder to build up our client slide JavaScript.
sb.Append("<script language='javascript'>");
// Loop round registered messages
string sMsg;
while (iMsgCount-- > 0)
{
sMsg = (string)queue.Dequeue();
sMsg = sMsg.Replace("\n", "\\n");
sMsg = sMsg.Replace("\"", "'");
sb.Append(#"alert( """ + sMsg + #""" );");
}
// Close our JS
sb.Append(#"</script>");
// Were done, so remove our page reference from the hashtable
m_executingPages.Remove(HttpContext.Current.Handler);
// Write the JavaScript to the end of the response stream.
HttpContext.Current.Response.Write(sb.ToString());
}
}
and the call the allert/message box with just a simple call like this MessageBox.Show("hello");

Categories

Resources