We would like to add a handler/middleware to Autofac to essentially unwrap any Autofac.Core.DependencyResolutionException; to throw the inner exception.
Hooking the Activation (or RegistrationPipelineStart) Pipeline phases (using the following code) unwraps one of the exceptions, but the exception ultimately get wrapped by another DependencyResolutionException.
container.RegisterServiceMiddleware<IOController>(PipelinePhase.ResolveRequestStart, (context, next) =>
{
try
{
next(context);
}
catch (Exception ex)
{
// This unwraps one exception, but even if this is done another exception is wrapped.
// If the inner exception is not thrown, there is a DependencyResolutionException wrapped in another DependencyResolutionException
throw ex.InnerException;
}
});
Irrespective of the phase, I always end up with the exception being wrapped.
I think I need to override the behaviour of ActivatorErrorHandlingMiddleware, but I cannot see a way to do this.
(I understand that Constructors should be lightweight an not throw exceptions, but we have a very large application, and are in the process of refactoring the internals...this will take several versions/iterations, so not really a possibility).
Many Thanks in advance.
Related
I see people use onError just for debugging. I thought I could use it to emit new states like emit(ErrorState(message: "An error")). But with the new versions of the bloc package, we should use emitters provided to the handlers and shouldn't use the dedicated function emit directly.
Currently I have try/catch blocks in all of my event handlers. If any error occurs, I emit the ErrorState with a message and show it in the UI with a widget. Is this how should I handle errors? This makes event handler functions to look awful with these try/catchs. I wonder if I'm doing it correct and want to know how should it be done actually?
void _startExercise(ExerciseStarted event, Emitter<ExerciseState> emit) async {
emit(ExerciseLoadingState());
try {
final something = await _repository.doSomething();
emit(ExerciseLoadedState(something: something));
} catch (e) {
log(e.toString());
emit(const ExerciseErrorState());
}
}
Well, let's separate this problem into two parts:
You get an error and you want to emit/change the state.
In this case, your provided code example is doing it properly - you have to use try/catch and emit an error state in case of an Error/Exception. The only thing I would adjust there is to change catch (e) {...} to on Exception catch (e) {...} since Dart errors must be handled in your code and you could simply miss them in case you catch everything there.
You get an error and just want to handle it.
In this case, you can handle errors inside the repository. E.g. use the try/catch blog inside the repository and log the error. Since you do not need to emit a state change, the error will be handled as well as your event handler won't be cluttered with this extra try/catch logic.
Anyway, whichever way you choose, just be consistent and you should be good to go.
I am trying to create a repository for use cases of FirebaseAuth and can see warnings!
Should I ignore the warning, as it not impacting the app?
OR should I handle it now, and How?
Dart has analyzed your program and found out that you have not handled all cases how the method can exit. This is a potentially a problem since your method signature specifies that you method are returning a Future<User> object.
In your case you have not handled the case where an exception are throw from the createUserWithEmailAndPassword method. If an exception are catch, you ends up with a execution path without any return statement.
In this case, Dart will at runtime just return null so it is not an error. But it is a potential sign of a code error since it it not unlikely that you have forgotten the handling of the exception by not have any return statement.
If it is your intention to just return null in case of an exception, you should therefore have insert return null; in both of your catch blocks (or just at the bottom of your method outside the catch-blocks).
Alternative, you can rethrow the exception if you just want to add some logging but still let the caller to also handle the exception. You can read more about this in the language tour: https://dart.dev/guides/language/language-tour#catch
In either cases, you should describe the behavior in the documentation of the method.
Dart explicitly makes a distinction between Error, that signals a problem in your code's logic and should never happen and should never be caught and Exceptions that signal a problem based on run-time data.
I really like this distinction but I wonder when should I then use assert() functions?
Asserts are ways to perform code useful in development only, without hindering the performances of release mode – usually to prevent bad states caused by a missing feature in the type system.
For example, only asserts can be used to do defensive programming and offer a const constructor.
We can do:
class Foo {
const Foo(): assert(false);
}
but can't do:
class Foo {
const Foo() { throw 42; }
}
Similarly, some sanity checks are relatively expensive.
In the context of Flutter, for example, you may want to traverse the widget tree to check something on the ancestors of a widget. But that's costly, for something only useful to a developer.
Doing that check inside an assert allows both performance in release, and utility in development.
assert(someVeryExpensiveCheck());
Background
In Dart an Exception is for an expected bad state that may happen at runtime. Because these exceptions are expected, you should catch them and handle them appropriately.
An Error, on the other hand, is for developers who are using your code. You throw an Error to let them know that they are using your code wrong. As the developer using an API, you shouldn't catch errors. You should let them crash your app. Let the crash be a message to you that you need to go find out what you're doing wrong.
An assert is similar to an Error in that it is for reporting bad states that should never happen. The difference is that asserts are only checked in debug mode. They are completely ignored in production mode.
Read more on the difference between Exception and Error here.
Next, here are a few examples to see how each is used in the Flutter source code.
Example of throwing an Exception
This comes from platform_channel.dart in the Flutter repo:
#optionalTypeArgs
Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
assert(method != null);
final ByteData? result = await binaryMessenger.send(
name,
codec.encodeMethodCall(MethodCall(method, arguments)),
);
if (result == null) {
if (missingOk) {
return null;
}
throw MissingPluginException('No implementation found for method $method on channel $name');
}
return codec.decodeEnvelope(result) as T;
}
The MissingPluginException here is a planned bad state that might occur. If it happens, users of the platform channel API need to be ready to handle that.
Example of throwing an Error
This comes from artifacts.dart in the flutter_tools repo.
TargetPlatform _currentHostPlatform(Platform platform) {
if (platform.isMacOS) {
return TargetPlatform.darwin_x64;
}
if (platform.isLinux) {
return TargetPlatform.linux_x64;
}
if (platform.isWindows) {
return TargetPlatform.windows_x64;
}
throw UnimplementedError('Host OS not supported.');
}
First every possibility is exhausted and then the error is thrown. This should be theoretically impossible. But if it is thrown, then it is either a sign to the API user that you're using it wrong, or a sign to the API maintainer that they need to handle another case.
Example of using asserts
This comes from overlay.dart in the Flutter repo:
OverlayEntry({
required this.builder,
bool opaque = false,
bool maintainState = false,
}) : assert(builder != null),
assert(opaque != null),
assert(maintainState != null),
_opaque = opaque,
_maintainState = maintainState;
The pattern in the Flutter source code is to use asserts liberally in the initializer list in constructors. They are far more common than Errors.
Summary
As I read the Flutter source code, use asserts as preliminary checks in the constructor initializer list and throw errors as a last resort check in the body of methods. Of course this isn't a hard and fast rule as far as I can see, but it seems to fit the pattern I've seen so far.
As asserts are ignored in production mode, you should use them as way to do initial tests to your code logic in debug mode:
In production code, assertions are ignored, and the arguments to assert aren’t evaluated.
When exactly do assertions work? That depends on the tools and framework you’re using:
Flutter enables assertions in debug mode.
Development-only tools such as dartdevc typically enable assertions by default.
Some tools, such as dart and dart2js, support assertions through a command-line flag: --enable-asserts.
In production code, assertions are ignored, and the arguments to assert aren’t evaluated.
Refer:https://dart.dev/guides/language/language-tour#assert
What practices do you use in your datalayer to catch sql exceptions?
Has anybody written a Generic Sql Exception handler where they catch the most common errors ?
how do you do it any examples out there?
Thanks
Handle unexpected exception by the underlying layer only
Exceptions from your data layer (in this case Entity Framework) should be handled only by your business layer. The business layer can raise then (if necessary) a more high-level exception for your presentation layer (UI).
Don't throw and catch exceptions across more than one layer of your application. This is considered to be bad practice. The presentation layer should only handle business layer exceptions.
Never swallow exceptions by using:
try {} catch (Exception) { // who cares }
Catch expected exceptions as early as possible
Always try to handle expected exceptions (e.g. FileNotFoundException) as soon as possible. If you can handle it, handle it directly there. If not, re-throw a Custom Exception and handle it in your underlying layer.
Don't clear the stack trace when re-throwing an exception
Catch and re-throw implicitly (see)
try {} catch (Exception) { throw; }
and not explicitly
try {} catch (Exception ex) { throw ex; }
UPDATED
Wanting some code to run with each controller, and being told to use Action Helpers or a Plugin rather than extending from a Base Controller, I decided on an Action Helper rather than Plugin, per excellent slides by #Bittarman (Ryan Mauger);
Zend Framework, getting to grips:
http://www.slideshare.net/rmauger/zend-framework-getting-to-grips
See slide 22:
Thrown Exceptions in (action helpers) Pre/Post Dispatch will stop further execution...
While it DOES stop further execution, the exception wasn't caught. I've been trying to debug this for hours but not getting anywhere.
If you run the following code, are you seeing exceptions caught or is it escaping the Error Controller?
I'm trying to figure out whether Zend Framework is NOT behaving as expected, or if I totally messed something up (more likely).
I tried to break this down into the simplest case to replicate, let me know what you see:
/* add to existing Bootstrap located here: APPLICATION_PATH/Bootstrap.php */
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH .'/controllers/helpers');
//hooks cause action helper to autorun: http://akrabat.com/zend-framework/hooks-in-action-helpers/
$hooks = Zend_Controller_Action_HelperBroker::getStaticHelper('Test');
Zend_Controller_Action_HelperBroker::addHelper($hooks);
}
/* in: APPLICATION_PATH/controllers/helpers/Test.php */
<?php
class Zend_Controller_Action_Helper_Test extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
// you can skip next line if you don't have xdebug
//xdebug_disable();
throw new Exception('test', 404);
parent::preDispatch();
}
}
Update:
OK, I've been running this through xDebug + Eclipse... (it was either that or have fun poking my eyes out, not sure if I chose the more pleasurable experience)....and I found out something bizarre.
The preDispatch is running twice!
And on the second call, it goes to the Zend_Controller_Plugin/ErrorHandler.php
where it runs this code:
if ($this->_isInsideErrorHandlerLoop) {
$exceptions = $response->getException();
if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {
// Exception thrown by error handler; tell the front controller to throw it
$frontController->throwExceptions(true);
throw array_pop($exceptions);
}
}
By setting throw Exceptions to true, it no longer gets caught. And I suspect this is to save a loop from occurring ($this->_isInsideErrorHandlerLoop is a subtle clue too ;)
Why is it in a loop?
OK, #Bittarman gave me the answer in #ZFTalk on IRC. Here it is (and apologies that I will mark my own answer as correct..but I don't want to bug him even more to write it up here).
if( ($this->getRequest()->getActionName() == 'error') && ($this->getRequest()->getControllerName() == 'error')) {
return;
}
The reason for this is that the error handler has to disable itself
(by setting throw exceptions to true) when its in the error
handler loop. So you have
to make sure your exception condition does not occur in the error controller.
The ErrorHandler plugin is designed to catch exceptions thrown by the mvc-component, not by plugins. It hooks into the postDispatch and checks for exceptions of the dispatch - and nothing else.
It won't catch exceptions prior to this like in the preDispatch.
If you have a look at the source of the ErrorHandler Plugin you can see that it checks for Exceptions in the Request object. This only works if the frontController option 'throwExceptions' is set to false which makes him to catch exceptions and store them for later use (like the plugin handler).
In your case the exception isn't caught by the frontcontroller thus thrown to the very top of the application. You sure can edit the frontController to catch exceptions prior to the dispatch - but this isn't implemented intentional: everything prior to the dispatch can be seen as "booting" the application: any exception there is critical. Like in real booting, any exception there stops the application to run. So you really should avoid any exceptions there.
Update: Ok this was for the plugin part and forgot you wanted to know for the ActionHelper part. Those aren't executed by the FrontController but by the Zend_Controller_Action. As there they're part of the dispatching and caught by the FrontController and handled by the ErrorHandler plugin.
But what does the ErrorHandler do? It adds another request to the FrontController with your errorController. So another dispatching loop is done and again, your actionhelper does throws an exception. As the errorController request isn't different to any other request, the ErrorHandler plugin would catch it again and chain another request of the errorController. Which again.. i guess you can see where this would lead to - a loop. To prevent this there is a property to see if there was already an exception somewhere. This is to catch any exception thrown by the error handler. If the ErrorHandler plugin notices such an exception it overwrites the throwException property to true and throws the exception.
So the unhandled exception you can see is the exception which rises from the errorController request.
I can see the point that ActionHelpers can throw an exception - but you should be really careful with that for exactly this reason ;)