多个控制器端点之间的Web Api交互

时间:2017-02-06 12:22:14

标签: c# asp.net asp.net-web-api architecture

我正在寻找一些建设性的建议。我试图映射多个控制器端点如何相互交互,这样我最终不会在多个控制器中编写相同的代码。请允许我用简单的看板示例进行说明。

我在想这里有两个(或三个)控制器:BoardController,CardController,SubCardController(未定)。现在让我们忽略卡可以组织成列表的事实,因为我们会在Board和Card控制器之间安装一个ListController。

董事会控制人:

public class BoardController : ApiController {
    // among basic CRUD methods I have a method that returns single board
    // implementation #1
    // /api/board/getbyid?id=123
    public HttpResponseMessage GetById(int id) {
        var board = dataStore.GetById(id);
        if (board == null)
            return Request.CreateResponse(HttpStatusCode.NotFound);

        return Request.CreateResponse(HttpStatusCode.OK, board);
    }

    // implementation #2
    // /api/board/getbyid?id=123
    public HttpResponseMessage GetById(int id) {
        var board = GetById(id);
        if (board == null)
            return Request.CreateResponse(HttpStatusCode.NotFound);

        return Request.CreateResponse(HttpStatusCode.OK, board);
    }

    [NonAction]
    // normally methods like this one I declare as private
    // but in this case CardController needs to call this method as well
    public static Board GetById(int id) {
        return dataStore.GetById(id);
    }
}

请允许我澄清dataStore是对另一个单独负责数据访问的控制器的引用。

卡控制器:

public class CardController : ApiController {
    // among basic CRUD methods I might want to call BoardControllers GetById(id) method (to verify if board exists for example)
    // implementation #1
    public HttpResponseMessage GetAll(int boardId) {
        // call BoardController.GetById(id) by issueing HTTP request
        HttpRequestMessage _request = new HttpRequestMessage(HttpMethod.Get, requestUri);
        HttpResponseMessage _response = Client.SendAsync(_request).Result;
        Board board = _response.Content.ReadAsAsync<Board>().Result;
        if (board == null /* || more condition(s) */)
            return Request.CreateResponse(HttpStatusCode.NotFound);

        // get cards and return
    }

    // implementation #2
    public HttpResponseMessage GetAll(int boardId) {
        // call BoardController.GetById(id) static method
        var board = _boardCtrl.GetById(boardId);
        if (board == null /* || more condition(s) */)
            return Request.CreateResponse(HttpStatusCode.NotFound);

        // get cards and return
    }
}

这是我的两种替代解决方案。一方面实现#1不需要额外的静态方法,但另一方面,我认为从一个控制器动作发出HTTP请求以访问另一个控制器动作是不好的。

让我知道你们的想法。特别是如果有更整洁的替代品。

1 个答案:

答案 0 :(得分:2)

根据需要创建服务并将其注入相关控制器。控制器应保持精益,不要关注实施问题。

public interface IBoardService {
    Board GetById(int id);
    //...other code removed for brevity
}

public class BoardController : ApiController {
    readonly IBoardService dataSource;
    public BoardController(IBoardService dataSource) {
        this.dataSource = dataSource;
    }

    // /api/board/getbyid?id=123
    public IHttpActionResult GetById(int id) {
        var board = dataSource.GetById(id);    
        return board == null ? NotFound() : OK(board);
    }
}

如果需要,电路板服务也可以重复使用,以便注入CardController

public class CardController : ApiController {
    readonly IBoardService boardService;
    readonly ICardService cardService;

    public CardController(ICardService cardService, IBoardService boardService) {
        this.cardService = cardService;
        this.boardService = boardService;
    }   

    public IHttpActionResult GetAll(int boardId) {
        var board = boardService.GetById(boardId);
        if (board == null /* || more condition(s) */)
            return NotFound();

        // get cards from card service and return
    }

}

使用注入的服务方法允许在需要时重用它。

另外,尽量保持控制器的精益。

不需要控制器中的所有逻辑。

卡服务的实施可能取决于电路板服务,并且仅公开GetAllByBoardId(int id),这将减少示例中CardController的逻辑。

相关问题