From my understanding of CQS you would create a set a DTOs that fulfill the requirements of the user interface screens or applications that may need to consume them.
Where this exists in the project is based on the requirements as it would depend if you were going to expose these Dtos via web services.
In which case I wouldn't put it in the Web Layer but rather in the Application layer or a dedicated Facade layer.
Then you would have a read only repository or data access layer which populates the DTOs directly. I think that the Query side of things should be optimized for read performance in which case direct queries/stored procs on database views or tables and SqlDataReaders would do the best job here. But it would definetly be worth abstracting this access behind an interface so you can add a cached implementation later down the track.
If you're using an ORM and want to map from your Domain Entities to the Dtos then you could have a generic QueryRepository which has methods which take an ISpecification or similar construct for defining your queries then a DtoAssembler object for creating the Dtos from your Domain objects.
Then have an implementation has a first class object for each of the queries you are going to perform.
Here's a fairly contrived example but I hope it gives you an idea.
public interface ISpecification<T>
{
Expression<Func<T, bool>> Predicate { get; }
}
public class ActiveCustomersSpecification : ISpecification<Customer>
{
private Expression<Func<Customer, bool>> predicate;
public ActiveCustomersSpecification()
{
predicate = c => c.IsActive;
}
#region ISpecicfication<Customer> Members
public Expression<Func<Customer, bool>> Predicate
{
get { return predicate; }
}
#endregion
}
public interface IQueryRepository<T>
{
IQueryable<T> GetQuery(ISpecification<T> specification);
IEnumerable<T> FindAllBy(ISpecification<T> specification);
}
public class CustomerDtoAssembler
{
public CustomerDto AssembleFrom(Customer customer)
{
var customerDto = new CustomerDto
{
Id = customer.Id
};
return customerDto;
}
}