2013-02-27 2 views
3

라우팅 및 컨트롤러에 대한 많은 질문을 읽었지 만 찾고있는 것을 찾을 수 없습니다. 나는이 구조를 가진이 컨트롤러를 가지고있다 :요청과 일치하는 여러 작업이 발견되었습니다.

업데이트 : 포함 된 전체 클래스 소스.

public class LocationsController : ApiController 
{ 
    private readonly IUnitOfWork _unitOfWork; 

    public LocationsController(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
    } 

    // GET /api/locations/id 
    public Location Get(Guid id) 
    { 
     return this.QueryById<Location>(id, _unitOfWork); 
    } 

    // GET /api/locations 
    public IQueryable<Location> Get() 
    { 
     return this.Query<Location>(_unitOfWork); 
    } 

    // POST /api/locations 
    public HttpResponseMessage Post(Location location) 
    { 
     var id = _unitOfWork.CurrentSession.Save(location); 
     _unitOfWork.Commit(); 

     var response = Request.CreateResponse<Location>(HttpStatusCode.Created, location); 
     response.Headers.Location = new Uri(Request.RequestUri, Url.Route(null, new { id })); 

     return response; 
    } 

    // PUT /api/locations 
    public Location Put(Location location) 
    { 
     var existingLocation = _unitOfWork.CurrentSession.Query<Location>().SingleOrDefault(x => x.Id == location.Id); 

     //check to ensure update can occur 
     if (existingLocation == null) 
     { 
      throw new HttpResponseException(HttpStatusCode.NotFound); 
     } 
     //merge detached entity into session 
     _unitOfWork.CurrentSession.Merge(location); 
     _unitOfWork.Commit(); 

     return location; 
    } 

    // DELETE /api/locations/5 
    public HttpResponseMessage Delete(Guid id) 
    { 
     var existingLocation = _unitOfWork.CurrentSession.Query<Location>().SingleOrDefault(x => x.Id == id); 

     //check to ensure delete can occur 
     if (existingLocation != null) 
     { 
      _unitOfWork.CurrentSession.Delete(existingLocation); 
      _unitOfWork.Commit(); 
     } 

     return new HttpResponseMessage(HttpStatusCode.NoContent); 
    } 

    // rpc/locations 
    public HttpResponseMessage Dummy() 
    { 
     // I use it to generate some random data to fill the database in a easy fashion 
     Location location = new Location(); 
     location.Latitude = RandomData.Number.GetRandomDouble(-90, 90); 
     location.Longitude = RandomData.Number.GetRandomDouble(-180, 180); 
     location.Name = RandomData.LoremIpsum.GetSentence(4, false); 

     var id = _unitOfWork.CurrentSession.Save(location); 
     _unitOfWork.Commit(); 

     var response = Request.CreateResponse<Location>(HttpStatusCode.Created, location); 
     response.Headers.Location = new Uri(Request.RequestUri, Url.Route(null, new { id })); 

     return response; 
    } 
} 

그리고 내 경로 정의 (Global.asax에) : 지금까지

public static void RegisterRoutes(RouteCollection routes) 
{ 
    // Default route 
    routes.MapHttpRoute(
     name: "Default", 
     routeTemplate: "{controller}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 

    // A route that enables RPC requests 
    routes.MapHttpRoute(
     name: "RpcApi", 
     routeTemplate: "rpc/{controller}/{action}", 
     defaults: new { action = "Get" } 
    ); 
} 

내가 가진 브라우저 치면 :

  • [baseaddress]/locations/s0m3-gu1d-g0e5-hee5eeeee // 그것은
  • [baseaddress]/locations/
  • 작동을 // 복수 검색 결과
  • [baseaddress]/rpc/locations/dummy // 그것은 이상한 일이 일부 업데이트를 수행하는 동안 내 NuGet으로 엉망이 될 때까지이,를 작동하는 데 사용 이다

작동합니다. 내가 여기서 무엇을 놓치고 있니?

GET, POST, PUT 또는 delete로 시작하는 동사가 첫 번째 경로에 자동 매핑되고 rpc를 통해 제 2 경로에 속하는 더미 테스트 메서드가 호출됩니다. MyProject를 입력에 System.Linq.IQueryable`1가 [Myproject.Domain.Location] 받기() : 슬로우됩니다

오류가

여러 작업 요청을 일치 발견 된 메시지 InvalidOperationException입니다. 형 Myproject.Webservices.Controllers.LocationsController

어떤 아이디어가 Webservices.Controllers.LocationsController System.Net.Http.HttpResponseMessage 더미()?

+0

Trimming 된 RPC 메소드를 포함하여 LocationsController에 대한 전체 코드를 게시 할 수 있습니까? –

+0

_ "NuGet을 업데이트하는 동안 엉망이 될 때까지이 작업이 사용되었습니다. 여기에 무엇이 없습니까?"- 소스 제어. 마우스 오른쪽 버튼을 클릭 -> 실행 취소/되돌리기. – CodeCaster

+0

프로젝트가 올바르게 빌드되고 실행됩니다. 나는 차라리 되돌리기보다는 잘못을 고치고 이해하려고 노력할 것입니다.(그리고 나는 그러한 복귀가 몇 시간 동안 나를 되돌아 놓을 것이라고 고백한다.) – Joel

답변

5

문제는 경로가로드되는 순서입니다. 그들이 이런 경우 :

// A route that enables RPC requests 
routes.MapHttpRoute(
    name: "RpcApi", 
    routeTemplate: "rpc/{controller}/{action}", 
    defaults: new { action = "Get" } 
); 

// Default route 
routes.MapHttpRoute(
    name: "Default", 
    routeTemplate: "{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional } 
); 

잘 작동합니다. 먼저 RPC에 대해 요청한 다음 컨트롤러 (Id가 있거나 없을 수도 있음)에 대해 요청이 매핑됩니다. 다음과 같이이 자유롭게 복잡한 유형으로 작업 할 수 있도록

+0

"괜찮습니다." 확실히했습니다! 올바른 방향으로 나를 설정해 주셔서 감사합니다! 참고로 새 경로가 필요합니까? (내가 처음 주문했을 때 2 개만 작동했기 때문에 주문을 다시했기 때문에 묻고있다.) – Joel

+0

@Joel : 나는 그냥 시험 받았을 뿐이라고 생각하지 않는다. 한 번에 더 많은 경로를 추가하면 당분간 증가하는 메소드 수가 많아지면 쉽게 깨질 수 있습니다. –

+0

내 원래 아이디어는 REST가 4 개의 Http 동사를 처리하고 실제로 필요할 때만 RPC 호출을 사용하도록하는 것입니다. 나는 당신이 당신의 대답을 편집하고 불필요한 경로를 제거하는 것이 좋습니다 :) – Joel

0

우리는 또한 API를 컨트롤러에 대한 사용자 지정 작업 선택기를 만들 수 있습니다 기존의 "POST는 DELETE, PUT GET"

class ApiActionSelector : IHttpActionSelector 
    { 
     private readonly IHttpActionSelector defaultSelector; 

     public ApiActionSelector(IHttpActionSelector defaultSelector) 
     { 
      this.defaultSelector = defaultSelector; 
     } 
     public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor) 
     { 
      return defaultSelector.GetActionMapping(controllerDescriptor); 
     } 
     public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) 
     { 
      // Get HttpMethod from current context 
      HttpMethod httpMethod = controllerContext.Request.Method; 

      // Set route values for API 
      controllerContext.RouteData.Values.Add("action", httpMethod.Method); 

      // Invoke Action 
      return defaultSelector.SelectAction(controllerContext); 
     } 
    } 

을 그리고 우리는을 등록 할 수 있습니다 WebApiConfig에서와 동일 :

이러한 종류의 문제를 실행하는 사용자에게 도움이 될 수 있습니다.

관련 문제