Do Action Helpers with hooks to auto-run, throw exceptions or not? - zend-framework

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 ;)

Related

Autofac - (Global) Handler/Middleware to unwrap exceptions

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.

How to call a method in a catch clause on an object defined in a try clause?

I am creating a redis pubsub client in a try-catch block. In the try block, the client is initialised with a callback to forward messages to a client. If there's a problem sending the message to the client, an exception will be thrown, in which case I need to stop the redis client. Here's the code:
try {
val redisClient = RedisPubSub(
channels = Seq(currentUserId.toString),
patterns = Seq(),
onMessage = (pubSubMessage: PubSubMessage) => {
responseObserver.onValue(pubSubMessage.data)
}
)
}
catch {
case e: RuntimeException =>
// redisClient isn't defined here...
redisClient.unsubscribe(currentUserId.toString)
redisClient.stop()
messageStreamResult.complete(Try(true))
responseObserver.onCompleted()
}
The problem is that the redis client val isn't defined in the catch block because there may have been an exception creating it. I also can't move the try-catch block into the callback because there's no way (that I can find) of referring to the redisClient object from within the callback (this doesn't resolve).
To solve this I'm instantiating redisClient as a var outside the try-catch block. Then inside the try block I stop the client and assign a new redisPubSub (created as above) to the redisClient var. That's an ugly hack which is also error prone (e.g. if there genuinely is a problem creating the second client, the catch block will try to call methods on an erroneous object).
Is there a better way of writing this code so that I can correctly call stop() on the redisClient if an exception is raised when trying to send the message to the responseObserver?
Update
I've just solved this using promises. Is there a simpler way though?
That exception handler is not going to be invoked if there is a problem sending the message. It is for problems in setting up the client. This SO answer talks about handling errors when sending messages.
As for the callback referring to the client, I think you want to register the callback after creating the client rather than trying to pass the callback in when you create it. Here is some sample code from Debashish Ghosh that does this.
Presumably that callback is going to run in another thread, so if it uses redisClient you'll have to be careful about concurrency. Ideally the callback could get to the client object through some argument. If not, then perhaps using volatile would be the easiest way to deal with that, although I suspect you'd eventually get into trouble if multiple callbacks can fail at once. Perhaps use an actor to manage the client connection, as Debashish has done?

Entity framework context in using block

I am writing a service layer application, which interacts with database using Entity framework.
I am enclosing my individual "unit-of-work" in a using block, where I initialise my data context.
However I need to throw some exceptions, to convey database errors to applications, which are using my service application. So I am doing something like this:
using (dbcontext = new DbContext())
{
throw new Exception("Error while Saving data");
}
Can anyone confirm if this is Ok? Will Entity framework data context be disposed off correctly even after an exception is thrown?
Yes. A using block is converted to a try/finally block when compiling with disposing logic inside the finally block.
However your exception will not be thrown outside if the Dispose method throws an exception.
Yes this is correct. From MSDN:
A using statement can be exited either when the end of the using
statement is reached or if an exception is thrown and control leaves
the statement block before the end of the statement.
That being said, I would throw a more specific exception than the Exception one.

How to do exception handling with nunit and moq?

I am trying to use nunits new way of exception handling but I am finding it hard to find information on it and how to also use it with moq.
I have right now moq that throws a exception on a mocked method but I don't know how to use nunit to catch it and look at it.
There's a few different ways to do it; I use Assert.Throws.
var exception = Assert.Throws<YourTypeOfException>(()=> Action goes here);
e.g.
var exception = Assert
.Throws<ArgumentNullException>(()=> new ChimpPuncher(null));
You can then query the exception object further if you want, e.g.
Assert.That(exception.Message, Text.Contains("paramname");
Best way to mention is: [ExpectedException(typeof(ApplicationException))] above the test method.
Why can't you enclose the mocked method call in a try/catch block and catch the specific exception being thrown?

How to diagnose "TestFixtureSetUp Failed"

We use TeamCity as our CI server, and I've just started seeing "TestFixtureSetUp Failed" in the test failure window.
Any idea how I go about debugging this problem? The tests run fine on my workstation (R# test runner in VS2008).
It is a bit of a flaw in the implementation of TestFixtureSetUp (and TestFixtureTearDown) that any exceptions are not well reported. I wrote the first implementation of them and I never got it to work the way it was supposed to. At the time the concepts in the NUnit code were tightly coupled to the idea that actions were directly related to a single test. So the reporting of everything was related to a test result. There wasn't really a space for reporting something that happened at the suite level without a huge re-write (it isn't a refactoring when you change a sheep into an escalator).
Because of that bit of history it's hard to find out what really happened in a TestFixtureSetUp. There isn't a good place to attach the error. The TestFixtureSetUp call is a side effect of running a test instead of being directly related to it.
#TrueWill has the right idea. Check the logs and then modify the test to add more logging if necessary. You might want to put at try/catch inside the TestFixtureSetup and log a lot in the catch block. I just thought I could add some background to it (in other words it's kind of my fault).
I'd check the Build Log first.
If it's not obvious from that, you could try including Console.WriteLines in the tests - I'm not positive, but I think those are written to the Build Log. Alternately you could log to a file (even using log4net if you wanted to get fancy).
If you have Visual Studio installed on the CI server, you could try running the build/tests from there. If it's a connectivity issue, that might resolve it.
I've seen path issues, though, where relative paths to files were no longer correct or absolute paths were used. These are harder to debug, and might require logging the paths and then checking if they exist on the build server.
I ran into this today when creating some integration tests that have long running setup that I don't want to duplicate. I ended up wrapping all the test fixture setup logic in a try/catch. I then add a SetUp method whose sole purpose is to see if a failure occurred during fixture setup and provide better logging.
Exception testFixtureSetupException = null;
[TestFixtureSetUp]
public void FixtureSetup()
{
try
{
// DoTestFixtureSetup
}
catch (Exception ex)
{
testFixtureSetupException = ex;
}
}
[SetUp]
// NUnit doesn't support very useful logging of failures from a TestFixtureSetUp method. We'll do the logging here.
public void CheckForTestFixturefailure()
{
if (testFixtureSetupException != null)
{
string msg = string.Format("There was a failure during test fixture setup, resulting in a {1} exception. You should check the state of the storage accounts in Azure before re-running the RenewStorageAccountE2ETests. {0}Exception Message: {3}{0}Stack Trace:{4}",
Environment.NewLine, testFixtureSetupException.GetType(), accountNamePrefix, testFixtureSetupException.Message, testFixtureSetupException.StackTrace);
Assert.Fail(msg);
}
}
I was getting the same error while running any test with SpecFlow using Visual NUnit. When I tried doing the same from the Unit Test Explorer(provided by Resharper), it gave a little more helpful message: Binding methods with more than 10 parameters are not supported. I realized I can't have a SpecFlow method with more than 10 params, had to remove the test.
I was able to see that I was not creating my test database correctly by doing a quick switch to VS Unit Testing. In my Case it was able to return a better response to the reason why it failed. I usually use NUnit.
"Unable to create instance of class X. Error: System.Data.SqlClient.SqlException: A file activation error occurred. The physical file name '\DbTest.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation.
CREATE DATABASE failed. Some file names listed could not be created. Check related errors..
"
Run the unit test in debug mode. You may find a runtime error in the the setup.
If you are using SpecFlow and C# in Visual Studio, look at the auto-generated <whatever>.feature.cs file after the test fails. On the public partial class <whatever>Feature line, you should see a symbol which when hovered over will show the reason that the NUnit fixture setup failed. In my case, it was that some of my BeforeFeature methods in my TestHooks class were not static. All BeforeTestRun, AfterTestRun, BeforeFeature, and AfterFeature methods need to be static.
I had this issue and it was caused by adding a private readonly Dictionary in the class, much the same way that you add a private const string.
I tried to make the Dictionary a constant but you can't do that at compile time. I solved this by putting my Dictionary in a method that returns it.
I was troubled by this today. I did the following to get the actual error.
(1) Write another test in a separate fixture which initializes an instance of the troubling test fixture, explicitly calls setup methods such as TestFixtureSetUp and SetUp if any, and then executes the target test method.
(2) Add exception handling code for the new code above, and log / output the actual exception to somewhere.
You can catch the exception and write it in the console on the TearDown
Something like:
[SetUpFixture]
public class BaseTest
{
private Exception caughtException = null;
[SetUp]
public void RunBeforeAnyTests()
{
try
{
throw new Exception("On purpose");
}
catch (Exception ex)
{
caughtException = ex;
}
}
[TearDown]
public void RunAfterAnyTests()
{
if (caughtException != null)
{
Console.WriteLine(string.Format("TestFixtureSetUp failed in {0} - {1}", this.GetType(), caughtException.Message));
}
}
}
And the result will be:
TestFixtureSetUp failed in IntegratedTests.Services.BaseTest - On purpose
I had this symptom caused by an error during field initialization. If you initialize your fields in the [SetUp] method, you should see a better error message.
[TestFixture]
internal class CommandParserTest
{
// obscure error message
private CommandParser parser = new CommandParser(...);
...
}
[TestFixture]
internal class CommandParserTest
{
private CommandParser parser;
[SetUp]
public void BeforeTest()
{
// better error message
parser = new CommandParser(...);
}
...
}