2014-04-14 2 views
3

WCF 배경에서 웹 API를 처음 접하는 동안 새로운 기능을 익히고 준비하기 전에 Shawn Wildermuth의 Pluralsight 과정을 본 후 다이빙을 시작했습니다. 그의 코스 자료는보다 전통적인 라우팅 방식을 중심으로 디자인되었습니다. 코스가 진행하는 과목 중 하나는 HATEOAS이며 기본 API 컨트롤러 및 모델 공장에서이를 달성하는 것이 얼마나 쉬운가입니다.속성 라우팅 및 쿼리 문자열

속성 라우팅을 구현할 때 가장 먼저 수행 한 작업 중 하나는 UrlHelper가 WebApiConfig에 구성된 기존 라우팅에서 상속 된 Link() 메서드의 첫 번째 인수로 경로 이름을 가져야한다는 것입니다. .cs.

내 컨트롤러 경로 속성 중 하나를 Name 속성으로 꾸미면이 작업을 수행했는데 해당 컨트롤러의 모든 메서드가 어떤 메서드를 사용했는지에 관계없이 name 속성에 액세스 할 수있는 것으로 나타납니다 (아래 코드 참조). 이것이 좀 이상하게 느껴지더라도 작동합니다. 이제는 HATEOAS를 구현 했으므로 생성 된 URL이 쿼리 문자열 형식이고 "url"형식이 아닌 것으로 나타났습니다 (이 용어는 잘못되었지만 나와 함께 있습니다.). 대신 .../api/deliverables/1을 얻는 중 .../api/deliverables? id = 1.

"ok"이지만 원하는 출력이 아닙니다. URL의 반환 값의 형식을 조정하는 방법을 아직 알지 못했지만 컨트롤러에 대해 쿼리 문자열을 테스트 한 결과 쿼리 문자열 형식에서 컨트롤러가 작동하지 않지만 "url "포맷.

나는 그 때 이유를 알아 내려고 노력했다. 나는 디폴트 값, 제약 조건을 설정하고 선택적으로 (즉, {id?}) 설정하는 것과 같이 다른 장식 (예 : [FromUri]은 메시지 본문을 기본으로하는 복잡한 객체에만 필요합니다)을 시도했습니다.

다음은 컨트롤러, 기본 API 컨트롤러 및 HATEOAS 구현을 가능하게 만드는 모델 팩터 모두에 해당하는 코드입니다.

3 개 질문 I이 있습니다

1) 어떻게 컨트롤러 (...// 1 산출물 및 .../산출물 쿼리 문자열에하고 URL 형식으로 "ID를"받아 들일 수 있도록? URL을 도우미의 링크 방식이 현재 쿼리 문자열로 반환합니다 (URL 형식으로 값을 반환 만드는 방법 ID = 1.

2). 이름 경로에

3) 적절한 방법으로 WebAPI 2. 내가하고있는 일 (하나의 메소드에 이름을 할당하고 다른 메소드가 그걸 상속받는 것처럼 보임)은 실제로 냄새가 난다. 실제로 구현하기 시작하면 이것이 엉망이 될 것이라고 믿어야한다. 더 복잡한 코드. Shawn의 구현에 어떤 방식으로 결함이 있습니까? 테스트/개발 목적으로 URL을 하드 코딩하지 않아도되지만 UrlHelper가이를 달성하는 가장 좋은 방법은 아닙니다. 그것은 필요하지 않을 수있는 많은 수화물을 가지고 다니는 것 같습니다.

컨트롤러 :

[RoutePrefix("api/deliverables")] 
public class DeliverablesController : BaseApiController 
{ 
    private readonly IDeliverableService _deliverableService; 
    private readonly IUnitOfWork _unitOfWork; 

    public DeliverablesController(IDeliverableService deliverableService, IUnitOfWorkAsync unitOfWork) 
    { 
     _deliverableService = deliverableService; 
     _unitOfWork = unitOfWork; 
    } 

    [Route("", Name = "Deliverables")] 
    public IHttpActionResult Get() 
    { 
     return Ok(_deliverableService.Get().Select(TheModelFactory.Create)); 
    } 

    [Route("{id}")] 
    public IHttpActionResult Get(int id) 
    { 
     return Ok(TheModelFactory.Create(_deliverableService.Find(id))); 
    } 

    [Route("")] 
    public IHttpActionResult Post([FromBody]DeliverableModel model) 
    { 
     try 
     { 
      var entity = TheModelFactory.Parse(model); 

      if (entity == null) 
      { 
       return BadRequest("Could not parse Deliverable entry in body."); 
      } 

      _deliverableService.Insert(entity); 
      _unitOfWork.SaveChanges(); 

      return Created(Request.RequestUri + "/" + entity.Id.ToString(CultureInfo.InvariantCulture),TheModelFactory.Create(entity)); 


     } 
     catch (Exception exception) 
     { 
      return BadRequest(exception.Message); 
     } 
    } 
} 

자료 API 컨트롤러 :

public abstract class BaseApiController : ApiController 
{ 
    private ModelFactory _modelFactory; 

    protected ModelFactory TheModelFactory 
    { 
     get 
     { 
      return _modelFactory ?? (_modelFactory = new ModelFactory(Request)); 
     } 
    } 
} 

모델 공장 :

public class ModelFactory 
{ 
    private readonly UrlHelper _urlHelper; 

    public ModelFactory(HttpRequestMessage request) 
    { 
     _urlHelper = new UrlHelper(request); 
    } 

    public DeliverableModel Create(Deliverable deliverable) 
    { 
     return new DeliverableModel 
       { 
        Url = _urlHelper.Link("deliverables", new { id = deliverable.Id }), 
        Description = deliverable.Description, 
        Name = deliverable.Name, 
        Id = deliverable.Id 
       }; 
    } 

    public Deliverable Parse(DeliverableModel model) 
    { 
     try 
     { 
      if (string.IsNullOrEmpty(model.Name)) 
       return null; 

      var entity = new Deliverable 
         { 
          Name = model.Name, 
          Description = !string.IsNullOrEmpty(model.Description) 
           ? model.Description 
           : string.Empty 
         }; 

      return entity; 
     } 
     catch (Exception) 
     { 
      return null; 
     } 
    } 
} 

는 p로 설명이 아닌 속성 (전통) 라우팅의 OINT는 URI와 쿼리 문자열 형식 모두 문제없이 작동 : 제 생각에는

config.Routes.MapHttpRoute(
      name: "deliverables", 
      routeTemplate: "api/deliverables/{id}", 
      defaults: new { controller = "deliverables", id = RouteParameter.Optional } 
     ); 

답변

1

, 이것은 기인 라우팅 문제 중 하나입니다. 그래서 예외적 인 경우에만 사용합니다. . 나는 대다수의 라우팅을 위해 라우트 테이블을 사용하고 예외적 인 경우 라우트를 특성화 된 라우팅으로 드롭 다운합니다.

이 방법으로 해결하려면 Get (id)에서 여러 경로를 생각해 보셨습니까? (나는 실제로 이것이 효과가있을 것이라고 생각하지 않지만 시도 할 가치가있다).

+0

답변 해 주셔서 감사합니다. 크게 감사드립니다. 여러 경로를 시도했지만 여전히 작동하지 못했습니다. 귀하의 조언에 따라, 필자는 경로 표로 돌아가서 필요할 때마다 속성 라우팅에 다시 접근 할 것입니다. –

+0

나는 그것이 다른 방법으로 라운드해야한다고 생각합니다 - AttributeRouting이 당신의 필요를 충족시키지 않을 때마다 RouteTables를 사용하십시오. – Mrchief

관련 문제