tags:

views:

79

answers:

3

I'm writing some unit tests to assert that all our controller action methods are marked with proper custom attributes, but I don't really know what the criteria is for determining whether a public method can act as MVC action or not.

I would assume that a criteria could be the return value type (it has to be ActionResult or a derivative). Is this true? What about static methods?

+1  A: 

I beleive all public methods in a controller are treated as actions - even one returning a string.

UpTheCreek
appart from the ones mentioned by saulius ;)
UpTheCreek
+4  A: 

For a method to be considered an action, it has to meet the following criteria:

  • It must be public and not static
  • It must not have a "special" name in order to exclude constructors, events etc.
  • It must not be defined on System.Web.Mvc.Controller or any other base class in order to exclude .ToString() and family.

Generic methods will throw an exception, yet for some reason they are considered actions. As for the return type, it does not necessarily have to be an ActionResult, since you can return e.g. a string for text data.

Saulius
The third point is what I was looking for: I didn't know what to do with methods like Dispose() and such. Thanks
Igor Brejc
Please note that it gets very tricky when you have things like the [NonAction] attribute applied to action methods. A public method that might otherwise appear to be an action method could have an attribute that overrides the default behavior.
Eilon
+1  A: 

Determining the true list of actions on a controller is a tricky problem. The only correct answer is that it "depends"! The list that Saulius gave is pretty much correct - if you're using the default ControllerActionInvoker - which of course, most people use.

If you want to avoid duplicating the logic I would recommend using the ControllerActionInvoker itself to get the list of actions and then verify the contents of the list that it returns.

You'll have to write a class that derives from ControllerActionInvoker so that you can call the GetControllerDescriptor() method. The return value of that method is a ControllerDescriptor, which is an abstract descriptor of what the controller has. You can then call GetCanonicalActions(), which returns a list of ActionDescriptors. Each of those items represents what is typically and action method.

To hook it all up you'll need to:

  1. Instantiate your controller
  2. Set its ActionInvoker property to be an instance of your custom invoker
  3. Create a ControllerContext instance that has its Controller instance set to your controller
  4. Call a new public method on your invoker that in turn calls GetControllerDescriptor()

Then verify the results and you're done!

Of course, I haven't tried any of this but in theory it all works :)

Eilon