Skip to content

Chapter 6: Presenters & View-Models

So far we covered the more command/write-side focused use-cases. It was pretty straight forward to implement this in a Clean Architecture fashion. What really got me think for a longer time (days or weeks) was the kind of use-cases where real user-output (eg. HTML) must be produced. This is the part where the Presenters come into the play.

If we take a look again at the control-flow in Uncle Bobs diagram at the beginning we see the following:

  1. Controller calls the interactor using the input-port.
  2. Interactor calls the output-port.
  3. Presenter implements the output-port and renders things to the UI.

This means that a presenter can render stuff on its own to “the user-interface”. This is not how standard MVC works. In standard MVC we have the following flow.

  1. Controller gets the user-input.
  2. Controller coordinates some kind of logic to do things.
  3. Controller returns a action result like a view result with the view-model needed to render the view.
  4. The ASP.Net pipelines fires the view-engine with the viewname and view-model from the view-result after the controller-action was finished.

Hmm… so how to bring these worlds closer to each other. I know that Uncle Bob would not like to use standard MVC at all because it highly couples our overall architecture and dependencies to a framework we don’t have control over it. Regarding Uncle Bub, even the ASP.Net MVC part of the application should be an implementation detail that does not affect your architecture.

I, on the other hand, have a existing MVC application and I like to use MVC as it was thought by its inventors for several reasons. First one is that if other developers join they at least know the basics. Other reason is documentation, communities and general help.

Maybe one day I find the time to have a closer look at frameworks like Nancy where I think I am more free with these architectural decisions.

So again, how can I get things closer to Clean Architecture?

I did some googling and found a few people thought about this already. Plainionist wrote a really nice series of article about this here. Another nice thread I found on here Stack-Overflow and one here on CodeReviews.

Regarding the control-flow we like to get this: controller-interactor-presenter.

Option 1: The controller gets the interactor result and create a view-model and returns the view. This will not result in the control flow as of Clean Architecture because no output-ports and presenters are used at all. The flow would be controller-interactor-controller.

Option 2: The controller gets the interactor result and forwards it to a presenter which builds and returns the view-model to the controller so the controller can return a view based on the presenters view-model. This is also not the Clean Architecture control-flow as its controller-interactor-controller-presenter-controller.

Option 3: The controller triggers the interactor and provide the presenter as the output port. The interactor then calls the presenter which builds the view-model. Finally the controller gets the view-model from the presenter and returns the view. Again its not exactly the Clean Architecture control-flow: controller-interactor-presenter-controller.

Option 4: Like option 3 but split controller into MVC- and Clean-Architecture-controller. This would result in the flow MVCcontroller-controller-interactor-presenter-MVCcontroller. Again not quite the Clean Architecture way. But if we remove the technical MVC-Controllers from the above equation we are in the green zone of Clean Architecture. I guess Uncle Bob would also like this because the controller-logic is split away from the MVC-Framework and therefore its dependency.

Why don’t we get the exact Clean Architecture flow? Its because we use MVC where we have to build a view and return the view to the framework which finally renders the HTML. This means we don’t have a self-containing render-flow. At least not if we stick to the MVC framework and therefore can not freely control the flow.

So what did I choose?

I like to go close with Clean Architecture but don’t do too much extra work. So I went with … tatarataaa … Option 3 (with one eye to option 4 – maybe one day I go for 4).

The next question regarding presenters was:

How to inject the presenter into the interactor?

I basically see two options here:

Option 1: Inject the output-port (eg. presenter) using a interactor constructor parameter (constructor injection).

Option 2: Pass the output-port (eg. presenter) to the input-port into the interactor.

The advantage of the first option is that you register the presenter as the output-port implementation with your DI and let the DI inject it. This way the controller does only know the presenters interface to get the view-model or the view out of it.

The advantage of option 2 is that one can pass different output-port implementations to the same interactor depending where the interactor is used. This increase the re-usability of the interactor.

What did I choose? I switched forth and back between these options but finally decided for option 2 because the very same application instance may not only host MVC- but also WebAPI controllers in the future. Using option 2 I can re-use the interactors for my REST-API and for my HTML-App. The only difference is that I pass in another output-port implementation. MVC-Presenter or JSON-Resenter.

With the stage set on how to implement Clean Architecture output-ports and presenters let’s have a look at the code I came up:

First the controller-action to renders the detail page of a LogbookEntry:

public async Task Detail(Guid id)
{
    var presenter = new MvcLogbookDetailsOutputPort(relativeUrlGenerator, logbookDetailsUrlGenerator);
    var interactorResult = await mediator.Send(new GetLogbookEntryDetails(id, presenter, await GetAllowEdit()));
    if (!interactorResult.IsSuccessful)
    {
        ShowErrorMessage("Fehler beim laden der Daten des Logbucheintrages!");
    }

    return View(presenter.GetViewModel());
}

Notes:

  • First the MVC-specific presenter is created including all the dependencies the presenter needs. I’m thinking of changing this so the presenter get created and injected into the controller using DI using constructor injection.

  • The presenter implements the interactors output-port.

  • The interactor-command (aka interactor input) is sent including a reference to the presenter as the output-port.

  • Basic error handling is done based on the interactor result.

  • Finally the controller asks the presenter for the view-model and returns a view. I am thinking if I should move the View() statement to the presenter so the presenter will not only return a view-model but an entire view. This would take further UI-logic away from the controller and move it to the presenter.

Let’s see how to presenter looks like:

    public class MvcLogbookDetailsOutputPort : ILogbookDetailOutputPort
    {
        [NotNull] private readonly IRelativeUrlGenerator relativeUrlGenerator;
        [NotNull] private readonly ILogbookDetailsUrlGenerator detailsUrlGenerator;
        private LogbookDetailViewModel viewModel;

        public MvcLogbookDetailsOutputPort(
            [NotNull] IRelativeUrlGenerator relativeUrlGenerator,
            [NotNull] ILogbookDetailsUrlGenerator detailsUrlGenerator)
        {
            this.relativeUrlGenerator = relativeUrlGenerator ?? throw new ArgumentNullException(nameof(this.relativeUrlGenerator));
            this.detailsUrlGenerator = detailsUrlGenerator ?? throw new ArgumentNullException(nameof(detailsUrlGenerator));
        }

        public void Output([NotNull] GetLogbookEntryDetailOutput interactorOutput)
        {
            if (interactorOutput == null) throw new ArgumentNullException(nameof(interactorOutput));

            viewModel = new LogbookDetailViewModel(
                interactorOutput.AllowEdit,
                interactorOutput.LogbookEntryId,
                interactorOutput.Title,
                interactorOutput.IsFavorite,
                interactorOutput.CreatedAt.ToStringSwissDateTime(),
                ...)
            );
        }

        public LogbookDetailViewModel GetViewModel() => viewModel;
    }

Notes:

  • The presenter implements the ILogbookDetailOutputPort by implementing the Output() method with the signature as defined by the output-port. Note that the interactors only know and depend on the output-port interface. He doesn’t know who implements it nor that there are presenters or even view-models at all.

  • The view-model can be retrieved from the presenter using get GetViewModel() method.

  • The presenter converts the output from the interactor to a view-model so view view has an easy job. This means that the presenter converts complex objects to with basic data-types. In the above example you see that DateTime types get converted into strings so the views don’t need to do such conversions. More complex views get an more specialized view-model so the presenter for example builds multiple lists based on one interactor output. As said: the view should have as less logic as possible. Address render-logic in the presenter if possible.

Let’s continue here …

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: