Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rest 表示深层资源树的最佳方法?_Rest_Asp.net Core_Asp.net Core Webapi - Fatal编程技术网

Rest 表示深层资源树的最佳方法?

Rest 表示深层资源树的最佳方法?,rest,asp.net-core,asp.net-core-webapi,Rest,Asp.net Core,Asp.net Core Webapi,是否有一种简单的方法可以将路线“段”与控制器逻辑一起重用,以验证和使用段中的参数 例如,我想用类似的方式表示我的资源: 房屋 {住址} 建筑 屋顶 侧线 房间 活着的 门 窗户 进餐 门 窗户 厨房 门 窗户 卧室 [0] 门 窗户 [1] 门 窗户 下面是一种可以做到的方法更好的方法是什么? [Route("[controller]")] [ApiController] class HousesController : ControllerBase

是否有一种简单的方法可以将路线“段”与控制器逻辑一起重用,以验证和使用段中的参数

例如,我想用类似的方式表示我的资源:

  • 房屋
    • {住址}
      • 建筑
        • 屋顶
        • 侧线
      • 房间
        • 活着的
          • 窗户
        • 进餐
          • 窗户
        • 厨房
          • 窗户
        • 卧室
          • [0]
            • 窗户
          • [1]
            • 窗户
下面是一种可以做到的方法更好的方法是什么?

[Route("[controller]")]
[ApiController]
class HousesController : ControllerBase
{
    [HttpGet]
    public IEnumerable<House> Get() => _housesRepo.GetAll();

    [HttpGet("{houseId}")]
    public ActionResult<House> Get(string houseId)
    {
        if (!_housesRepo.TryGetHouse(houseId, out var house))
            return NotFound("Bad house ID");
    }
}

class RoomsController : ControllerBase
{
    [HttpGet("~houses/{houseId}/rooms/bedrooms/{bedroomId}")]
    public ActionResult<Room> GetBedroom(string houseId, int bedroomId)
    {
        if (!_housesRepo.TryGetHouse(houseId, out var house))
            return NotFound("Bad house ID");
        var bedrooms = house.Bedrooms;
        if (bedroomId < 0 || bedroomId >= bedrooms.Length)
            return NotFound("Bad bedroom ID");
        return bedrooms[bedroomId];
    }

    [HttpGet("~houses/{houseId}/rooms/{roomClass}")]
    public ActionResult<Room> GetRoom(string houseId, string roomClass)
    {
        if (!_housesRepo.TryGetHouse(houseId, out var house))
            return NotFound("Bad house ID");
        var roomsByClass = house.RoomsByClass;
        if (!roomsByClass.TryGetValue(roomClass, out var room))
            return NotFound("Bad room class");
        return room;
    }
}

class ArchitectureController : ControllerBase
{
    [HttpGet("~houses/{houseId}/architecture")]
    public ActionResult<string[]> Get(string houseId)
    {
        if (!_housesRepo.TryGetHouse(houseId, out _))
            return NotFound("Bad house ID");
        return new [] { "roof", "siding" };
    }

    [HttpGet("~houses/{houseId}/architecture/roof")]
    public ActionResult<Roof> GetRoof(string houseId)
    {
        if (!_housesRepo.TryGetHouse(houseId, out var house))
            return NotFound("Bad house ID");
        return house.Architecture.Roof;
    }

    [HttpGet("~houses/{houseId}/architecture/siding")]
    public ActionResult<Siding> GetSiding(string houseId)
    {
        if (!_housesRepo.TryGetHouse(houseId, out var house))
            return NotFound("Bad house ID");
        return house.Architecture.Siding;
    }
}
这将是非常容易建立的基础。例如,我可以快速添加门和窗的控制器:

[HttpGet("[ROOM|BEDROOM]/doors")]
public Door[] GetDoors(Room room) => room.Doors;

[HttpGet("[ROOM|BEDROOM]/windows")]
public Window[] GetWindows(Room room) => room.Windows;

正如您所指出的,这是不可能的,但它仍然是可以实现的。首先,您希望依赖应用于控制器类本身的路由前缀。换句话说,不是:

[HttpGet("~houses/{houseId}/rooms/bedrooms/{bedroomId}")]
public ActionResult<Room> GetBedroom(string houseId, int bedroomId)

这看起来有点复杂,但所做的只是从路由中拉出
houseId
参数,并试图找到相关的房屋。如果没有找到,将立即返回404,否则,控制器上的
House
属性将与该House一起设置。因此,您在该控制器中的每个操作现在都可以依赖于可用的
房屋
属性,并可以相应地使用它,只需关注自己的特定行为。

。细节(比如参数名以及如何将参数转换成对象)可以被封装和抽象——我喜欢!基于使用
FindAsync
,传递什么作为
houseId
应该无关紧要。例如,如果有人尝试了
/houses/foo/rooms/beddrooms/1
,结果应该是404。但是,您可能仍然希望将路由约束添加到参数:
house/{houseId:int}/rooms
beddrooms/{beddroomid:int}
[HttpGet("~houses/{houseId}/rooms/bedrooms/{bedroomId}")]
public ActionResult<Room> GetBedroom(string houseId, int bedroomId)
[Route("houses/{houseId}/rooms")]
public class RoomsController : ControllerBase
{
    [HttpGet("bedrooms/{bedroomId}")]
    public ActionResult<Room> GetBedroom(int bedroomId)
private House House { get; set; }

public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
    if (context.RouteData.Values.TryGetValue("houseId", out var houseId))
    {
        House = await _context.Set<House>().FindAsync(houseId);
        if (House == null)
            context.Result = NotFound();
    }

    await base.OnActionExecutionAsync(context, next);
}