2
\$\begingroup\$

I am a little confused over which layers my filters should be contained in with an n-layer web application.

I've got 4 layers:

  • Presentation layer
  • Application layer
  • Business layer
  • Infrastructure layer

The Presentation layer can only talk to the Application layer and the Infrastructure layer. The Application layer can only talk to the Presentation layer, Business layer and the Infrastructure layer. The Business layer can only talk to the Application layer and the Infrastructure layer.

All my models, views and controllers are stored in the Presentation layer.

I have the following code:

public class AuthoriseAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (SkipAuthorisation(filterContext))
        {
            return;
        }

        // This line...
        var evalReportProxy = new EvalReportProxy(WebHelper.PcwAliasName);
        if (evalReportProxy.EvalReport.SubscribedToModule("Workspace Only"))
        {
            filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary 
            { 
                { "controller", "Redirect" },
                { "action", "Workspace" }
            });
        }

        if (string.IsNullOrEmpty(WebHelper.Username) || WebHelper.IsGuest)
        {
            filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary 
            { 
                { "controller", "Account" },
                { "action", "LogIn" }
            });
        }
    }

    private static bool SkipAuthorisation(AuthorizationContext filterContext)
    {
        return filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
            || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
    }
}

I've highlighted a line of code using a comment which shows where I am making use of a concrete type in the infrastructure layer to check to see if a user is subscribed to a module. By using a concrete type I've made it impossible to use mock objects which I want to avoid, but...

I'm a little confused because in the line highlighted using a comment I guess I should really be using a repository or a service although I'm not really sure if I should be or not. Also, if I use a repository then the filters can't be in the presentation layer, but I'm not sure if services are purely for controllers or whether I can use services elsewhere.

Can anyone please advise me on whether I should be putting filters in the presentation layer or not, and whether or not I should be using a service, repository, or keep the code how it is.

Also, I'm open to code improvements if you think any can be made.

\$\endgroup\$
4
  • \$\begingroup\$ I would keep the AuthoriseAttribute part of the presentation layer I think and use the service to do the main logic validation like you are doing. \$\endgroup\$
    – dreza
    Commented Jul 8, 2015 at 9:26
  • \$\begingroup\$ Maybe I drew out your dependencies incorrectly, but how are you not having a circular reference errors? \$\endgroup\$ Commented Jul 8, 2015 at 12:31
  • \$\begingroup\$ Where do you think I'd have circular reference errors? I am unclear on how you have came to this conclusion. \$\endgroup\$ Commented Jul 8, 2015 at 13:03
  • \$\begingroup\$ Jamal, why did you change the title as the question is not relating to "locating" filters, it is more so related to where in the solution they should reside, but now the title is quite confusing. You have updated a number of questions I've asked in the same manner. \$\endgroup\$ Commented Jul 8, 2015 at 16:38

1 Answer 1

2
\$\begingroup\$

Here's my take on this problem.

Your use of the AttributeFilter in the presentation layer is fine. You are correct about avoiding the use of a Repository in the filter, it does not belong there. However you can call upon the business layer (which in turn calls your repository) to check if they are subscribed. Keep your business logic where it belongs.

Dependencies in Filters can be mocked, you simply need to create a constructor which accepts the IBusinessService of your choice. Most dependency injection frameworks will create Filters and pass in the correct dependency.

If you don't want to go down that route, change your Filter like so.

class AuthoriseAttribute {

  // Use for testing
  public AuthoriseAttribute(IMockedBusinessService) {
  }

  // Production
  public AuthoriseAttribute():this(new ConcreteBusinessService()) {
  }
}

As always with these things, "it depends". If you have a high performance site, say > 200 connections per second and you get considerable performance gains by having the repository in directly in the presentation layer, then I would bend the rules and leave a nice comment in the code on why you have data access in the presentation layer.

Almost always I prefer code readability and separation of concerns much higher than anything else. Just be sure to take measurements on the performance gains by doing X. If your not measuring, your guessing.

\$\endgroup\$
1
  • \$\begingroup\$ I've gone with this method but rather than using a concrete type with poor man's dependency injection I require a type to be passed which must either be an interface or type which implements the required interface and then I use Windsor to resolve it. \$\endgroup\$ Commented Jul 10, 2015 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.