C# 沉积的, IRepository shoppingListEntryRepository) { _shoppingListRepository=shoppingListRepository; _shoppingListEntryRepository=shoppingListEntryRepository; } 公共IOutputDataModel GetUserShoppingList(GetUserShoppingListsInput模型) { 购物清单= _shoppingListRepository.Get(q=>q.Filter(sl=>sl.OwnerId==model.InitiatorId)。包括(sl=>sl.Entries)); return SuccessOutput(新的ListModel(Mapper.Map(shoppingLists)); } 公共IOutputDataModel GetShoppingList(GetShoppingListInput模型) { var购物清单= _shoppingListRepository .Get(q=>q.Filter(sl=>sl.Id==model.ShoppingListId)。Include(sl=>sl.Entries)。Take(1)) .SingleOrDefault(); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); 返回 SuccessOutput(新的GetShoppingListOutputData(Mapper.Map(shoppingList)), Map(shoppingList.Entries)); } 公共IOutputModel DeleteShoppingList(DeleteShoppingListInput模型) { var shoppingList=\u shoppingListRepository.Get(model.ShoppingListId); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); _shoppingListRepository.Delete(shoppingList); 返回SuccessOutput(); } 公共IOutputModel DeleteShoppingListEntry(DeleteShoppingListEntryInput模型) { 风险值分录= _shoppingListEntryRepository。获取( q=>q.Filter(e=>e.Id==model.ShoppingListEntryId)。包括(e=>e.ShoppingList)。取(1)) .SingleOrDefault(); if(条目==null) 返回输出(OperationResult.NotFound); if(entry.ShoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); if(entry.ShoppingListId!=model.ShoppingListId) 返回输出(OperationResult.BadRequest); _shoppingListEntryRepository.Delete(条目); 返回SuccessOutput(); } 公共IOutputModel ClearHoppingListEntries(ClearHoppingListEntries输入模型) { var购物清单= _shoppingListRepository.Get( q=>q.Filter(sl=>sl.Id==model.ShoppingListId)。包括(sl=>sl.Entries)。取(1)) .SingleOrDefault(); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); if(shoppingList.Entries!=null) _shoppingListEntryRepository.Delete(shoppingList.Entries.ToList()); 返回SuccessOutput(); } 私有IOutputDataModel CreateShoppingList(SaveShoppingListInput模型) { var shoppingList=新shoppingList { OwnerId=model.InitiatorId, Title=model.ShoppingListTitle, Entries=model.Entries.Select(Mapper.Map).ForEach(sle=>sle.Id=0).ToList() }; shoppingList=\u shoppingListRepository.Save(shoppingList); 返回输出(OperationResult.Created,shoppingList.Id); } }

C# 沉积的, IRepository shoppingListEntryRepository) { _shoppingListRepository=shoppingListRepository; _shoppingListEntryRepository=shoppingListEntryRepository; } 公共IOutputDataModel GetUserShoppingList(GetUserShoppingListsInput模型) { 购物清单= _shoppingListRepository.Get(q=>q.Filter(sl=>sl.OwnerId==model.InitiatorId)。包括(sl=>sl.Entries)); return SuccessOutput(新的ListModel(Mapper.Map(shoppingLists)); } 公共IOutputDataModel GetShoppingList(GetShoppingListInput模型) { var购物清单= _shoppingListRepository .Get(q=>q.Filter(sl=>sl.Id==model.ShoppingListId)。Include(sl=>sl.Entries)。Take(1)) .SingleOrDefault(); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); 返回 SuccessOutput(新的GetShoppingListOutputData(Mapper.Map(shoppingList)), Map(shoppingList.Entries)); } 公共IOutputModel DeleteShoppingList(DeleteShoppingListInput模型) { var shoppingList=\u shoppingListRepository.Get(model.ShoppingListId); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); _shoppingListRepository.Delete(shoppingList); 返回SuccessOutput(); } 公共IOutputModel DeleteShoppingListEntry(DeleteShoppingListEntryInput模型) { 风险值分录= _shoppingListEntryRepository。获取( q=>q.Filter(e=>e.Id==model.ShoppingListEntryId)。包括(e=>e.ShoppingList)。取(1)) .SingleOrDefault(); if(条目==null) 返回输出(OperationResult.NotFound); if(entry.ShoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); if(entry.ShoppingListId!=model.ShoppingListId) 返回输出(OperationResult.BadRequest); _shoppingListEntryRepository.Delete(条目); 返回SuccessOutput(); } 公共IOutputModel ClearHoppingListEntries(ClearHoppingListEntries输入模型) { var购物清单= _shoppingListRepository.Get( q=>q.Filter(sl=>sl.Id==model.ShoppingListId)。包括(sl=>sl.Entries)。取(1)) .SingleOrDefault(); if(shoppingList==null) 返回输出(OperationResult.NotFound); if(shoppingList.OwnerId!=model.InitiatorId) 返回输出(OperationResult.AccessDenied); if(shoppingList.Entries!=null) _shoppingListEntryRepository.Delete(shoppingList.Entries.ToList()); 返回SuccessOutput(); } 私有IOutputDataModel CreateShoppingList(SaveShoppingListInput模型) { var shoppingList=新shoppingList { OwnerId=model.InitiatorId, Title=model.ShoppingListTitle, Entries=model.Entries.Select(Mapper.Map).ForEach(sle=>sle.Id=0).ToList() }; shoppingList=\u shoppingListRepository.Save(shoppingList); 返回输出(OperationResult.Created,shoppingList.Id); } },c#,linq,asp.net-web-api,refactoring,C#,Linq,Asp.net Web Api,Refactoring,现在,所有创建DTO、响应和其他非业务逻辑操作的例程都在基类中,我们可以以一种简单明了的方式添加特性。对于新实体,创建新的“服务”(将以通用方式自动创建存储库)并从服务库继承它。对于新操作,向API中的现有“服务”和操作添加一个方法。仅此而已 这只是一个与问题无关的建议,但对于我来说,用自动生成的方法检查路线是非常有用的。我还用于从帮助页面执行web api查询 我的结果: 独立于平台且可测试的业务逻辑层 以通用方式将业务逻辑结果映射到基类中的HttpResponseMessage 具有Act

现在,所有创建DTO、响应和其他非业务逻辑操作的例程都在基类中,我们可以以一种简单明了的方式添加特性。对于新实体,创建新的“服务”(将以通用方式自动创建存储库)并从服务库继承它。对于新操作,向API中的现有“服务”和操作添加一个方法。仅此而已

  • 这只是一个与问题无关的建议,但对于我来说,用自动生成的方法检查路线是非常有用的。我还用于从帮助页面执行web api查询

  • 我的结果:

    • 独立于平台且可测试的业务逻辑层
    • 以通用方式将业务逻辑结果映射到基类中的
      HttpResponseMessage
    • 具有
      ActionFilterAttribute
      的半自动安全性
    • “空”控制器
    • 可读代码(代码约定和模型层次结构)
    我建议和你一起去。在国际海事组织,你有一篇关于它的优秀文章。这应该是最简单的重构之一

    按照上述文章中的指导原则,您可以重构代码,如下所示:

    • 创建基本存储库接口

      public interface IRepository<TEntity, in TKey> where TEntity : class
      {
          TEntity Get(TKey id);
      
          void Save(TEntity entity);
      
          void Delete(TEntity entity);
      }
      

    这应该接近结果代码(显然有些东西可能需要更改)。如果有任何不清楚的地方,请告诉我。

    使用单独的数据访问层。我假设GetDrone(int Id)将检索一个或没有drone,并使用SingleOrDefault()。您可以根据需要进行调整

    //move all the db access stuff here
    public class Db
    {
        //assuming single drone is returned
        public Drone GetDrone(int id)
        {   
            //do SingleOrDefault or Where depending on the needs
            Drone drone = GetDrones().SingleOrDefault(drones => drones.iddrones == id);         
            return drone;
        }
    
        public IQueryable<Drone> GetDrones()
        {
            var drone = db.drones.Select(d => new DroneDTO
            {
                iddrones = d.iddrones,
                //more stuff
            });
            return drone;
        }
    }
    
  • DB调用应该位于web api的一个单独的层中(原因:关注点分离:您可能希望将来更改DB技术,并且您的web api可能希望从其他来源获取数据)
  • 使用工厂制造无人机。如果您使用的是依赖项注入,那么可以将其注入web api控制器。如果这个工厂很简单(不受其他工厂的依赖),你可以让它成为静态的,但要小心:你不想有很多相互依赖的静态工厂,因为一旦一个工厂不再是静态的,你就必须改变它们

    public class APIController : ApiController
    {
        private readonly IDroneService _droneService;
    
        public APIController(IDroneService droneService)
        {
            _droneService = droneService;
        }
    
        [HttpGet]
        [Route("api/drones")]
        public HttpResponseMessage GetDrones()
        {
            var drones = _droneService
                .GetDrones()
                .Select(DroneDTOFactory.Build);
    
            return Request.CreateResponse(HttpStatusCode.OK, drones);
        }
    
        [HttpGet]
        [Route("api/drones/{id}")]
        public HttpResponseMessage GetDrones(int id)
        {
            // I am assuming you meant to get a single drone here
            var drone = DroneDTOFactory.Build(_droneService.GetDrone(id));
    
            return Request.CreateResponse(HttpStatusCode.OK, drone);
        }
    }
    
    public static class DroneDTOFactory
    {
        public static DroneDTO Build(Drone d)
        {
            if (d == null)
                return null;
    
            return new DroneDTO
            {
                iddrones = d.iddrones,
                //more stuff
            };
        }
    }
    

  • 你有什么问题?我可能解释得不够。对于第二个端点
    api/drones/{id}
    ,我将复制粘贴第一个端点的完全相同的选择代码,并将
    追加到其中(drones=>drones.iddrones==id)到它。我的
    Select
    很大。如果我必须做出改变,我必须确保我没有错过考试
    db.Drones
      .Where(d => ... condition ...)
      .Project()
      .To<DroneDto>()
      .ToList();
    
    public class DroneDto
    {
        public int iddrones {get;set;}
    
        public static DroneDto CreateFromEntity(DroneEntity dbEntity)
        {
            return new DroneDto
            {
                iddrones = dbEntity.iddrones,
                ...
            };
        }
    }
    
    public class APIController : ApiController
    {
        [HttpGet]
        [Route("api/drones")]
        public HttpResponseMessage getDrones()
        {
            var drones = db.drones.ToList().Select(d => DroneDto.CreateFromEntity(d));
    
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drones);
            return res;
        }
    
        [HttpGet]
        [Route("api/drones/{id}")]
        public HttpResponseMessage getDrones(int id)
        {
            var drone = db.drones.Where(d => d.iddrone == id)
                        .ToList().Select(d => DroneDto.CreateFromEntity(d));                                      
    
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drone);
            return res;
        }
    }
    
        public class DroneDTO
        {
            public int Id { get; set; }
            public static IEnumerable<DroneDTO> CreateFromQuery(IQueryable<Drone> query)
            {
                return query.Select(r=> new DroneDTO
                {
                    Id = r.Id
                });
            }
        }
    
    
        public class APIController : ApiController
        {
            [HttpGet]
            [Route("api/drones")]
            public HttpResponseMessage getDrones()
            {
                var drones = DroneDTO.CreateFromQuery(db.drones);
    
                HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drones);
                return res;
            }
    
            [HttpGet]
            [Route("api/drones/{id}")]
            public HttpResponseMessage getDrones(int id)
            {
                var drone = DroneDTO.CreateFromQuery(db.drones.Where(d => d.iddrone == id));
    
                HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drone);
                return res;
            }
        }
    
    public static IQueryable<TResult> Select<TSource, TResult>(
        this IQueryable<TSource> source,
        Expression<Func<TSource, TResult>> selector
    )
    
    public class APIController : ApiController
    {
        static Expression<Func<Drone, DroneDto>> ToDto()
        {
            // The code that was inside Select(...)
            return d => new DroneDTO
            {
                iddrones = d.iddrones,
                //more stuff
            }; 
        }
    
        [HttpGet]
        [Route("api/drones")]
        public HttpResponseMessage getDrones()
        {
            var drones = db.drones.Select(ToDto());
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drones);
            return res;
        }
    
        [HttpGet]
        [Route("api/drones/{id}")]
        public HttpResponseMessage getDrones(int id)
        {
            var drone = db.drones.Where(d => d.iddrones == id).Select(ToDto());
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drone);
            return res;
        }
    }
    
    public class OutputModel
    {
        [JsonIgnore]
        public OperationResult Result { get; private set; }
    
        public OutputDataModel(OperationResult result)
        {
            Result = result;
        }
    
        #region Initializatiors
    
        public static OutputModel CreateResult(OperationResult result)
        {
            return new OutputModel(result);
        }
    
        public static OutputModel CreateSuccessResult()
        {
            return new OutputModel(OperationResult.Success);
        }
    
        #endregion Initializatiors
    }
    
    public class OutputDataModel<TData> : OutputModel
    {
        public TData Data { get; private set; }
    
        public OutputDataModel(OperationResult result)
            : base(result)
        {
        }
    
        public OutputDataModel(OperationResult result, TData data)
            : this(result)
        {
            Data = data;
        }
    
        #region Initializatiors
    
        public static OutputDataModel<TData> CreateSuccessResult(TData data)
        {
            return new OutputDataModel<TData>(OperationResult.Success, data);
        }
    
        public static OutputDataModel<TData> CreateResult(OperationResult result, TData data)
        {
            return new OutputDataModel<TData>(result, data);
        }
    
        public new static OutputDataModel<TData> CreateResult(OperationResult result)
        {
            return new OutputDataModel<TData>(result);
        }
    
        #endregion Initializatiors
    }
    
    public enum OperationResult 
    {
        AccessDenied,
        BadRequest,
        Conflict,
        NotFound,
        NotModified,
        AccessDenied,
        Created,
        Success        
    }
    
    public class RikropApiControllerBase : ApiController
    {
        #region Result handling
    
        protected HttpResponseMessage Response(IOutputModel result, HttpStatusCode successStatusCode = HttpStatusCode.OK)
        {
            switch (result.Result)
            {
                case OperationResult.AccessDenied:
                    return Request.CreateResponse(HttpStatusCode.Forbidden);
                case OperationResult.BadRequest:
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                case OperationResult.Conflict:
                    return Request.CreateResponse(HttpStatusCode.Conflict);
                case OperationResult.NotFound:
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                case OperationResult.NotModified:
                    return Request.CreateResponse(HttpStatusCode.NotModified);
                case OperationResult.Created:
                    return Request.CreateResponse(HttpStatusCode.Created);
                case OperationResult.Success:
                    return Request.CreateResponse(successStatusCode);
                default:
                    return Request.CreateResponse(HttpStatusCode.NotImplemented);
            }
        }
    
        protected HttpResponseMessage Response<TData>(IOutputDataModel<TData> result, HttpStatusCode successStatusCode = HttpStatusCode.OK)
        {
            switch (result.Result)
            {
                case OperationResult.AccessDenied:
                    return Request.CreateResponse(HttpStatusCode.Forbidden);
                case OperationResult.BadRequest:
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                case OperationResult.Conflict:
                    return Request.CreateResponse(HttpStatusCode.Conflict);
                case OperationResult.NotFound:
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                case OperationResult.NotModified:
                    return Request.CreateResponse(HttpStatusCode.NotModified, result.Data);
                case OperationResult.Created:
                    return Request.CreateResponse(HttpStatusCode.Created, result.Data);
                case OperationResult.Success:
                    return Request.CreateResponse(successStatusCode, result.Data);
                default:
                    return Request.CreateResponse(HttpStatusCode.NotImplemented);
            }
        }
    
        #endregion Result handling
    }
    
    [RoutePrefix("api/ShoppingList/{shoppingListId:int}/ShoppingListEntry")]
    public class ShoppingListEntryController : RikropApiControllerBase
    {
        private readonly IShoppingListService _shoppingListService;
    
        public ShoppingListEntryController(IShoppingListService shoppingListService)
        {
            _shoppingListService = shoppingListService;
        }
    
        [Route("")]
        [HttpPost]
        public HttpResponseMessage AddNewEntry(int shoppingListId, SaveShoppingListEntryInput model)
        {
            model.ShoppingListId = shoppingListId;
            var result = _shoppingListService.SaveShoppingListEntry(model);
    
            return Response(result);
        }
    
        [Route("")]
        [HttpDelete]
        public HttpResponseMessage ClearShoppingList(int shoppingListId)
        {
            var model = new ClearShoppingListEntriesInput {ShoppingListId = shoppingListId, InitiatorId = this.GetCurrentUserId()};
            var result = _shoppingListService.ClearShoppingListEntries(model);
    
            return Response(result);
        }
    
        [Route("{shoppingListEntryId:int}")]
        public HttpResponseMessage Put(int shoppingListId, int shoppingListEntryId, SaveShoppingListEntryInput model)
        {
            model.ShoppingListId = shoppingListId;
            model.ShoppingListEntryId = shoppingListEntryId;
    
            var result = _shoppingListService.SaveShoppingListEntry(model);
    
            return Response(result);
        }
    
        [Route("{shoppingListEntry:int}")]
        public HttpResponseMessage Delete(int shoppingListId, int shoppingListEntry)
        {
            var model = new DeleteShoppingListEntryInput 
            {
                ShoppingListId = shoppingListId, 
                ShoppingListEntryId = shoppingListEntry,
                InitiatorId = this.GetCurrentUserId()
            };
            var result = _shoppingListService.DeleteShoppingListEntry(model);
    
            return Response(result);
        }
    }
    
    public class ServiceBase
    {
        #region Output parameters
    
        public IOutputDataModel<TData> SuccessOutput<TData>(TData data)
        {
            return OutputDataModel<TData>.CreateSuccessResult(data);
        }
    
        public IOutputDataModel<TData> Output<TData>(OperationResult result, TData data)
        {
            return OutputDataModel<TData>.CreateResult(result, data);
        }
    
        public IOutputDataModel<TData> Output<TData>(OperationResult result)
        {
            return OutputDataModel<TData>.CreateResult(result);
        }
    
        public IOutputModel SuccessOutput()
        {
            return OutputModel.CreateSuccessResult();
        }
    
        public IOutputModel Output(OperationResult result)
        {
            return OutputModel.CreateResult(result);
        }
    
        #endregion Output parameters
    }
    
    public class ShoppingListService : ServiceBase, IShoppingListService
    {
        private readonly IRepository<ShoppingList, int> _shoppingListRepository;
        private readonly IRepository<ShoppingListEntry, int> _shoppingListEntryRepository;
    
        public ShoppingListService(IRepository<ShoppingList, int> shoppingListRepository,
            IRepository<ShoppingListEntry, int> shoppingListEntryRepository)
        {
            _shoppingListRepository = shoppingListRepository;
            _shoppingListEntryRepository = shoppingListEntryRepository;
        }
    
        public IOutputDataModel<ListModel<ShoppingListDto>> GetUserShoppingLists(GetUserShoppingListsInput model)
        {
            var shoppingLists =
                _shoppingListRepository.Get(q => q.Filter(sl => sl.OwnerId == model.InitiatorId).Include(sl => sl.Entries));
    
            return SuccessOutput(new ListModel<ShoppingListDto>(Mapper.Map<IEnumerable<ShoppingList>, ShoppingListDto[]>(shoppingLists)));
        }
    
        public IOutputDataModel<GetShoppingListOutputData> GetShoppingList(GetShoppingListInput model)
        {
            var shoppingList =
                _shoppingListRepository
                    .Get(q => q.Filter(sl => sl.Id == model.ShoppingListId).Include(sl => sl.Entries).Take(1))
                    .SingleOrDefault();
    
            if (shoppingList == null)
                return Output<GetShoppingListOutputData>(OperationResult.NotFound);
    
            if (shoppingList.OwnerId != model.InitiatorId)
                return Output<GetShoppingListOutputData>(OperationResult.AccessDenied);
    
            return
                SuccessOutput(new GetShoppingListOutputData(Mapper.Map<ShoppingListDto>(shoppingList),
                    Mapper.Map<IEnumerable<ShoppingListEntry>, List<ShoppingListEntryDto>>(shoppingList.Entries)));
        }
    
        public IOutputModel DeleteShoppingList(DeleteShoppingListInput model)
        {
            var shoppingList = _shoppingListRepository.Get(model.ShoppingListId);
    
            if (shoppingList == null)
                return Output(OperationResult.NotFound);
    
            if (shoppingList.OwnerId != model.InitiatorId)
                return Output(OperationResult.AccessDenied);
    
            _shoppingListRepository.Delete(shoppingList);
    
            return SuccessOutput();
        }
    
        public IOutputModel DeleteShoppingListEntry(DeleteShoppingListEntryInput model)
        {
            var entry =
                _shoppingListEntryRepository.Get(
                    q => q.Filter(e => e.Id == model.ShoppingListEntryId).Include(e => e.ShoppingList).Take(1))
                    .SingleOrDefault();
    
            if (entry == null)
                return Output(OperationResult.NotFound);
    
            if (entry.ShoppingList.OwnerId != model.InitiatorId)
                return Output(OperationResult.AccessDenied);
    
            if (entry.ShoppingListId != model.ShoppingListId)
                return Output(OperationResult.BadRequest);
    
            _shoppingListEntryRepository.Delete(entry);
            return SuccessOutput();
        }
    
        public IOutputModel ClearShoppingListEntries(ClearShoppingListEntriesInput model)
        {
            var shoppingList =
                _shoppingListRepository.Get(
                    q => q.Filter(sl => sl.Id == model.ShoppingListId).Include(sl => sl.Entries).Take(1))
                    .SingleOrDefault();
    
            if (shoppingList == null)
                return Output(OperationResult.NotFound);
    
            if (shoppingList.OwnerId != model.InitiatorId)
                return Output(OperationResult.AccessDenied);
    
            if (shoppingList.Entries != null)
                _shoppingListEntryRepository.Delete(shoppingList.Entries.ToList());
    
            return SuccessOutput();
        }
    
        private IOutputDataModel<int> CreateShoppingList(SaveShoppingListInput model)
        {
            var shoppingList = new ShoppingList
            {
                OwnerId = model.InitiatorId,
                Title = model.ShoppingListTitle,
                Entries = model.Entries.Select(Mapper.Map<ShoppingListEntry>).ForEach(sle => sle.Id = 0).ToList()
            };
    
            shoppingList = _shoppingListRepository.Save(shoppingList);
    
            return Output(OperationResult.Created, shoppingList.Id);
        }
    }
    
    public interface IRepository<TEntity, in TKey> where TEntity : class
    {
        TEntity Get(TKey id);
    
        void Save(TEntity entity);
    
        void Delete(TEntity entity);
    }
    
    public interface IDroneDTORepository : IRepository<DroneDTO, int>
    {
        IEnumerable<DroneDTO> FindAll();
    
        IEnumerable<DroneDTO> Find(int id);
    }
    
    public class DroneDTORepository : IDroneDTORepository
    {
        private readonly DbContext _dbContext;
    
        public DroneDTORepository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
    
        public DroneDTO Get(int id)
        {
            return _dbContext.DroneDTOs.FirstOrDefault(x => x.Id == id);
        }
    
        public void Save(DroneDTO entity)
        {
            _dbContext.DroneDTOs.Attach(entity);
        }
    
        public void Delete(DroneDTO entity)
        {
            _dbContext.DroneDTOs.Remove(entity);
        }
    
        public IEnumerable<DroneDTO> FindAll()
        {
            return _dbContext.DroneDTOs
                .Select(d => new DroneDTO
                {
                    iddrones = d.iddrones,
                    //more stuff
                })
                .ToList();
        }
    
        public IEnumerable<DroneDTO> Find(int id)
        {
            return FindAll().Where(x => x.iddrones == id).ToList();
        }
    }
    
    private IDroneDTORepository _repository = new DroneDTORepository(dbContext);
    
    [HttpGet]
    [Route("api/drones")]
    public HttpResponseMessage getDrones()
    {
        var drones = _repository.FindAll();
        HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drones);
        return res;
    }
    
    [HttpGet]
    [Route("api/drones/{id}")]
    public HttpResponseMessage getDrones(int id)
    {
        var drone = _repository.Find(id);
        HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drone);
        return res;
    }
    
    //move all the db access stuff here
    public class Db
    {
        //assuming single drone is returned
        public Drone GetDrone(int id)
        {   
            //do SingleOrDefault or Where depending on the needs
            Drone drone = GetDrones().SingleOrDefault(drones => drones.iddrones == id);         
            return drone;
        }
    
        public IQueryable<Drone> GetDrones()
        {
            var drone = db.drones.Select(d => new DroneDTO
            {
                iddrones = d.iddrones,
                //more stuff
            });
            return drone;
        }
    }
    
    public class APIController : ApiController
    {
        //this can be injected, service located, etc. simple instance in this eg.
        private Db dataAccess = new Db();
    
        [HttpGet]
        [Route("api/drones")]
        public HttpResponseMessage getDrones()
        {
            var drones = dataAccess.GetDrones();
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drones);
            return res;
        }
    
        [HttpGet]
        [Route("api/drones/{id}")]
        public HttpResponseMessage getDrones(int id)
        {
            var drone =  dataAccess.GetDrone(int id);
            HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, drone);
            return res;
        }
    }
    
    public class APIController : ApiController
    {
        private readonly IDroneService _droneService;
    
        public APIController(IDroneService droneService)
        {
            _droneService = droneService;
        }
    
        [HttpGet]
        [Route("api/drones")]
        public HttpResponseMessage GetDrones()
        {
            var drones = _droneService
                .GetDrones()
                .Select(DroneDTOFactory.Build);
    
            return Request.CreateResponse(HttpStatusCode.OK, drones);
        }
    
        [HttpGet]
        [Route("api/drones/{id}")]
        public HttpResponseMessage GetDrones(int id)
        {
            // I am assuming you meant to get a single drone here
            var drone = DroneDTOFactory.Build(_droneService.GetDrone(id));
    
            return Request.CreateResponse(HttpStatusCode.OK, drone);
        }
    }
    
    public static class DroneDTOFactory
    {
        public static DroneDTO Build(Drone d)
        {
            if (d == null)
                return null;
    
            return new DroneDTO
            {
                iddrones = d.iddrones,
                //more stuff
            };
        }
    }