2014-04-14 170 views
3

我是來自WCF背景的web api的新手,因爲我在潛水之前觀看了Shawn Wildermuth的Pluralsight課程。他的課程材料是圍繞更傳統的路由而設計的。該課程涉及的主題之一是HATEOAS,通過基礎API控制器和模型工廠實現這一點是多麼容易。屬性路由和查詢字符串

我在實現對屬性路由時遇到的第一件事情是需要UrlHelper將路由名稱作爲Link()方法的第一個參數,這是在WebApiConfig中配置的常規路由中繼承的的.cs。

我通過使用Name屬性裝飾我的控制器路由屬性來解決此問題,並且無論我使用哪種方法(請參見下面的代碼),該控制器中的所有方法都可以訪問name屬性。雖然我覺得這有點奇怪,但它的工作原理。現在我已經實現了HATEOAS,我注意到它生成的URL是以查詢字符串格式生成的,而不是「url」格式(我知道該術語是錯誤的,但是忍受着我)。而不是.../api /交付物/ 1我正在.../api /交付物?id = 1。

這是「好」,但不是所需的輸出。雖然我還沒有想出如何調整URL的返回值的格式,我想我會測試查詢字符串對我的控制器,發現在查詢字符串格式我的控制器不起作用,但在「url 「它的格式。

然後我花了一個小時試圖找出原因。我嘗試過不同的裝飾(即[FromUri],從我的閱讀來看,這隻適用於默認爲消息正文的複雜對象)設置默認值,約束並使其成爲可選項(即{id?})。

下面是有問題的代碼,無論是控制器,基本API控制器和模型工廠,使HATEOAS實現成爲可能。

的3個問題我有是:

1)如何使控制器接受查詢字符串並在URL格式(... /交付/ 1 ... /交付的「身份證」? ID = 1。

2)如何使URL幫手的鏈接方法中的URL格式返回值(這是目前恢復它作爲查詢字符串。

3)以適當的方式來命名路線WebAPI 2.我在做什麼(爲單一方法分配一個名稱,其他人似乎繼承了它,只是聞起來有異味,我必須相信這會崩潰,因爲我實際上開始實施更復雜的代碼。肖恩的執行是否以某種方式存在缺陷?我喜歡不必爲測試/開發目的而硬編碼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