Search code examples
c#apiodataasp.net-core-2.0asp.net-core-webapi

ASP.NET Core API oData and API layer model


I need to use OData for my API endpoints in ASP.NET Core application, but all examples are about working directly with Data Model classes. In my application architecture I has service layer, methods of this service return DTO classes and then map to API view classes.

My data class (infrastructure layer):

public partial class Carrier : BaseEntity
{
    public string Name { get; set; }
    public string Code { get; set; }
    public string UsDotNumber { get; set; }
    public string McNumber { get; set; }

My DTO class:

public class CarrierBaseDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public string Fein { get; set; }
    public string McNumber { get; set; }

My presentation (API) class:

public class CarrierAPI
{
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }
    [JsonProperty(PropertyName = "code")]
    public string Code { get; set; }
    [JsonProperty(PropertyName = "fein")]
    public string Fein { get; set; }
    [JsonProperty(PropertyName = "mcNumber")]
    public string McNumber { get; set; }

my service method:

    public List<CarrierBaseDto> SearchCarriersDto()
    {
        var query = _context.Carriers
            .Where(c => !c.Deleted);

        IQueryable<CarrierBaseDto> queryDto = query.ProjectTo<CarrierBaseDto>(_mapperConfig);
        return queryDto.ToList();
    }

My controller method:

    [HttpGet]
    [Route("GetAll")]
    public IActionResult GetAll()
    {
        var carriers = _carrierService.SearchCarriersDto();
        var carriersApi = _mapper.Map<List<CarrierElementAPI>>(carriers);
        return new OkObjectResult(carriersApi);
    }

I want to add abilities to use $orderBy, $filter, $fields params. How to add it to my current architecture?


Solution

  • I think it was when they originally designed OData it was not intended to be used without DDD, because the metadata was suppose to allow you to handle the filter etc, which is now creating somewhat of a limitation on using it.

    There's some hacky workarounds but they only partially work. The closest thing that I can think of that you can do is generically take in query options and apply them, Then use automapper to project to your queryable,

    The only issue is the mappings from Entity to DTO in your automapper setup cannot be complex and must be setup through expression mapping

    public Object[] Get(ODataQueryOptions<ProductDTO> options)
    {
        ODataQuerySettings settings = new ODataQuerySettings()
        {
            PageSize = 5
        };
    
        IQueryable results = options.ApplyTo(_products.AsQueryable().ProjectTo<ProductDTO>(), settings);
    
        results.ToArray()
    }