2010-01-28 1 views
8

는 I은이 URL에 POST를 받아들이는 컨트롤러가 :ASP.NET MVC 라우팅에서 HttpMethodConstraint와 함께 사용자 정의 제약 조건을 사용하려면 어떻게해야합니까?

POST http://server/stores/123/products 

POST는 내용 유형 application/json이어야한다, 그래서 이것은 내 라우팅 테이블에있는 것입니다 :

routes.MapRoute(null, 
       "stores/{storeId}/products", 
       new { controller = "Store", action = "Save" }, 
       new { 
         httpMethod = new HttpMethodConstraint("POST"), 
         json = new JsonConstraint() 
        } 
       ); 

어디 JsonConstraint 것은 : 내가 경로를 사용하는 경우

public class JsonConstraint : IRouteConstraint 
{ 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     return httpContext.Request.ContentType == "application/json"; 
    } 
} 

, 나는 금지 된 405를 얻을 :

The HTTP verb POST used to access path '/stores/123/products' is not allowed

그러나 json = new JsonConstraint() 제약 조건을 제거하면 올바르게 작동합니다. 아무도 내가 뭘 잘못하고 있는지 알아?

+0

당신이 jQuery를 조각을 게시 할 수 있습니다하세요? 추가 테스트를 실행했으며 ContentType이 "application/xml"으로 표시되고 있음을 보여줍니다. –

+0

나는 이것을 테스트하기 위해'REST Client'라는 Firefox 플러그인을 사용하고 있습니다. –

답변

8

나는 이것을 주석에 넣었지만 충분한 공간이 없다.

사용자 정의 제한 조건을 작성할 때 routeDirection 매개 변수를 검사하고 적시에 로직이 실행되도록하는 것이 매우 중요합니다.

이 매개 변수는 들어오는 요청을 처리하는 동안 또는 누군가가 URL을 생성하는 동안 실행중인 제한 조건 (예 : Html.ActionLink을 호출 할 때)을 알려줍니다. 귀하의 경우에는

나는 당신이 "만약"거대한에 모든 일치하는 코드를 삽입 할 생각 :

public bool Match(HttpContextBase httpContext, Route route, 
    string parameterName, RouteValueDictionary values, 
    RouteDirection routeDirection) 
{ 
    if (routeDirection == RouteDirection.IncomingRequest) { 
     // Only check the content type for incoming requests 
     return httpContext.Request.ContentType == mimeType; 
    } 
    else { 
     // Always match when generating URLs 
     return true; 
    } 
} 
+0

좋은 답변이지만'ContentType' 대신'Accept'를 사용해서는 안됩니까? http://stackoverflow.com/a/15898503/1804678 – Jess

+0

@Jess 원래 질문에 특별히 언급 된 'ContentType'. 'ContentType'은 요청 본문의 형식을 나타내며 'Accept' 헤더는 응답 본문으로 구성된 * desired *를 나타냅니다. – Eilon

4

JsonConstraint을 디버그하고 내용 유형이 무엇인지 확인합니다.

어떤 이유로 든 application/json 일 수 없습니다.

나는 그것이 RFC MIME 형식이라는 것을 알고 있지만 여기에 previous question에서 언급했듯이 내 주위에 떠 다니는 몇 가지 다른 것들 (예 : text/x-json)을 보았습니다.

또한 ContentType 제약 조건을 본 적이 없으므로 작동하는지 확인하고 싶습니다. 다른 MIME 형식으로 시도해 보셨습니까?

마지막으로, 단일 JsonConstraint를 갖기보다는 일반적인 ContentTypeConstraint를 생성합니다.

업데이트 : 함께 ContentTypeConstraint 코드를 사용하는 경로에 대한 빠른 WebRequest 클래스의 방법을 노크하고 올바르게 작동하는 것 같다

.

열거

public enum ConstraintContentType 
{ 
    XML, 
    JSON, 
} 

이 호출 될

public class ContentTypeConstraint : IRouteConstraint 
{ 
    private string mimeType; 

    public ContentTypeConstraint(ConstraintContentType constraintType) 
    { 
    //FYI: All this code could be redone if you used the Description attribute, and a ToDescription() method. 
    switch (constraintType) 
    { 
     case ConstraintContentType.JSON: 
     mimeType = "application/json"; 
     break; 
     case ConstraintContentType.XML: 
     mimeType = "text/xml"; 
     break; 
     default: 
     mimeType = "text/html"; 
     break; 
    } 
    } 

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
    //As suggested by Eilon 
    if (routeDirection == RouteDirection.UrlGeneration) 
     return true; 

    return httpContext.Request.ContentType == mimeType; 
    } 
} 

제약 클래스로, 귀하의 예제를 사용 :

contentType = new ContentTypeConstraint(ConstraintContentType.JSON) 

제약 조건이되었다가 재사용 무 단지 JSON 그 이상입니다. 또한 enum 클래스의 description 속성을 사용하면 스위치 케이스를 없앨 수 있습니다.

+0

업데이트 및 블로그 게시물을 보내 주셔서 감사합니다. –

+0

@Jess입니다. 슬프게도 나는 몇 년 전에 내 블로그를 쓰러 뜨 렸지만 대답의 고기와 뼈는 여전히 유효하다. –

관련 문제