I have to make my own Exception Class for .NET project. Could somebody please help how can I use it in the code? I just to show to MessageBox to user that the images were not found. But I don't know where to do it. Hoping for a good answer.
class RijException : Exception
{
public RijException()
: base() { }
public RijException(string message)
: base(message) { }
public RijException(string format, params object[] args)
: base(string.Format(format, args)) { }
public RijException(string message, Exception innerException)
: base(message, innerException) { }
public RijException(string format, Exception innerException, params object[] args)
: base(string.Format(format, args), innerException) { }
}
Now I want to use it:
try
{
afbeeldingPictureBox.BackgroundImage =
Image.FromFile(#"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png");
}
catch (FileNotFoundException)
{
throw new RijException("Can't find the images");
}
Edit
try
{
try
{
afbeeldingPictureBox.BackgroundImage = Image.FromFile(#"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png");
}
catch (FileNotFoundException)
{
throw new RijException("ImageNotFound");
//MessageBox.Show("Afbeeldingen konden niet worden geladen");
}
}
catch (RijException)
{
MessageBox.Show("Not able to load the image...");
}
Your example could be improved, but before that let's take a more useful example.
Imagine that you have the following code:
class Program
{
static void Main(string[] args)
{
try
{
var processor = new FileProcessor();
processor.Run();
}
catch (RijException exception)
{
//what will I get here.
}
}
}
Which uses the following classes:
public class FileProcessor
{
private string _myFileName;
public void Run()
{
try
{
var fileLoader = new FileLoader();
Process(fileLoader.Load(_myFileName));
}
catch (FileNotFoundException)
{
throw new RijException("Can't find requested file");
}
}
private void Process(object file)
{
//some logic
}
}
public class FileLoader
{
public object Load(string myFileName)
{
//throws FileNotFoundException
}
}
So the call stack will be like this:
If we modify the code in the main method to print the stack trace, what do you think that we get?
try
{
var processor = new FileProcessor();
processor.Run();
}
catch (RijException exception)
{
Console.WriteLine(exception.StackTrace);
}
The correct answer is:
See? The stack trace shows that the error happened in FileProcessor while it really happened in FileLoader. The reason to that is this code:
catch (FileNotFoundException)
{
throw new RijException("Can't find requested file");
}
When you catch an exception and throw another one you must always include the original exception as the inner exception. Otherwise it will be hard to understand where the exception originally occurred.
catch (FileNotFoundException ex)
{
throw new RijException("Can't find requested file", ex); //includes inner
}
Another problem is the exception message: "Can't find requested file". Ask yourself. If you get that message in a log file, would you be able to figure out what went wrong? At least give some context information.
Finally you have another problem. Best practices for designing exceptions says that they should be able to get serialized. To do that you need to include the serialization constructor and mark the exception as serializable:
[Serializable]
public class RijException : Exception
{
public RijException(string message) : base(message)
{
}
public RijException(string message, Exception inner) : base(message, inner)
{
}
//serialization constructor
protected RijException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
}
Finally I would therefore write your exercise like this:
try
{
var filename = #"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png";
try
{
afbeeldingPictureBox.BackgroundImage = Image.FromFile(filename);
}
catch (FileNotFoundException exception)
{
throw new RijException("Failed to load " + filename, exception);
}
}
catch (RijException)
{
MessageBox.Show("Not able to load the image...");
//now you would have all information required
//to figure out where and why something went wrong.
}
Summary
Always include inner exceptions
Provide useful context information so that you can figure out what went wrong
Make sure that exceptions can be serialized.
It is generally not a great idea to catch an exception that you cannot do much about. Just catching the FileNotFoundException and then throwing a new RijException that essentially conveys the same information is not usually done.
I just to show to MessageBox to user that the images were not found. But I don't know where to do it.
The most direct way to restructure your code to show the message box is
catch (FileNotFoundException)
{
MessageBox.Show("Can't find the images.");
//Don't do this: throw new RijException("Can't find the images");
}
You really do not want your custom RijException to take on the responsibility of displaying the MessageBox.
Related
I'm having quite a bit of difficulty in getting a custom exception message to return from my Web Api solution. It's a bit more complicated than that:
I want to override the read only property of the exception with my own:
public class CustomException : Exception
{
public CustomException(string message)
: base(message)
{
}
public CustomException(string message, Exception inner)
: base(message, inner)
{
}
}
However, I also have a global exception handler:
public class GlobalExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
if (context.Exception.Message == "Password has already been used in the past...1")
{
throw new CustomException("some msg", context.Exception);
}
NLogger.LogError("Global Error Handler", context.Exception);
}
}
When I throw the error I do so like:
if (some condition)) throw new CustomException("some msg");
And then I catch it in the method like:
catch (CustomException ex)
{
throw ex;
}
catch (Exception ex)
{
NLogger.LogError(ex);
throw;
}
How can I set the message to be "some msg"? What I'm trying to do is have the api return 1-2 use case related error messages with customErrors mode set to on.
throw new HttpResponseException(
new HttpResponseMessage
{
StatusCode = code,
ReasonPhrase = phrase,
Content = new StringContent(body)
});
I have a global try/catch around my application methods to log unhandled exceptions and show an error message. For logging I use NLog. If I handle an exception and log it manually I set a key 'logged' in the exceptions data object to prevent the second log from the global try/catch.
public partial class App : Application
{
public static void Main(string[] args)
{
try
{
// Application stuff
SomeMethod();
}
catch (Exception ex)
{
if (ex.Data['logged'] == false)
{
logger.Error(ex, "A unhandled exception occured.")
ex.Data['logged'] = true;
}
// Show error dialog
}
}
public static void SomeMethod()
{
try
{
// Method stuff
}
catch (Exception ex)
{
logger.Error(ex, "A handled exception occured.")
ex.Data['logged'] = true;
throw;
}
}
}
I want to simplify the process so that I don't have to call ex.Data['logged'] = true; manually. Is there a way to modify the data property of an exception automatically while logging with NLog? I tried to use a MethodCall-Target but I had no access to the exception reference. The exception could only be passed as a string.
Would it work for you to use NLog to perhaps modify your approach to logging exceptions slightly?
public partial class App
{
private static Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
try
{
SomeMethod();
}
catch (Exception ex)
{
logger.ErrorEx(ex, "message");
}
}
public static void SomeMethod()
{
try
{
// Method stuff
}
catch (Exception ex)
{
logger.ErrorEx(ex, "A handled exception occured.");
throw;
}
}
}
public static class NLogExt
{
public static void ErrorEx(this NLog.Logger logger, Exception ex, string message)
{
if (ex.Data["logged"] as bool? == true) return;
logger.Error(ex, message);
ex.Data.Add("logged", true);
}
}
I have a Dynamics CRM 2013 plugin executing in the Sandbox.
This code has the following custom exception class:
[Serializable]
public class PluginValidationException : Exception
{
public PluginValidationException()
{
}
protected PluginValidationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public PluginValidationException(string message)
: base(message)
{
}
public PluginValidationException(string message, Exception inner)
: base(message, inner)
{
}
}
When this exception is thrown in the plugin it results in a generic error window, with no details in the log file:
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: System.Runtime.Serialization.SerializationException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #1355B4E4Detail:
-2147220970
CallStack
at Microsoft.Crm.Application.Platform.ServiceCommands.PlatformCommand.XrmExecuteInternal()
at Microsoft.Crm.Application.Platform.ServiceCommands.CreateCommand.Execute()
at Microsoft.Crm.Application.Platform.EntityProxy.Create(Boolean performDuplicateCheck, Guid auditingTransactionId)
at Microsoft.Crm.Application.Platform.EntityProxy.Create(Boolean performDuplicateCheck)
at Microsoft.Crm.Application.Platform.EntityProxy.CreateAndRetrieve(String[] columnSet, Boolean performDuplicateCheck)
at Microsoft.Crm.Application.WebServices.InlineEdit.CommandBase.UpdateEntity(Entity entity, Boolean retrieve)
at Microsoft.Crm.Application.WebServices.InlineEdit.SaveCommand.ExecuteCommand(String commandXml)
at Microsoft.Crm.Application.WebServices.InlineEdit.CommandBase.Execute(String commandXml)
System.Runtime.Serialization.SerializationException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #1355B4E4
2014-04-06T02:04:30.0972001Z
[Demo.DemoPlugin: Demo.DemoPlugin.BasicCrmPlugin]
[d86b89ab-f1bc-e311-9408-000c29254b18: Demo.DemoPlugin.BasicCrmPlugin: Create of contact]
Looking at the CRM trace log shows the following:
System.Runtime.Serialization.SerializationException: Type 'Demo.Helpers.PluginValidationException' in assembly 'Demo.DemoPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fbb51ba1e588d276' is not marked as serializable.
at Microsoft.Crm.Sandbox.SandboxAppDomainHelper.Execute(IServiceEndpointNotificationService serviceBusService, IOrganizationServiceFactory organizationServiceFactory, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, IPluginExecutionContext requestContext)
at Microsoft.Crm.Sandbox.SandboxWorker.Execute(SandboxCallInfo callInfo, SandboxPluginExecutionContext requestContext, Guid pluginAssemblyId, Int32 sourceHash, String assemblyName, Guid pluginTypeId, String pluginTypeName, String pluginConfiguration, String pluginSecureConfig, SandboxRequestCounter& workerCounter)
I do not, based on some reading, believe this is a bug - rather it is because custom Exception classes are not, inherently trusted as of .NET 4 (I'm using .NET 4.5.)
Does anyone know how to make a custom exception class that will work with the CRM Sandbox. I'm using a custom exception class because I catch errors and need to distinguish between an InvalidPluginExecutionException an exception caused because the plug-in is incorrectly registered.
UPDATED Apr 08 2014
Here is the code in the plugin that catches the exceptions, with significant simplification for putting it on Stackoverflow:
try
{
//TODO: Prevalidation Logic
ValidatePluginExecution(crmContext, logging, out keyName);
//TODO: Postvalidation Logic
}
catch (PluginValidationException ex)
{
//TODO: Specific logging for Plugin Validation Exception
throw new InvalidPluginExecutionException("Did Not Validate");
}
catch (InvalidPluginExecutionException ex)
{
logging.Write("InvalidPluginExectionException at Plugin Validation");
throw;
}
catch (Exception ex)
{
logging.Write("Unhandled Exeception During Plugin Validation Operation");
logging.Write(ex);
throw new InvalidPluginExecutionException("Error. Download Log and submit to the Help Desk.", ex);
}
After some extra testing, this is what I was able to determine:
Apparently, you can access the Stack Trace for exceptions, only if explicitly done so. When throwing an exception from a sandboxed plugin, the stack trace of the exception is not actually being displayed as long as the exception is one that the CRM platform "knows about" (Not sure what it is doing, here but I'm guessing it is looking at the type of the exception, and handling different types in different ways). If the type is unknown, it results in CRM attempting to be serialize the exception which is not allowed in a because it uses reflection (why it has to be serialized, not sure).
Here is an example Plugin with some examples that worked, and some that didn't:
public class TestPlugin: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
try
{
OtherMethod();
}
catch (Exception ex)
{
var trace = (ITracingService)serviceProvider.GetService(typeof (ITracingService));
trace.Trace("Throwing Plugin");
// Doesn't work
throw new InvalidPluginExecutionException("Error ", ex);
}
}
// Works:
//public void Execute(IServiceProvider serviceProvider)
//{
//try
//{
//OtherMethod();
//}
//catch (Exception ex)
//{
//var trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
//trace.Trace("Throwing Plugin");
//throw new InvalidPluginExecutionException("Error " + ex);
//}
//}
// Doesn't Work:
//public void Execute(IServiceProvider serviceProvider)
//{
// try
// {
// OtherMethod();
// }
// catch (Exception ex)
// {
// throw;
// }
//}
// Doesn't Work:
//public void Execute(IServiceProvider serviceProvider)
//{
// try
// {
// OtherMethod();
// }
// catch (Exception ex)
// {
// throw new InvalidPluginExecutionException("Error", ex);
// }
//}
public void OtherMethod()
{
throw new MyException();
}
}
public class MyException : Exception
{
}
So to answer your question: I wrote an exception handler to be able to walk the inner exceptions and determine if it is valid to be thrown:
/// <summary>
/// Exception Handler For Exceptions when executing in Sandbox Isolation Mode
/// </summary>
public class ExceptionHandler
{
/// <summary>
/// Determines whether the given exception can be thrown in sandbox mode.
/// Throws a Safe if it can't
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns></returns>
/// <exception cref="InvalidPluginExecutionException"></exception>
/// <exception cref="Exception"></exception>
public static bool CanThrow(Exception ex)
{
var exceptionRootTypeIsValid = IsValidToBeThrown(ex);
var canThrow = exceptionRootTypeIsValid;
var innerException = ex.InnerException;
// While the Exception Types are still valid to be thrown, loop through all inner exceptions, checking for validity
while (canThrow && innerException != null)
{
if (IsValidToBeThrown(ex))
{
innerException = innerException.InnerException;
}
else
{
canThrow = false;
}
}
if (canThrow)
{
return true;
}
var exceptionMessage = ex.Message +
(ex.InnerException == null
? string.Empty
: " Inner Exception: " + ex.InnerException.ToStringWithCallStack());
// ReSharper disable once InvertIf - I like it better this way
if (exceptionRootTypeIsValid)
{
// Attempt to throw the exact Exception Type, with the
var ctor = ex.GetType().GetConstructor(new[] { typeof(string) });
if (ctor != null)
{
throw (Exception) ctor.Invoke(new object[] { exceptionMessage });
}
}
throw new Exception(exceptionMessage);
}
/// <summary>
/// Determines whether the specified ex is valid to be thrown.
/// Current best guess is that it is not
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns></returns>
private static bool IsValidToBeThrown(Exception ex)
{
var assembly = ex.GetType().Assembly.FullName.ToLower();
return assembly.StartsWith("mscorlib,") || assembly.StartsWith("microsoft.xrm.sdk,");
}
}
This can be called from your uppermost try catch in your plugin like so:
catch (InvalidPluginExecutionException ex)
{
context.LogException(ex);
// This error is already being thrown from the plugin, just throw
if (context.PluginExecutionContext.IsolationMode == (int) IsolationMode.Sandbox)
{
if (Sandbox.ExceptionHandler.CanThrow(ex))
{
throw;
}
}
else
{
throw;
}
}
catch (Exception ex)
{
// Unexpected Exception occurred, log exception then wrap and throw new exception
context.LogException(ex);
ex = new InvalidPluginExecutionException(ex.Message, ex);
if (context.PluginExecutionContext.IsolationMode == (int)IsolationMode.Sandbox)
{
if (Sandbox.ExceptionHandler.CanThrow(ex))
{
// ReSharper disable once PossibleIntendedRethrow - Wrap the exception in an InvalidPluginExecutionException
throw ex;
}
}
else
{
// ReSharper disable once PossibleIntendedRethrow - Wrap the exception in an InvalidPluginExecutionException
throw ex;
}
}
I believe this is an actual error, and I have opened up support ticket with Microsoft, we shall see if they agree...
Update!!
I created a ticket with Microsoft: (not sure what these numbers mean, but they were in the subject and hopefully will be beneficial for someone in the future: REG:115122213520585 SRXCAP:1318824373ID). They did confirm that Custom Exceptions were not supported in CRM for Sandboxed Plugins.
Please up-vote this Connect Ticket to have Microsoft fix this or at least handle it better!
I don't think what you want is possible, if you want a message in that error dialog you have to throw InvalidPluginExecutionException.
Handle Exceptions in Plug-Ins
For synchronous plug-ins, you can optionally display a custom error
message in the error dialog of the web application by having your
plug-in throw an InvalidPluginExecutionException exception with the
custom message string as the exception Message property value
It is recommended that plug-ins only pass an
InvalidPluginExecutionException back to the platform.
As a side, I wouldn't bother checking the registration in the plugin itself, its a situation which doesn't make a lot of sense in 2013. Back in CRM 4 where plugins had to be manually registered there was some sense in it. Now we have solutions, the correct registration is a development and testing task - not a run time check.
When an exception is possible to be thrown in a finally block how to propagate both exceptions - from catch and from finally?
As a possible solution - using an AggregateException:
internal class MyClass
{
public void Do()
{
Exception exception = null;
try
{
//example of an error occured in main logic
throw new InvalidOperationException();
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//example of an error occured in finally
throw new AccessViolationException();
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
These exceptions can be handled like in following snippet:
private static void Main(string[] args)
{
try
{
new MyClass().Do();
}
catch (AggregateException e)
{
foreach (var innerException in e.InnerExceptions)
Console.Out.WriteLine("---- Error: {0}", innerException);
}
catch (Exception e)
{
Console.Out.WriteLine("---- Error: {0}", e);
}
Console.ReadKey();
}
I regularly come into the same situation and have not found a better solution yet. But I think the solution suggested by the OP is eligible.
Here's a slight modification of the original example:
internal class MyClass
{
public void Do()
{
bool success = false;
Exception exception = null;
try
{
//calling a service that can throw an exception
service.Call();
success = true;
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//reporting the result to another service that also can throw an exception
reportingService.Call(success);
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
IMHO it will be fatal to ignore one or the other exception here.
Another example: Imagin a test system that calibrates a device (DUT) and therefore has to control another device that sends signals to the DUT.
internal class MyClass
{
public void Do()
{
Exception exception = null;
try
{
//perform a measurement on the DUT
signalSource.SetOutput(on);
DUT.RunMeasurement();
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//both devices have to be set to a valid state at end of the procedure, independent of if any exception occurred
signalSource.SetOutput(off);
DUT.Reset();
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
In this example, it is important that all devices are set to a valid state after the procedure. But both devices also can throw exceptions in the finally block that must not get lost or ignored.
Regarding the complexity in the caller, I do not see any problem there either. When using System.Threading.Tasks the WaitAll() method, for example, can also throw AgregateExceptions that have to be handled in the same way.
One more note regarding #damien's comment: The exception is only caught to wrap it into the AggregateException, in case that the finally block throws. Nothing else is done with the exception nor is it handled in any way.
For those who want to go this way you can use a little helper class I created recently:
public static class SafeExecute
{
public static void Invoke(Action tryBlock, Action finallyBlock, Action onSuccess = null, Action<Exception> onError = null)
{
Exception tryBlockException = null;
try
{
tryBlock?.Invoke();
}
catch (Exception ex)
{
tryBlockException = ex;
throw;
}
finally
{
try
{
finallyBlock?.Invoke();
onSuccess?.Invoke();
}
catch (Exception finallyBlockException)
{
onError?.Invoke(finallyBlockException);
// don't override the original exception! Thus throwing a new AggregateException containing both exceptions.
if (tryBlockException != null)
throw new AggregateException(tryBlockException, finallyBlockException);
// otherwise re-throw the exception from the finally block.
throw;
}
}
}
}
and use it like this:
public void ExecuteMeasurement(CancellationToken cancelToken)
{
SafeExecute.Invoke(
() => DUT.ExecuteMeasurement(cancelToken),
() =>
{
Logger.Write(TraceEventType.Verbose, "Save measurement results to database...");
_Db.SaveChanges();
},
() => TraceLog.Write(TraceEventType.Verbose, "Done"));
}
As the comments have suggested this may indicate "unfortunately" structured code. For example if you find yourself in this situation often it might indicate that you are trying to do too much within your method. You only want to throw and exception if there is nothing else you can do (your code is 'stuck' with a problem you can't program around. You only want to catch an exception if there is a reasonable expectation you can do something useful. There is an OutOfMemoryException in the framework but you will seldom see people trying to catch it, because for the most part it means you're boned :-)
If the exception in the finally block is a direct result of the exception in the try block, returning that exception just complicates or obscures the real problem, making it harder to resolve. In the rare case where there is a validate reason for returning such as exception then using the AggregateException would be the way to do it. But before taking that approach ask yourself if it's possible to separate the exceptions into separate methods where a single exception can be returned and handled (separately).
I want to use custom exception handling, for example
instead of using (Exception ex) i want to use (LoginException ex) or (RegistrationException ex) or (SomeNameException ex)
is it possible to design such custom exception handling in ASP.NET webforms?
Yes but what you need to do is first create your own custom exceptions. You need to derive your exception from the Exception base class. Heres an example:
[Serializable]
public class LoginFailedException: Exception
{
public LoginFailedException() : base()
{
}
public LoginFailedException(string message)
: base(message)
{
}
public LoginFailedException(string message, Exception innerException)
: base(message, innerException)
{
}
protected LoginFailedException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
Then in your code, you would need to raise this exception appropriately:
private void Login(string username, string password)
{
if (username != DBUsername && password != DBPassword)
{
throw new LoginFailedException("Login details are incorrect");
}
// else login...
}
private void ButtonClick(object sender, EventArgs e)
{
try
{
Login(txtUsername.Text, txtPassword.Text);
}
catch (LoginFailedException ex)
{
// handle exception.
}
}
You mean something like:
try{
somefunc();
}catch(LoginException ex){
}catch(RegistrationException ex){
}catch(SomeNameException ex){
}
Or do you mean coding the classes to throw the exceptions?