Jinish Jinish - 16 days ago 9
C# Question

CQRS and WebAPI Design

I have recently been looking into CQRS along side Web API. I understand the separation between read and write i.e. query and command. The question that I have is, that my whether Web Api actions, for example [HttpGet] should expect a Query parameter encapsulating properties like (SortParam, Page, PageSize etc...) or should/could I still have these parameters exposed individually and then create a Query object and pass it along the handler? So essentially how should my action look like:

public IHttpActionResult Get(Query query)
{
try
{
var result = _queryDispatcher.Dispatch<Query, QueryResult>(query);
return Ok(result);
}
catch (Exception)
{
return InternalServerError();
}
}


or is it ok if it looks like:

public IHttpActionResult Get(string sortBy = "id", int page = 1, int pageSize = maxPageSize)
{
try
{
var query = new Query { SortParam = sortby, Page = page, PageSize = pageSize };
var result = _queryDispatcher.Dispatch<Query, QueryResult>(query);
return Ok(result);
}
catch (Exception)
{
return InternalServerError();
}
}

Answer

It's a matter of opinion. That said, I however believe that it is totally fine to

keep these parameters exposed individually and then create a Query object and pass it along the handler.

The framework allows for both. For the first one use the [FromUri] parameter attribute to build the complex object form the query string.

[HttpGet]
public IHttpActionResult Get([FromUri]Query query) {
    var result = _queryDispatcher.Dispatch<Query, QueryResult>(query);
    return Ok(result);
}

Or just go with the parameters exposed.

[HttpGet]
public IHttpActionResult Get(string sortBy = "id", int page = 1, int pageSize = maxPageSize) {
    var query = new Query { SortParam = sortby, Page = page, PageSize = pageSize };
    var result = _queryDispatcher.Dispatch<Query, QueryResult>(query);
    return Ok(result);
}

They both result in the same functionality.

The first one however allows for easier maintainability because if any new properties are added there it no need to change the action as the framework will bind the model based on provided parameters.

Also if the goal is to keep the controller lean then do not handle the error in the action but rather apply cross-cutting concerns and have it handled by an exception filter