tekiegirl
tekiegirl

Reputation: 1305

How to specify MVC controller/action for a filter/attribute in a class library?

I would be very interested to hear if there is a better way of implementing the following. I don't want to create complex or unmaintainable code.

I am creating a class library which will be implemented by future projects. The library contains a couple of filters/attributes, inheriting from ActionFilterAttribute, which the implementing application can use to decorate controllers or actions.

An example is MustBeLoggedInAttribute. This checks for a cookie to see if the current user is logged in. If there is a valid cookie no action is taken. If there is no valid cookie the attribute redirects to a controller and action, e.g. AuthController > Login().

So as there is an application implementing the class library I don't know what controller or action the application wants to redirect to. I have thought of two ways of getting this information.

  1. Get the implementing app to specify the controller and action name in it's web.config.

    I validate the string names by checking they both exist in the implementing app's assembly, otherwise try a default, e.g. Home > Index(). This method seems to have many cons including

    • making the implementing application less maintainable (changing the controller or action name means updating the web config too)

    • I have to validate the string names

    • The developer of the implementing app needs to read documentation to know to specify this

    • There are probably loads more

  2. Have the filter/attribute take two parameters to specify the controller and action

    This also seems to have some of the pitfalls of the first idea, e.g. updating the names if they are changed, but also the fact that the names would be duplicated throughout the implementing application.

I feel that there must be a better way to do this which would make the implementing app maintainable, not duplicate code, and not be too complex. Is that wishful thinking?

The filter needs to know where to redirect to, but what would be the best way to do it? Or should I be doing this in a completely different way? Should the implementing applications implement their own filters/attributes that then use a public method in my class library to do the cookie checks? Is there an even better way?

I would really appreciate people's thoughts on this as I really don't want to create bad code. Many thanks!

Upvotes: 1

Views: 1157

Answers (2)

fdomn-m
fdomn-m

Reputation: 28611

Old question, but here's a couple of new choices:

Use your option 2, but instead of applying to each action separately, create a base Controller and apply the filter to that controller. Then all actions in that controller and derivatives will need to pass your filter. Put actions that don't need to pass in a different controller that doesn't derive from the filtered base controller. May not be an option depending on how you organise your actions / routes etc, but is probably the easiest.

Alternatively, you could have your filter raise a custom exception, eg MustBeLoggedInException and then have your global asax handle that error specifically in the way it needs to for each application/implementation. Better adherence to single-responsibility-principle: your attribute simply informs your app that it has not passed the filter. You then use some other mechanism to act on that information (eg a redirect in global error handler).

Upvotes: 1

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

You could make your action filter abstract and have some HandleUnauthorizedRequests abstract method that will take the filter context. Now the implementing application will take your base action filter and write a derived one implementing the abstract method and use this class instead. In this method it can do whatever it wants -> redirect, render a view, ...

You could of course provide some default implementation with standard conventional stuff like redirecting to a Account/Logon action. People that want to override this conventional stuff could always do it. This way, you, as a class library author, don't need to worry whether the controller exists - this is the responsibility of the consumer.

Upvotes: 2

Related Questions