1

We have a bunch of MVC and WebAPI projects that use dependency injection to access service classes and other dependencies like that from the controllers in both frameworks. The problem I'm having is that I wanted to make all the services specific to each project internal, but I can't because the controller classes on both frameworks need to be public, which causes compilation errors if I try to receive instances of parameters that are internal types using constructor injection.

This has bitten me more than once. It happens with almost all frameworks that call your code, be it web frameworks like WebAPI, MVC or even WebForms, and with other kinds of projects like tests, where the test classes need to be public also.

My understanding of object orientation in general is that you want to have as closed a scope as possible, so that things only have access to a minimal set of features that they need to work with. I find this a very good approach in general, because it minimizes the influence of other stuff on each class, and leads to clearer and easier to discover code.

My service classes are just that. They were created to be used just by the controllers in the same assembly, and by nobody else. By having to mark them public, I'm exposing them to external callers for no reason, and I lose a lot of important compile time information by doing so, like for instance FxCop will warn me if there is no one calling a certain method from an internal class, but it can't infer that if the class is marked public, since someone else outside of the project (or even the solution) could be using that type and calling that method.

This extends to interfaces as well obviously. As I said, we are using dependency injection (with Unity) and usually there is a interface for each service class in that scenario. Even if I can mark implementations themselves as internal, needing the interface to be public is still not ideal.

Is there some pattern that would allow me to cleanly define internal classes and interfaces but still work with external frameworks that need my outside facing classes to be public so they can call me? How should I proceed in general to make sure my code is as tightly scoped as possible?

julealgon
  • 7,072
  • 3
  • 32
  • 77

1 Answers1

0

I recommend using the facade pattern, discussed here:

http://en.m.wikipedia.org/wiki/Facade_pattern

Brennan Pope
  • 1,014
  • 7
  • 11
  • I know about the façade pattern, but it wouldn't solve the problems I mentioned at all, it would just transfer them to the façade interface and implementation. – julealgon Mar 26 '15 at 14:22
  • Yes, it would transfer the problems to the facade. I was assuming that you could provide a limited subset of the functionality of your service classes in the facade, therefore limiting the access of any external caller. – Brennan Pope Mar 26 '15 at 16:33
  • What about just giving the external assembly access to your internals using this directive: `[assembly: InternalsVisibleTo("name of assembly here")]` I saw this here: [C# - How to access internal class from external assembly](http://stackoverflow.com/questions/920844/c-sharp-how-to-access-internal-class-from-external-assembly) – Brennan Pope Mar 26 '15 at 18:50
  • 1
    The problem is that the assembly I need to "give permission to" is not mine in this case. You see, this is why I said _using external frameworks_ in the title. What happens is that MVC needs to create the routes and controllers, but if I mark the controller as `internal` then the MVC engine does not recognize it as a valid controller and I get a 404 response. The same thing happens with other frameworks: in WebForms, page classes need to be public, and MSTest also requires test classes to be public. The effect on the later two is less pronounced because they don't support dependency injection. – julealgon Mar 26 '15 at 18:56
  • Thank you for the explanation. I have one final idea that I'm not sure I really want to put out there, but would it be worth it to localize your service classes to the projects that need them? You could still have a central version of the code in source control. – Brennan Pope Mar 26 '15 at 19:23
  • Or are you saying the projects depending on your service classes are not under your control? – Brennan Pope Mar 26 '15 at 19:31
  • 1
    I'm doing exactly that already actually. The controller classes are the only ones that need the services, and they are located on the same assembly. The problem is that I _need_ to mark those controllers as `public` because the external frameworks require it. This in turn makes it impossible for me to mark my service classes as `internal`, due to the fact that it's illegal to have a public class depend on an internal one in C# via it's constructor. I want to keep the constructor dependency scheme because it is the best possible place to perform dependency injection. – julealgon Mar 26 '15 at 19:46