I am doing a project on C#. It's a project to send message using GSM Modem. In my project, I have several function that may give errors. I have used a string variable to store error message. The basic flow is like this.
class SMS{
string message;
public string getport(){
if(ErrorCondition)
message="Error Finding port";
return port;
}
public void executecommand(command){
if(ErrorCondition1)
message="Error Executing Command";
else(ErrorCondition2)
message="No Response from device";
}
public void sendMessage(int number, string text, out string error){
findport();
executecommand(command);
error = message;
}
}
NB:This is not the working code
This is the way I have thought to collect error message, but I not sure if I am doing it the right way. I need your help on this. Is there a better approach? Error string does not save any string.
Update: As the answers of Exception are coming, I am confused about arrangement of try catch, here I have my actual code so that I'll help to give further suggestions.
public string ReadResponse(SerialPort port, int timeout)
{
string buffer = string.Empty;
try
{
do
{
if (receiveNow.WaitOne(timeout, false))
{
string t = port.ReadExisting();
buffer += t;
}
else
{
if (buffer.Length > 0)
message = "Response incomplete";
else
message = "Error on Modem";
}
}
while (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"));
}
catch (Exception ex)
{
throw ex;
}
return buffer;
}
Your (pseudo) code can be refactored to use the de facto way of managing errors in C#, which are exceptions. Based on your code right there, you're used to using a special variable or return value as an error message and there's nothing wrong with that, it just won't be what other C# developers would expect.
Here's some (pseudo) code that demonstrates what I'm typing about.
class SMS {
public string GetPort() {
if (ErrorCondition) {
throw new PortNotFoundException("Error finding port.");
}
return port;
}
public void ExecuteCommand(Command command) {
if(ErrorCondition1) {
throw new UnknownErrorException("Error Executing Command");
}
else(ErrorCondition2) {
throw new NoResponseException("No Response from device");
}
}
public void SendMessage(int number, string text) {
FindPort();
ExecuteCommand(command);
}
}
You'll note that there's no out variable in SendMessage to handle passing out the error to calling code. That's handled by the thrown exceptions. The calling code is at liberty to determine how best to handle the exception.
You can declare
string message;
to
private List<string> message;
and add message to list, will help to catch multiple errors as well. Also make it private so that other class cant access the same.
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I have an SSIS package which calls a Data Flow Task as part of a loop which iterates different end-point addresses (out of scope).
The Data Flow Task has a source Script Component responsible for calling a REST API and creating a row for each result.
There are 3 output buffers;
1. actual data row
2. error row
3. monitoring
The monitoring buffer used for telemetry and is populated through an event (EventHander) that is fired every time the API makes a request.
During the first iteration of the ForEach int the Control Flow loop, everything runs as expected, all the buffers produce the correct rows.
However, during the next iterations, the monitoring buffer which is populated within the event throws;
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.HandleUserException(Exception e)
at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.PrimeOutput(Int32 outputs, Int32[] outputIDs, PipelineBuffer[] buffers)
at Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostPrimeOutput(IDTSManagedComponentWrapper100 wrapper, Int32 outputs, Int32[] outputIDs, IDTSBuffer100[] buffers, IntPtr ppBufferWirePacket)
I don't understand why the MonitoringBuffer is not initialised in the proceeding iterations.
The exception occurs while calling MonitoringBuffer.AddRow();.
Here's the whole Script Component simplified for readability:
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
private string ClientCode { get { return Variables.ErplyClientCode; } }
private string Username { get { return Variables.ErplyUsername; } }
private string Password { get { return Variables.ErplyPassword; } }
private bool IsTest { get { return Variables.IsTest; } }
private int ErplyRecordsPerPage { get { return Variables.ErplyRecordsPerPage; } }
private string ErplyDebugOutputPath { get { return Variables.ErplyDebugOutputPath; } }
private DateTime ChangeSince { get { return Variables.ChangeSince; } }
private int records { get; set; }
private int errors { get; set; }
private string rawFolder { get; set; }
public override void PreExecute()
{
base.PreExecute();
}
public override void PostExecute()
{
base.PostExecute();
}
public override void CreateNewOutputRows()
{
ErplyAPI.OnPreRequestEvent += new EventHandler<EAPIEvent>(ErplyAPI_OnPreRequestEvent);
var staff = ErplyAPI.getStaff(ClientCode, Username, Password, ChangeSince, ErplyRecordsPerPage, IsTest);
foreach (var p in staff.List)
{
try
{
if (!p.IsError)
{
EmployeeBuffer.AddRow();
EmployeeBuffer.employeeID = p.employeeID;
}
else
{
ErrorBuffer.AddRow();
ErrorBuffer.employeeID = p.employeeID;
ErrorBuffer.Error = p.Error.Message.Trim() + "\n" + p.Error.StackTrace;
errors++;
}
records++;
}
catch (Exception ex)
{
this.ComponentMetaData.FireWarning(0, "Script", ex.Message + "\n" + ex.StackTrace, string.Empty, 0);
}
}
EmployeeBuffer.SetEndOfRowset();
ErrorBuffer.SetEndOfRowset();
}
private void ErplyAPI_OnPreRequestEvent(object sender, EAPIEvent e)
{
var request = string.Empty;
var sessionKey = string.Empty;
bool fireAgain = true;
if (e == null)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
return;
}
if (e.eAPI == null)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent.eAPI is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
return;
}
try
{
if (e.Parameters != null && e.Parameters.ContainsKey("request"))
request = e.Parameters["request"].ToString();
if (request != "verifyUser" && e.Parameters != null && e.Parameters.ContainsKey("sessionKey"))
sessionKey = e.Parameters["sessionKey"].ToString();
}
catch (Exception ex)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("Error occurred assigning variables from EAPIEvent parameters in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace), string.Empty, 0);
}
try
{
MonitoringBuffer.AddRow(); // Exception occurs here
MonitoringBuffer.Request = ResizeString(request, 255);
MonitoringBuffer.SessionKey = ResizeString(sessionKey, 128);
}
catch (Exception ex)
{
var message = string.Format("Error occurred outputting Erply request in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace);
MonitoringBuffer.ErrorMessage = ResizeString(message, 8000);
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", message, string.Empty, 0);
}
finally
{
MonitoringBuffer.EndOfRowset();
}
}
}
I sorted the problem out.
The exception was being raised when the variable dispenser was being accessed from the Event. For some reason the GetValueWithContext(ScriptComponent.EvaluatorContext) is being dropped during the second call. Why this happens is beyond me.
The solution is simple, assign the variables from the variables dispenser to a local property or variable in the OnPreExecute function.
It's also good practice to not call the variable dispenser in the CreateNewOutputRows as it cause variable locking.
I ran into this issue too, but my solution was a little different -- moving the variable assignments into PreExecute() didn't help.
Instead, what I'd done is that I wanted to parse three different files, and read each of them with a Script Component. Their columns were kinda similar, so I created one Data Flow task, made sure it worked, then copied it and modified each copy to reflect the differences in the files. Running each individual Data Flow task was successful, but when I tried to run two of them, one after the other in a loop, I got a NullReferenceException from HostPrimeOutput() after calling the OutputBuffer.AddRow() method in my Script Component.
It turns out that when I copied each Data Flow task, the Script Components all kept the same namespace, and I guess it doesn't like that. So, I created brand new Script Components, set up all the output columns again (ugh!), copied the body of the script over, and it's happy.
i have the following code that gets an error message.i want to pass it into a string before an exception is thrown,this is my code
ValidateError(authDeserialized, "Succeed", "error", "failed"); //the validateError is a function as indicated below
Model.Response= authResponse.Content;
protected static void ValidateError(dynamic response, string validStatus,string categoryMatch, string message)
{
if (response.result.status != validStatus)
{
try
{
var category = response.result.category;
if (category == categoryMatch)
message=ErrorCodes.MessageFor(code,description);
//so i get the message back fine here but now how do i pass it back to this line Model.Response= authResponse.Content; so that it can get saved?
}
catch (Exception) { }
throw new Exception(message ?? "Request was not successfull");
}
}
As you are already sending message to the ValidateError() method, pass that parameter as a out parameter, it will update value of message if you assign new value to it then it will update message and will be accessible to outside environment.
string failureMessage = "failed";
ValidateError(authDeserialized, "Succeed", "error", out failureMessage);
//^^^ This is what you have to change
//Now you can assign failureMessage to any other value
Model.Response= authResponse.Content;
protected static void ValidateError(dynamic response, string validStatus,string categoryMatch, out string message)
{ //^^^ This is what you have to change
if (response.result.status != validStatus)
{
try
{
var category = response.result.category;
if (category == categoryMatch)
message=ErrorCodes.MessageFor(code,description); //so i get the message back fine here but now how do i pass it back to this line Model.Response= authResponse.Content; so that it can get saved?
}
catch (Exception) { }
throw new Exception(message ?? "Request was not successfull");
}
}
In this way you can assign value to failure message before throwing an error.
Try out online
I just started right now with the topic exceptionhandling. I read alot of positiv stuff about it, so I thought I should do the same, because my current technique using errorcodes is really ugly...
Okay we have following scenario: A user typed his password in a textbox. After pressing the login button, he gets an positiv or negativ message.
MainWindow.xaml
<TextBox x:Name="txtBoxUserPassword/>
<Button x:Name="btnLogin" Click="btnLogin_Click">Login</Button>
MainWindow.xaml.cs
private void btnCT_Click(object sender, RoutedEventArgs e)
{
DataBase db = new DataBase();
db.IsPasswordCorrect(this.txtBoxUserPassword.Text);
// How can I catch here the exception from the class to
// show the error notification?
}
DataBase.cs
public class DataBase{
public void IsPasswordCorrect(string password)
{
try{
if(password != "fooBar")
{
throw new InvalidPasswordException("You entered the wrong password. Try it again.");
}
else
{
/*
...
*/
}
}
catch(InvalidPasswordException ex){
// What should I do here? I want to give the user an
// error message with the content "You entered the wrong
// password. Try it again."
}
}
}
InvalidPasswordException.cs
public class InvalidPasswordException: Exception
{
public InvalidPasswordException(string message, Exception inner)
: base(message, inner)
{
}
}
As you can see, it's the first time I using exceptions. Hopefully you can help me a bit. Thanks!
Edit
I have this switch/case construct inside my public void btnCT_Click().
switch (CheckString("EnteredString"))
{
case 1:
MessageBox.Show("Error 1");
break;
case 2:
MessageBox.Show("Error 2");
break;
case 3:
MessageBox.Show("Error 3");
break;
case 0:
MessageBox.Show("Successful");
break;
}
Here is my method from another class. The classname is not important.
public int CheckString(string enteredString)
{
if(enteredString length is larger 25 chars)
return 1;
else if(enteredString contains special characters)
return 2;
else if(enteredString dosent contain any number)
return 3;
else
return 0;
}
The first thing that I have to say is that you don't need a custom exception just for this. Looking just to the method's name (IsPasswordCorrect) anyone would expect this method to return a true/false boolean value not an exception.
So you could have a simpler
public class DataBase
{
public bool IsPasswordCorrect(string password)
{
if(password != "fooBar")
return false;
else
return true;
}
}
.... at the UI level ....
if(!db.IsPasswordCorrect("notA_fooBar"))
MessageBox.Show("You entered the wrong password. Try again");
else
....
However, if you really need to thrown an exception (remember that this is a costly operation in terms of performances) then do not catch it in the same method where you throw it but let it bubble up to reach the calling code
public bool IsPasswordCorrect(string password)
{
if(password != "fooBar")
throw new InvalidPasswordException("You entered the wrong password. Try again");
....
}
and in the calling code (at the UI level) add the try catch blocks
private void btnCT_Click(object sender, RoutedEventArgs e)
{
try
{
DataBase db = new DataBase();
db.IsPasswordCorrect(this.txtBoxUserPassword.Text);
// If you reach this point the password is correct
// But it is ugly and unclear to any reader....
}
catch(InvalidPasswordException ex)
{
MessageBox.Show(ex.Message);
}
In any case exceptions should be used only for exceptional reasons. You don't use them to drive your code. In this context the best method is to return a true/false value.
When the failure reasons are complex I usually use this approach
bool ok = true;
ok = database.IsPasswordCorrect("fooBar");
if(ok) ok = database.Method1();
if(ok) ok = database.Method2();
if(ok) ok = database.Method3();
if(!ok)
MessageBox.Show(database.LastErrorMessage);
public class Database
{
public string LastErrorMessage { get; set; }
public bool Method1()
{
if(errorFoundForReason1)
{
LastErrorMessage = "Error found for reason1";
return false;
}
if(errorFoundForReason2)
{
LastErrorMessage = "Error found for reason2";
return false;
}
....
return true;
}
}
Of course, every boolean method in the database class, when there is a reason to fail and before returning false, sets a global variable with the exact error message involved in the failure so the client code could handle easily the message when it has finished the calls.
I have seen similar questions, but not exactly this:
I would like to know the right way of determining whether a method is executed correctly or not, returning a boolean, and if the method is not executed know the reason, even if an exception is thrown.
I do it in this way, but I think that return inside the catch is a bad practice, so which is the right way?:
if(!myObject.DoSomething('A', out result))
{
MessageBox.Show(myObject.ErrorMessage);
[...]
}else{
MessageBox.Show(result);
[...]
}
class myObject()
{
public string ErrorMessage;
bool DoSomething(char inputValue, out string result)
{
try
{
if(inputValue == 'A')
{
ErrorMessage = "Bad input value: " + inputValue;
return false;
}
[...]
return true;
}catch(Exception ex){
ErrorMessage = ex.Message;
return false;
}
}
I don't like trhow the exception inside the catch because I lose the control of the application (and I can't get the description), and the exception always finish in the form. And if I show the exception in the form, I don't need try catch in the rest of the classes.
I mean that try {} catch(Exception ex) { throw ex;} is the same as not putting try catch.
thanks a lot
My suggestion would be to create your own Exception type (possibly global), and pass it in as a reference.
Thereafter you can still get back your boolean indicating success or failure (and having only one return outside of the try..catch).
public class CustomException
{
private string _message;
private string _title;
public CustomException()
{
_title = "";
_message = "";
}
public CustomException(string title, string message)
{
_title = title;
_message = message;
}
}
Then call DoSomething passing in an instance of CustomException (ce in this case).
CustomException ce = new CustomException();
Be advised this is the best process to solve the problem of having to return a boolean indicating success or failure and know the message, for example; dumping it to a log file or logging to database (particularly for Service Calls - WCF)
However this is not a solution for bad logic in handling business process.
Return false inside a catch isn't by itself bad practice. It's useful when you handle a piece of code's exceptions and it must not fail.
For example, I'm working on a printer piloting DLL at the time, and this DLL must read a XML file containing multiple records to print. The method must not fail because one record fails to print, but it still can return exception if the XML file is not correctly formated.
public void Print(string xmlFile)
{
if (String.IsNullOrWhiteSpace(xmlFile))
throw new ArgumentNullException("No xml file has been passed to the Print method.");
// This line will most likely throw an exception if the XMl file is not well formated
XDocument dom = XDocument.Load(xmlFile);
foreach (XElement n in dom.XPathSelectElements("//RECORDS/RECORD"))
{
try
{
// send commands to the printer, if the printer fails to print, throw a PrinterRecordException
}
catch (PrinterRecordException e)
{
// log print failure, but keep on printing the rest
continue;
}
catch (Exception e)
{
// dunno what happened, but still have to print the rest
continue;
}
}
}
In this example, my function could return false instead of throwing exceptions to the main program, if this program doesn't care. In my case it does :p In my opinion, that's how you should think your method.
Exception handling methods and best practices are a some-what subjective matter. I cannot attest to the method I'm about to present because I have only just started to use it in my own project.
What I suggest is having a static ExceptionHandler class with which you can register any exception to be handled by Generic Parameter and its corresponding handler. This will decouple your business logic from your UI in case you wanted to display some kind of message box when a particular exception occurs.
Here's an example:
/// the real implementation uses lambda's and/or implementations of IExceptionHandler<TException>
ExceptionHandler.Register<InvalidPasswordException>(() => /*some handler logic*/);
// ... else where in the code ...
catch (InvalidPasswordException ex)
{
// do resource clean-up and raise exception for listeners such as the UI or logging infrastructure.
ExceptionHandler.Raise(ex);
}
So far this looks promising, especially when compared with my previous approaches. But only time will tell.
Update
The ExceptionHandler class itself need not be static, for example you might want to have different instances of ExceptionHandlers at different layers of your application if you are using a layered architecture.
Modifying to make it clear:
I have a question on exception logging and graceful exit. This is in continuation with previous question. The code looks like:
string status = "0";
ClassA ObjA = new ClassA();
try
{
status = objA.Method1();
if (status != "-1")
{
status = objA.Method1();
}
}
catch (Exception Ex)
{
//Log Exception EX
}
Inside the Method1:
public string Method1()
{
string status = "0";
try
{
//Code
return "0";
}
catch (Exception Ex)
{
//Log Exception with details
return "-1"
}
}
I log the Exception in the calling method and return only a status to the caller.
Should I return the Exception to the calling method or is only a status sufficient. With a status of "-1", I know there was an Exception in the called method and details of that Exception were logged in a log file.
I think it is OK to do it like that if you have a lot of status codes, otherwise you could also just throw an exception and catch it in the method higher up.
Also maybe reconsider your return type. Looks like you could be using integers, think you are opening yourself up to errors using strings.
Don't use the status return value, it is not adding anything that is useful to you.
consider,
var a = new ClassA()
try
{
a.Mehtod1();
}
catch
{
try
{
a.Method1();
}
catch (Exception ex)
{
//Log without details;
}
}
class ClassA
{
void Method1()
{
try
{
//Code
}
catch (Exception ex)
{
//Log with details
throw;
}
}
}
This code achieves the same functionality but leaves the return code of the functions for something useful and non exceptional.
More generally, I suggest that you should have one catch all handler at the top level of your application that deals with logging, or at most one per public entry point. Other handlers should deal with specific exception types that they can actually "handle" (do something about.)
It all depends on the purpose and implementation of the code; sometimes it is better to allow exceptions to pass back to the caller - they should be used in exceptional cases.
If you do intend on using return codes, however, I would be more inclined to use enum's (though, again, it depends what the purpose of the code is). That way, it is easy for the caller to check against an available selection of return codes. Also, a comment on using integers or strings as error codes - it may not be very descriptive for a caller to know what the issue was. In this case, throwing an Exception or a specific type (containing the error message), or returning a pre-defined enum with a descriptive name, would be more meaningful to the caller.
From these short code snippets which does nothing it is very difficult to say what is best practice.
In general it is best to push exceptions to where they are handled best. If you are writing a framework for interfacing with some webservice the users of your framework will most likely not care about network exceptions etc. - they want return codes or, even better some framework specific exceptions that you include/code.
Hm - in your situation I'd rather do the following, but it really depends on the situation:
public string Method1()
{
string status = "0";
//Code - Exception may be thrown
return "0";
}
string status = "0";
ClassA ObjA = new ClassA();
try
{
status = objA.Method1();
}
Catch(Exception Ex)
{
//Log Exception EX
status = "-1;
}
EDIT
Sometimes it's hard to define values that indicate whether an error occurred in the method. You should keep Nullable types in mind. If you can find a suitable return value that indicates errors, it may also be ok to log the error within the method that caused the error and just react to the return value as you suggested.
By the way: In your code you're calling Method1 twice if the first call succeeded. I guess that is because it is a quick sample...
class MyException : Exception
{
public readonly int status;
public MyException(int status, string msg):base(msg)
{
this.status = status;
}
}
public string Method1()
{
throw new MyException(-1,"msg");
return "0";
}
SomeCode()
{
try
{
Method1();
}catch(MyException ex)
{
ex.status //here you get the status
}
}