0

I worked for a client a number of years ago (who I won't name to protect the guilty) that would periodically have information like the following in their View logic:

if (client == "a") {
   // ...
}
else if (client == "b") {
   // ...
}
else {
   // ...
}

Their platform was ColdFusion (yeah, don't laugh) and this was part of the template for their primary form process.

Obviously, this is cringe-worthy and terrible for numerous reasons.

I was recently thinking about how I would've architected that instead. My first thought was to use a Template Method pattern combined with either Dependency Injection or a Factory Pattern (to abstract away the client-specific reasoning) for the view in question.

Obviously, this solution assumes that you construct views on the "back end." This isn't really the "standard" way of doing this anymore, though, and most people seem to have switched to some kind of MVC architecture (ASP.NET MVC, Ruby on Rails, etc.). With that in mind, I did notice that ASP.NET Core includes support for Dependency Injection into views, as does MVC 4.

I'm hoping this isn't too simple of a question, but is what I describe above still valid way to solve this problem in MVC-based frameworks (especially ASP.NET MVC)? In particular, I'm confused about how to apply this to ASP.NET Views; I know that the Views support Dependency Injection, but is there some kind of analogy to a Template Method pattern for ASP.NET views that won't result in inappropriate mixing of business and view logic? Or am I on the wrong track here entirely?

  • 1
    I would recommend against any kind of DI wiring directly into the View, even if MS gives us a way to do so. You're better off having a ViewModel constructed in the controller, which handles all that, and the View is only aware of the properties/methods of that ViewModel. Views are not the place to be doing data calls. – Graham Feb 10 '17 at 19:44
1

In ASP.Net, Views are still typically rendered on the backend but even so your suggested approach - a Factory - that is indeed an accepted way of doing this.

Template methods don't necessarily come into it either, you can choose to use them or not; the implementations of the classes that have the client-specific code in them might use them as the mechanism to achieve Polymorphism via inheritance and implementation of abstract base class or methods, or you might go with a plainer interface implementation.

Here's an example using a more classic Controller->Model->View scenario; note that I haven't shown injection of the dependencies and the factory is really just a switch statement so in real life, you'd use an IOC library, and inject the factory into the Controller, as well as using the container's built-in factory ability. I just wanted to keep things clear in this case.

public interface IClientSpecificFoo
{
    FooDataModel GetTheFoo();
}

Implementations of IClientSpecificFoo are not shown, this is where you might decide to implement them using inheritance or composition, it's really up to you.

public class ClientSpecificFooFactory
{
    public IClientSpecificFoo GetFooProviderFor(string clientId)
    {      
       switch(clientId)
       {
           case "clientA":
              return new ClientAFoo();
              break;
            case "clientB":
              return new ClientBFoo();
                break;
            default:
                return new GenericClientFoo();         
       }
    }
}

public class ClientSpecificController: Controller
{
    public ActionResult SomethingSpecific()
    {       
        var clientId=GetClientIdFromHeaders(); //or whatever way you identify the client
        var factory = new ClientSpecificFooFactory();
        var clientSpecificFoo = factory.GetFooProviderFor(clientId);
        var model = clientspecificFoo.GetTheFoo();
        return View(model);
    }
}

The View itself in all cases would be the same, it just renders the FooDataModel given to it by the Controller.

and that's it really.

  • What if different clients want changes to things like stylesheets, etc. for their version? Can the same mechanism be used? – EJoshuaS Feb 10 '17 at 20:17
  • 1
    @EJoshuaS - yes - you can have a handler that serves those files as well, and vary it by client id. Or even simpler, reference those css files using a folder structure by client id e.g. <link rel="stylesheet" type="text/css" href="~/styles/byClientId/@ViewBag.ClientID/main.css"> etc – Stephen Byrne Feb 10 '17 at 21:27
  • Yeah, that makes sense. – EJoshuaS Feb 10 '17 at 21:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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