How to show messages depending of the program's nature
Please, sorry for the long text.
I have a library of C# Classes which retrieves information from various systems, invokes external functions, validates this info and generates results of the validation to a file. This library can indistinctly be invoked from: 1) a DOS console program, 2) from a Windows form or 3) from a windows service program.
Users have asked me for modifying the library so it can run in a verbose way, i.e. to show the date and time at certain steps, to briefly explain what a certain step or method is doing, etc. They also asked me for introducing exception handling and show error messages.
If I execute in console mode, I should show the messages on the console, if I execute from a Windows form I should send the messages to a message box or to a text box, and if I run from a Windows Service I should send the messages to a log file.
I have 2 questions:
1) How should I modify the C# Classes so I can avoid the constant evaluation: If program is in console mode writeline….. Else if program is in windows forms mode messagebox or textbox.text … Else if program is invoked from a windows service program writelogfile….
2) If the above evaluation is unavoidable, how can I know if the library of C# classes is being invoked by a console, windows form windows service program?
Thanks!!
Possible solution:
I read a little about MS Enterprise Library and ... it is too much for my modest requirement so I went for the pragmatic solution of Reed.
I share the way I solved the user requirements, it is a preliminary model before applying to the real situation so, before accepting the Reed solution, your comments to improve and learn are really welcome.
1) I created a little library to define all possible outputs, in this case I defined only the outputs to a console and to a WPF form:
namespace diClass { public interface IVerbose { void show(string msg, object textBox); void notify(string msg); }
public class ConsoleOutput : IVerbose
{
public void show(string msg, object textBox)
{
System.Console.WriteLine(msg);
}
public void notify(string msg)
{
System.Console.WriteLine("Notif: " + msg);
}
}
public class WpfOutput : IVerbose
{
public void show(string msg, object textBox)
{
TextBox tb = (TextBox)textBox;
tb.Text += msg + "\r\n";
System.Windows.Forms.Application.DoEvents();
}
public void notify(string msg)
{
MessageBox.Show(msg);
}
}
public class Output
{
IVerbose outputType;
public IVerbose verboseType
{
get { return outputType; }
set { outputType = value; }
}
public void show(string msg, object textBox)
{
outputType.show(msg, textBox);
}
public void notify(string msg)
{
outputType.notify(msg);
}
}
}
2) Then I defined a console program which uses the above library:
class Program
{
static void Main(string[] args)
{
IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.ConsoleOutput));
Output o = new Output();
o.verboseType = verboseType;
object textBox1 = null;
o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
}
}
3) Finally I defined a WPF program which also uses the above library:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void 开发者_如何学Gobutton1_Click(object sender, RoutedEventArgs e)
{
IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.WpfOutput));
Output o = new Output();
o.verboseType = verboseType;
o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
}
}
In programs 2) and 3) the last two lines of code are equal, there is no ifs and, that is what I wanted as answer.
Regards.
Instead of trying to handle all these conditions, have considered adding logging (e.g Enterprise Library Logging Application Block or any other logging tool) that writes verbose logs, this will help you satisfy all your requirements, i.e. timestamping, method execution information, exceptions, errors.
My preference, for this type of situation, is to make a set of interfaces, and work against the interfaces. You can then use Dependency Injection to inject a concrete version of the interface depending on whether you're running in console, gui, or as a service. Something like (this is a very simple version):
public interface IAlgorithm
{
void UpdateProgress(double percent);
void Complete(bool success);
void Error(string error); // Or (Exception error), if you want to pass an exception
}
public interface IAlgorithmFactory
{
IAlgorithm StartAlgorithm(string name);
}
Then, let's take the console application version. You just need to provide the correct IAlgorithmFactory
for a console app:
class ConsoleAlgorithm : IAlgorithm
{
string name;
public ConsoleAlgorithm(string algorithmName)
{
this.name = algorithmName;
}
public void UpdateProgress(double percent)
{
if(percent == 0)
Console.WriteLine();
else if (percent == 1.0)
Console.WriteLine("100% ");
else
Console.Write("\r{0}%", percent * 100);
}
public void Complete(bool success)
{
if (success)
Console.WriteLine("{0} completed successfully.", this.name);
else
Console.WriteLine("{0} failed.");
}
public void Error(string error)
{
Console.WriteLine("{0} received error: {1}", this.name, error);
}
}
public class ConsoleAlgorithmFactory: IAlgorithmFactory
{
public IAlgorithm StartAlgorithm(string name)
{
return new ConsoleAlgorithm(name);
}
}
When your program runs as a console, you'd provide it a ConsoleAlgorithmFactory
, and it would just use it as an IAlgorithmFactory
. You can call the methods on it to report progress, and your main program doesn't care how it's run - it just reports as needed.
When you run as a GUI, on the other hand, you'd make something like WindowsFormsAlgorithmFactory
, pass it in, and now the reporting would be done via forms... Nothing in your program changes.
Have an event which displays messages/alerting in case of exceptions.
public event Action<string> Message;
Allowing any UI that wants to do something with that message, just add its own delegate.
精彩评论