Pergunta

The Clean Architecture suggests to let a use case interactor call the actual implementation of the presenter (which is injected, following the DIP) to handle the response/display. However, I see people implementing this architecture, returning the output data from the interactor, and then let the controller (in the adapter layer) decide how to handle it. Is the second solution leaking application responsibilities out of the application layer, in addition to not clearly defining input and output ports to the interactor?

Input and output ports

Considering the Clean Architecture definition, and especially the little flow diagram describing relationships between a controller, a use case interactor, and a presenter, I'm not sure if I correctly understand what the "Use Case Output Port" should be.

Clean architecture, like hexagonal architecture, distinguishes between primary ports (methods) and secondary ports (interfaces to be implemented by adapters). Following the communication flow, I expect the "Use Case Input Port" to be a primary port (thus, just a method), and the "Use Case Output Port" an interface to be implemented, perhaps a constructor argument taking the actual adapter, so that the interactor can use it.

Code example

To make a code example, this could be the controller code:

Presenter presenter = new Presenter();
Repository repository = new Repository();
UseCase useCase = new UseCase(presenter, repository);
useCase->doSomething();

The presenter interface:

// Use Case Output Port
interface Presenter
{
    public void present(Data data);
}

Finally, the interactor itself:

class UseCase
{
    private Repository repository;
    private Presenter presenter;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.repository = repository;
        this.presenter = presenter;
    }

    // Use Case Input Port
    public void doSomething()
    {
        Data data = this.repository.getData();
        this.presenter.present(data);
    }
}

On the interactor calling the presenter

The previous interpretation seems to be confirmed by the aforementioned diagram itself, where the relation between the controller and the input port is represented by a solid arrow with a "sharp" head (UML for "association", meaning "has a", where the controller "has a" use case), while the relation between the presenter and the output port is represented by a solid arrow with a "white" head (UML for "inheritance", which is not the one for "implementation", but probably that's the meaning anyway).

Furthermore, in this answer to another question, Robert Martin describes exactly a use case where the interactor calls the presenter upon a read request:

Clicking on the map causes either the placePinController to be invoked. It gathers the location of the click, and any other contextual data, constructs a placePinRequest data structure and passes it to the PlacePinInteractor which checks the location of the pin, validates it if necessary, create a Place entity to record the pin, constructs a EditPlaceReponse object and passes it to the EditPlacePresenter which brings up the place editor screen.

To make this play well with MVC, I could think that the application logic that traditionally would go into the controller, here is moved to the interactor, because we don't want any application logic to leak outside the application layer. The controller in the adapters layer would just call the interactor, and maybe do some minor data format conversion in the process:

The software in this layer is a set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the Database or the Web.

from the original article, talking about Interface Adapters.

On the interactor returning data

However, my problem with this approach is that the use case must take care of the presentation itself. Now, I see that the purpose of the Presenter interface is to be abstract enough to represent several different types of presenters (GUI, Web, CLI, etc.), and that it really just means "output", which is something a use case might very well have, but still I'm not totally confident with it.

Now, looking around the Web for applications of the clean architecture, I seem to only find people interpreting the output port as a method returning some DTO. This would be something like:

Repository repository = new Repository();
UseCase useCase = new UseCase(repository);
Data data = useCase.getData();
Presenter presenter = new Presenter();
presenter.present(data);

// I'm omitting the changes to the classes, which are fairly obvious

This is attractive because we're moving the responsibility of "calling" the presentation out of the use case, so the use case doesn't concern itself with knowing what to do with the data anymore, rather just with providing the data. Also, in this case we're still not breaking the dependency rule, because the use case still doesn't know anything about the outer layer.

However, the use case doesn't control the moment when the actual presentation is performed anymore (which may be useful, for example to do additional stuff at that point, like logging, or to abort it altogether if necessary). Also, notice that we lost the Use Case Input Port, because now the controller is only using the getData() method (which is our new output port). Furthermore, it looks to me that we're breaking the "tell, don't ask" principle here, because we're asking the interactor for some data to do something with it, rather than telling it to do the actual thing in the first place.

To the point

So, is any of these two alternatives the "correct" interpretation of the Use Case Output Port according to the Clean Architecture? Are they both viable?

Foi útil?

Solução

The Clean Architecture suggests to let a use case interactor call the actual implementation of the presenter (which is injected, following the DIP) to handle the response/display. However, I see people implementing this architecture, returning the output data from the interactor, and then let the controller (in the adapter layer) decide how to handle it.

That's certainly not Clean, Onion, or Hexagonal Architecture. That is this:

enter image description here

Not that MVC has to be done that way

enter image description here

You can use many different ways to communicate between modules and call it MVC. Telling me something uses MVC doesn't really tell me how the components communicate. That isn't standardized. All it tells me is that there are at least three components focused on their three responsibilities.

Some of those ways have been given different names: enter image description here

And every one of those can justifiably be called MVC.

Anyway, none of those really capture what the buzzword architectures (Clean, Onion, and Hex) are all asking you to do.

enter image description here

Add the data structures being flung around (and flip it upside down for some reason) and you get:

enter image description here

One thing that should be clear here is that the response model does not go marching through the controller.

If you are eagle eye'd, you might have noticed that only the buzzword architectures completely avoid circular dependencies. Importantly, it means the impact of a code change won't spread by cycling through components. The change will stop when it hits code that doesn't care about it.

Wonder if they turned it upside down so that the flow of control would go through clockwise. More on that, and these "white" arrow heads, later.

Is the second solution leaking application responsibilities out of the application layer, in addition to not clearly defining input and output ports to the interactor?

Since communication from Controller to Presenter is meant to go through the application "layer" then yes making the Controller do part of the Presenters job is likely a leak. This is my chief criticism of VIPER architecture.

Why separating these is so important could probably be best understood by studying Command Query Responsibility Segregation.

Input and output ports

Considering the Clean Architecture definition, and especially the little flow diagram describing relationships between a controller, a use case interactor, and a presenter, I'm not sure if I correctly understand what the "Use Case Output Port" should be.

It's the API that you send output through, for this particular use case. It's no more than that. The interactor for this use case doesn't need to know, nor want to know, if output is going to a GUI, a CLI, a log, or an audio speaker. All the interactor needs to know is the very simplest API possible that will let it report the results of it's work.

Clean architecture, like hexagonal architecture, distinguishes between primary ports (methods) and secondary ports (interfaces to be implemented by adapters). Following the communication flow, I expect the "Use Case Input Port" to be a primary port (thus, just a method), and the "Use Case Output Port" an interface to be implemented, perhaps a constructor argument taking the actual adapter, so that the interactor can use it.

The reason the output port is different from the input port is that it must not be OWNED by the layer that it abstracts. That is, the layer that it abstracts must not be allowed to dictate changes to it. Only the application layer and it's author should decide that the output port can change.

This is in contrast to the input port which is owned by the layer it abstracts. Only the application layer author should decide if it's input port should change.

Following these rules preserves the idea that the application layer, or any inner layer, does not know anything at all about the outer layers.


On the interactor calling the presenter

The previous interpretation seems to be confirmed by the aforementioned diagram itself, where the relation between the controller and the input port is represented by a solid arrow with a "sharp" head (UML for "association", meaning "has a", where the controller "has a" use case), while the relation between the presenter and the output port is represented by a solid arrow with a "white" head (UML for "inheritance", which is not the one for "implementation", but probably that's the meaning anyway).

The important thing about that "white" arrow is that it lets you do this:

enter image description here

You can let the flow of control go in the opposite direction of dependency! That means the inner layer doesn't have to know about the outer layer and yet you can dive into the inner layer and come back out!

Doing that has nothing to do with using the "interface" keyword. You could do this with an abstract class. Heck you could do it with a (ick) concrete class so long as it can be extended. It's simply nice to do it with something that focuses only on defining the API that Presenter must implement. The open arrow is only asking for polymorphism. What kind is up to you.

Why reversing the direction of that dependency is so important can be learned by studying the Dependency Inversion Principle. I mapped that principle onto these diagrams here.

On the interactor returning data

However, my problem with this approach is that the use case must take care of the presentation itself. Now, I see that the purpose of the Presenter interface is to be abstract enough to represent several different types of presenters (GUI, Web, CLI, etc.), and that it really just means "output", which is something a use case might very well have, but still I'm not totally confident with it.

No that's really it. The point of making sure the inner layers don't know about the outer layers is that we can remove, replace, or refactor the outer layers confident that doing so wont break anything in the inner layers. What they don't know about won't hurt them. If we can do that we can change the outer ones to whatever we want.

Now, looking around the Web for applications of the clean architecture, I seem to only find people interpreting the output port as a method returning some DTO. This would be something like:

Repository repository = new Repository();
UseCase useCase = new UseCase(repository);
Data data = useCase.getData();
Presenter presenter = new Presenter();
presenter.present(data);
// I'm omitting the changes to the classes, which are fairly obvious

This is attractive because we're moving the responsibility of "calling" the presentation out of the use case, so the use case doesn't concern itself with knowing what to do with the data anymore, rather just with providing the data. Also, in this case we're still not breaking the dependency rule, because the use case still doesn't know anything about the outer layer.

The problem here is now whatever knows how to ask for the data has to also be the thing that accepts the data. Before the Controller could call the Usecase Interactor blissfully unaware of what the Response Model would look like, where it should go, and, heh, how to present it.

Again, please study Command Query Responsibility Segregation to see why that's important.

However, the use case doesn't control the moment when the actual presentation is performed anymore (which may be useful, for example to do additional stuff at that point, like logging, or to abort it altogether if necessary). Also, notice that we lost the Use Case Input Port, because now the controller is only using the getData() method (which is our new output port). Furthermore, it looks to me that we're breaking the "tell, don't ask" principle here, because we're asking the interactor for some data to do something with it, rather than telling it to do the actual thing in the first place.

Yes! Telling, not asking, will help keep this object oriented rather than procedural.

To the point

So, is any of these two alternatives the "correct" interpretation of the Use Case Output Port according to the Clean Architecture? Are they both viable?

Anything that works is viable. But I wouldn't say that the second option you presented faithfully follows Clean Architecture. It might be something that works. But it's not what Clean Architecture asks for.

Outras dicas

In a discussion related to your question, Uncle Bob explains the purpose of the presenter in his Clean Architecture:

Given this code sample:

namespace Some\Controller;

class UserController extends Controller {
    public function registerAction() {
        // Build the Request object
        $request = new RegisterRequest();
        $request->name = $this->getRequest()->get('username');
        $request->pass = $this->getRequest()->get('password');

        // Build the Interactor
        $usecase = new RegisterUser();

        // Execute the Interactors method and retrieve the response
        $response = $usecase->register($request);

        // Pass the result to the view
        $this->render(
            '/user/registration/template.html.twig', 
            array('id' =>  $response->getId()
        );
    }
}

Uncle Bob said this:

"The purpose of the presenter is to decouple the use cases from the format of the UI. In your example, the $response variable is created by the interactor, but is used by the view. This couples the interactor to the view. For example, let's say that one of the fields in the $response object is a date. That field would be a binary date object that could be rendered in many different date formats. The wants a very specific date format, perhaps DD/MM/YYYY. Whose responsibility is it to create the format? If the interactor creates that format, then it knows too much about the View. But if the view takes the binary date object then it knows too much about the interactor.

"The presenter's job is to take the data from the response object and format it for the View. Neither the view nor the interactor know about each other's formats."

--- Uncle Bob

(UPDATE: May 31, 2019)

Given that answer of Uncle Bob, I think it doesn't matter that much whether we do option #1 (let interactor use presenter)...

class UseCase
{
    private Presenter presenter;
    private Repository repository;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.presenter = presenter;
        this.repository = repository;
    }

    public void Execute(Request request)
    {
        ...
        Response response = new Response() {...}
        this.presenter.Show(response);
    }
}

... or we do option #2 (let interactor return response, create a presenter inside the controller, then pass response to presenter)...

class Controller
{
    public void ExecuteUseCase(Data data)
    {
        Request request = ...
        UseCase useCase = new UseCase(repository);
        Response response = useCase.Execute(request);
        Presenter presenter = new Presenter();
        presenter.Show(response);
    }
}

Personally, I prefer option #1 because I want to be able control inside the interactor when to show data and error messages, like this example below:

class UseCase
{
    private Presenter presenter;
    private Repository repository;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.presenter = presenter;
        this.repository = repository;
    }

    public void Execute(Request request)
    {
        if (<invalid request>) 
        {
            this.presenter.ShowError("...");
            return;
        }

        if (<there is another error>) 
        {
            this.presenter.ShowError("another error...");
            return;
        }

        ...
        Response response = new Response() {...}
        this.presenter.Show(response);
    }
}

... I want to be able to do these if/else that are related to presentation inside the interactor and not outside the interactor.

If on the other hand we do option #2, we would have to store the error message(s) in the response object, return that response object from the interactor to the controller, and make the controller parse the response object...

class UseCase
{
    public Response Execute(Request request)
    {
        Response response = new Response();
        if (<invalid request>) 
        {
            response.AddError("...");
        }

        if (<there is another error>) 
        {
            response.AddError("another error...");
        }

        if (response.HasNoErrors)
        {
            response.Whatever = ...
        }

        ...
        return response;
    }
}
class Controller
{
    private UseCase useCase;

    public Controller(UseCase useCase)
    {
        this.useCase = useCase;
    }

    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        Response response = useCase.Execute(request);
        Presenter presenter = new Presenter();
        if (response.ErrorMessages.Count > 0)
        {
            if (response.ErrorMessages.Contains(<invalid request>))
            {
                presenter.ShowError("...");
            }
            else if (response.ErrorMessages.Contains("another error")
            {
                presenter.ShowError("another error...");
            }
        }
        else
        {
            presenter.Show(response);
        }
    }
}

I don't like parsing response data for errors inside the controller because if we do that we are doing redundant work --- if we change something in the interactor, we also have to change something in the controller.

Also, if we later decide to reuse our interactor to present data using the console, for example, we have to remember to copy-paste all those if/else in the controller of our console app.

// in the controller for our console app
if (response.ErrorMessages.Count > 0)
{
    if (response.ErrorMessages.Contains(<invalid request>))
    {
        presenterForConsole.ShowError("...");
    }
    else if (response.ErrorMessages.Contains("another error")
    {
        presenterForConsole.ShowError("another error...");
    }
}
else
{
    presenterForConsole.Present(response);
}

If we use option #1 we will have this if/else only in one place: the interactor.


If you are using ASP.NET MVC (or other similar MVC frameworks), option #2 is the easier way to go.

But we can still do option #1 in that kind of environment. Here is an example of doing option #1 in ASP.NET MVC:

(Notice that we need to have public IActionResult Result in the presenter of our ASP.NET MVC app)

class UseCase
{
    private Repository repository;

    public UseCase(Repository repository)
    {
        this.repository = repository;
    }

    public void Execute(Request request, Presenter presenter)
    {
        if (<invalid request>) 
        {
            this.presenter.ShowError("...");
            return;
        }

        if (<there is another error>) 
        {
            this.presenter.ShowError("another error...");
            return;
        }

        ...
        Response response = new Response() {
            ...
        }
        this.presenter.Show(response);
    }
}
// controller for ASP.NET app

class AspNetController
{
    private UseCase useCase;

    public AspNetController(UseCase useCase)
    {
        this.useCase = useCase;
    }

    [HttpPost("dosomething")]
    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        var presenter = new AspNetPresenter();
        useCase.Execute(request, presenter);
        return presenter.Result;
    }
}
// presenter for ASP.NET app

public class AspNetPresenter
{
    public IActionResult Result { get; private set; }

    public AspNetPresenter(...)
    {
    }

    public async void Show(Response response)
    {
        Result = new OkObjectResult(new { });
    }

    public void ShowError(string errorMessage)
    {
        Result = new BadRequestObjectResult(errorMessage);
    }
}

(Notice that we need to have public IActionResult Result in the presenter of our ASP.NET MVC app)

If we decide to create another app for the console, we can reuse the UseCase above and create just the Controller and Presenter for the console:

// controller for console app

class ConsoleController
{    
    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        var presenter = new ConsolePresenter();
        useCase.Execute(request, presenter);
    }
}
// presenter for console app

public class ConsolePresenter
{
    public ConsolePresenter(...)
    {
    }

    public async void Show(Response response)
    {
        // write response to console
    }

    public void ShowError(string errorMessage)
    {
        Console.WriteLine("Error: " + errorMessage);
    }
}

(Notice that we DO NOT HAVE public IActionResult Result in the presenter of our console app)

Use case containing the presenter or returning data?

So, is any of these two alternatives the "correct" interpretation of the Use Case Output Port according to the Clean Architecture? Are they both viable?


In short

Yes, they are both viable as long as both approaches take into consideration Inversion Of Control between the business layer and the delivery mechanism. With the second approach, we are still able to introduce IOC by making use of observer, mediator few others design patterns...

With his Clean Architecture, Uncle Bob's attempt is to synthesizes a bunch of known architectures to reveal important concepts and components for us to comply widely with OOP principles.

It would be counter productive to consider his UML class diagram (the diagram below) as THE unique Clean Architecture design. This diagram could have been drawn for the sake of concrete examples… However, since it is far less abstract than usual architecture representations he had to make concrete choices among which the interactor output port design which is only an implementation detail

Uncle Bob's UML class diagram of Clean Architecture


My two cents

The main reason why I prefer returning the UseCaseResponse is that this approach keeps my use cases flexible, allowing both composition between them and genericity (generalization and specific generation). A basic example:

// A generic "entity type agnostic" use case encapsulating the interaction logic itself.
class UpdateUseCase implements UpdateUseCaseInterface
{
    function __construct(EntityGatewayInterface $entityGateway, GetUseCaseInterface $getUseCase)
    {
        $this->entityGateway = $entityGateway;
        $this->getUseCase = $getUseCase;
    }

    public function execute(UpdateUseCaseRequestInterface $request) : UpdateUseCaseResponseInterface
    {
        $getUseCaseResponse = $this->getUseCase->execute($request);

        // Update the entity and build the response...

        return $response;
    }
}

// "entity type aware" use cases encapsulating the interaction logic WITH the specific entity type.
final class UpdatePostUseCase extends UpdateUseCase;
final class UpdateProductUseCase extends UpdateUseCase;

Note that it is analogously closer of UML use cases including/extending each other and defined as reusable on different subjects (the entities).


On the interactor returning data

However, the use case doesn't control the moment when the actual presentation is performed anymore (which may be useful, for example to do additional stuff at that point, like logging, or to abort it altogether if necessary).

Not sure to understand what you mean with this, why would you need to "control" the presentation performation? Don't you control it as long as you don't return the use case response?

The use case can return in its response a status code to let know to the client layer what happened exactly during its operation. HTTP response status codes are particularly well suited to describe the operation status of a use case…

There are some good answers here already. As it has been said, Clean Architecture's presenters exist to decouple use cases and views. It's worth noting they are not exactly the same as prescribed in the MVP architecture.

I'd like to add that you can use the option #2 (use case to return data) and still implement presenters as described by Uncle Bob in his Clean Arcbitecture book in the chapter 8: OCP - THE OPEN-CLOSED PRINCIPLE.

enter image description here

A use case can contain either the presenter or returning data, depends on what is required by the application flow.

Let’s understand few terms before understanding different application flows:

  • Domain Object: A domain object is the data container in domain layer on which business logic operations are carried.
  • View Model: Domain Objects are usually mapped to view models in application layer to make them compatible and friendly to user interface.
  • Presenter: While a controller in application layer typically invokes a use case, but it is advisable to delegate the domain to view model mapping logic to separate class (following Single Responsibility Principle), which is called “Presenter”.

A Use Case Containing Returning Data

In a usual case, a use case simply returns a domain object to application layer that can further be processed in application layer to make it friendly to show in UI.

As the controller is responsible to invoke use case, in this case it also contains a reference of the respective presenter to conduct domain to view model mapping before sending it to view to be rendered.

Here is a simplified code sample:

namespace SimpleCleanArchitecture
{
    public class OutputDTO
    {
        //fields
    }

    public class Presenter 
    {
        public OutputDTO Present(Domain domain)
        {
            // Mapping takes action. Dummy object returned for demonstration purpose
            // Usually frameworks like automapper to the mapping job.
            return new OutputDTO();
        }
    }

    public class Domain
    {
        //fields
    }

    public class UseCaseInteractor
    {
        public Domain Process(Domain domain)
        {
            // additional processing takes place here
            return domain;
        }
    }

    // A simple controller. 
    // Usually frameworks like asp.net mvc provides url routing mechanism to reach here through this type of class.
    public class Controller
    {
        public View Action()
        {
            UseCaseInteractor userCase = new UseCaseInteractor();
            var domain = userCase.Process(new Domain());//passing dummy domain(for demonstration purpose) to process
            var presenter = new Presenter();//presenter might be initiated via dependency injection.

            return new View(presenter.Present(domain));
        }
    }

    // A simple view. 
    // Usually frameworks like asp.net mvc provides mechanism to render html based view through this type of class.
    public class View
    {
        OutputDTO _outputDTO;

        public View(OutputDTO outputDTO)
        {
            _outputDTO = outputDTO;
        }

    }
}

A Use Case Containing Presenter

While not common, but it is possible that the use case may need to call the presenter. In that case instead of holding the concrete reference of the presenter, it is advisable to consider an interface (or abstract class) as the reference point (which should be initialized in run time via dependency injection).

Having the domain to view model mapping logic in a separate class (instead of inside the controller) also breaks the circular dependency between controller and use case (when reference to the mapping logic is required by the use case class).

enter image description here

Below is simplified implementation of the control flow as illustrated in the original article, that demonstrates how it can be done. Please note that unlike shown in the diagram, for the sake of simplicity UseCaseInteractor is a concrete class.

namespace CleanArchitectureWithPresenterInUseCase
{
    public class Domain
    {
        //fields
    }

    public class OutputDTO
    {
        //fields
    }

    // Use Case Output Port
    public interface IPresenter
    {
        OutputDTO Present(Domain domain);
    }

    public class Presenter: IPresenter
    {
        public OutputDTO Present(Domain domain)
        {
            // Mapping takes action. Dummy object returned for demonstration purpose
            // Usually frameworks like automapper to the mapping job.
            return new OutputDTO();
        }
    }

    // Use Case Input Port / Interactor   
    public class UseCaseInteractor
    {
        IPresenter _presenter;
        public UseCaseInteractor (IPresenter presenter)
        {
            _presenter = presenter;
        }

        public OutputDTO Process(Domain domain)
        {
            return _presenter.Present(domain);
        }
    }

    // A simple controller. 
    // Usually frameworks like asp.net mvc provides url routing mechanism to reach here through this type of class.
    public class Controller
    {
        public View Action()
        {
            IPresenter presenter = new Presenter();//presenter might be initiated via dependency injection.
            UseCaseInteractor userCase = new UseCaseInteractor(presenter);
            var outputDTO = userCase.Process(new Domain());//passing dummy domain (for demonstration purpose) to process
            return new View(outputDTO);
        }
    }

    // A simple view. 
    // Usually frameworks like asp.net mvc provides mechanism to render html based view through this type of class.
    public class View
    {
        OutputDTO _outputDTO;

        public View(OutputDTO outputDTO)
        {
            _outputDTO = outputDTO;
        }

    }
}

Even though I generally agree with the answer from @CandiedOrange, I would also see benefit in the approach where the interactor just retruns data which is then passed by the controller to the presenter.

This for example is a simple way to use the ideas of the Clean Architecture (Dependency Rule) in the context of Asp.Net MVC.

I have written a blog post to dive deeper into this discussion: https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/

The primary reason to use a presenter is single responsibility/separation of concerns. The situation with web APIs is a little murky as modern frameworks will do content negotiation and take care of the wire format (say JSON vs XML) for you.

I'm strongly in favor of the use case calling the presenter directly, as this means the use case response model is "not traipsing through the controller" as stated above. However, the approach where the controller plays traffic cop with the presenter and yanks state out of the presenter, etc, is awkward.

If you make the presenter a delegate, you can do something that looks a little cleaner, but now you've lost the content negotiation provided by the framework, at least with this demo code. I suspect there's more you can do with extending OkResult directly perhaps, and tapping back in to the content negotiation.

[HttpGet]
public IActionResult List()
{
    return new GridEntriesPresenter(presenter =>
       _listGridEntriesUseCase.ListAsync(presenter));
}

Then GridEntriesPresenter is then something that extends

public class ActionResultPresenter<T> : IActionResult
{
    private readonly Func<Func<T, Task>, Task> _handler;

    public ActionResultPresenter(Func<Func<T, Task>, Task> handler)
    {
        _handler = handler;
    }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        await _handler(async responseModel =>
        {
            context.HttpContext.Response.ContentType = "application/json";
            context.HttpContext.Response.StatusCode = 200;
            await context.HttpContext.Response.StartAsync();

            await SerializeAsync(context.HttpContext.Response.Body, responseModel);

            await context.HttpContext.Response.CompleteAsync();
        });
    }

    ... 
}
public class GridEntriesPresenter : ActionResultPresenter<IEnumerable<GridEntryResponseModel>>
{
    public GridEntriesPresenter(Func<Func<IEnumerable<GridEntryResponseModel>, Task>, Task> handler) : base(handler)
    {
    }

    protected override Task SerializeAsync(Stream stream, IEnumerable<GridEntryResponseModel> responseModel)
    {
        ...
        return SerializeJsonAsync(stream, new {items, allItems, totalCount, pageCount, page, pageSize});
    }
}

And your use case looks like this:

public class ListGridEntriesUseCase : IListGridEntriesUseCase
{
    private readonly IActivityRollups _activityRollups;

    public ListGridEntriesUseCase(IActivityRollups activityRollups)
    {
        _activityRollups = activityRollups;
    }

    public async Task ListAsync(int skip, int take, Func<IEnumerable<GridEntryResponseModel>, Task> presentAsync)
    {
        var activityRollups = await _activityRollups.ListAsync(skip, take);
        var gridEntries = activityRollups.Select(x => new GridEntryResponseModel
        {
            ...
        });
        await presentAsync(gridEntries);
    }
}

But now you're using the awkward Func<T> syntax (but IDE support will help here, at least if you're using Rider), and your controller only looks clean because it's not explicitly declaring types, which is perhaps cheating.

Licenciado em: CC-BY-SA com atribuição
scroll top