2012-05-02 60 views

回答

0

查詢字符串參數是可選的,不是地址的「正式」部分 - 它從方案到路徑(通過主機和端口)。有許多情況下,您在操作代碼的地址http://something.com/path處有一個操作,您可以查看查詢字符串參數以做出某些決定。例如,下面的代碼在查詢字符串中查找「格式」參數,該查詢字符串可能會或可能不會被傳遞,並且所有請求(帶或不帶)都被正確路由到操作。評論後

public class StackOverflow_10422764 
{ 
    [DataContract(Name = "Person", Namespace = "")] 
    public class Person 
    { 
     [DataMember] 
     public string Name { get; set; } 
     [DataMember] 
     public int Age { get; set; } 
    } 
    [ServiceContract] 
    public class Service 
    { 
     [WebGet(UriTemplate = "/NoQueryParams")] 
     public Person GetPerson() 
     { 
      string format = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters["format"]; 
      if (format == "xml") 
      { 
       WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml; 
      } 
      else if (format == "json") 
      { 
       WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json; 
      } 

      return new Person { Name = "Scooby Doo", Age = 10 }; 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress)); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     WebClient c = new WebClient(); 
     Console.WriteLine(c.DownloadString(baseAddress + "/NoQueryParams")); 

     c = new WebClient(); 
     Console.WriteLine(c.DownloadString(baseAddress + "/NoQueryParams?format=json")); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 

更新: 如果要強制請求發給包含在模板中指定的參數,那麼你可以使用類似消息檢查來驗證。

public class StackOverflow_10422764 
{ 
    [DataContract(Name = "Person", Namespace = "")] 
    public class Person 
    { 
     [DataMember] 
     public string Name { get; set; } 
     [DataMember] 
     public int Age { get; set; } 
    } 
    [ServiceContract] 
    public class Service 
    { 
     [WebGet(UriTemplate = "/NoQueryParams")] 
     public Person GetPerson() 
     { 
      string format = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters["format"]; 
      if (format == "xml") 
      { 
       WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml; 
      } 
      else if (format == "json") 
      { 
       WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json; 
      } 

      return new Person { Name = "Scooby Doo", Age = 10 }; 
     } 

     [WebGet(UriTemplate = "/TwoQueryParam?x={x}&y={y}")] 
     public int Add(int x, int y) 
     { 
      return x + y; 
     } 
    } 
    public class MyForceQueryMatchBehavior : IEndpointBehavior, IDispatchMessageInspector 
    { 
     #region IEndpointBehavior Members 

     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
     { 
     } 

     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
     { 
      endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this); 
     } 

     public void Validate(ServiceEndpoint endpoint) 
     { 
     } 

     #endregion 

     #region IDispatchMessageInspector Members 

     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
     { 
      UriTemplateMatch uriTemplateMatch = (UriTemplateMatch)request.Properties["UriTemplateMatchResults"]; 

      // TODO: may need to deal with the case of implicit UriTemplates, or if you want to allow for some query parameters to be ommitted 

      List<string> uriTemplateQueryVariables = uriTemplateMatch.Template.QueryValueVariableNames.Select(x => x.ToLowerInvariant()).ToList(); 
      List<string> requestQueryVariables = uriTemplateMatch.QueryParameters.Keys.OfType<string>().Select(x => x.ToLowerInvariant()).ToList(); 
      if (uriTemplateQueryVariables.Count != requestQueryVariables.Count || uriTemplateQueryVariables.Except(requestQueryVariables).Count() > 0) 
      { 
       throw new WebFaultException(HttpStatusCode.NotFound); 
      } 

      return null; 
     } 

     public void BeforeSendReply(ref Message reply, object correlationState) 
     { 
     } 

     #endregion 
    } 
    static void SendRequest(string uri) 
    { 
     Console.WriteLine("Request to {0}", uri); 
     WebClient c = new WebClient(); 
     try 
     { 
      Console.WriteLine(" {0}", c.DownloadString(uri)); 
     } 
     catch (WebException e) 
     { 
      HttpWebResponse resp = e.Response as HttpWebResponse; 
      Console.WriteLine(" ERROR => {0}", resp.StatusCode); 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), ""); 
     endpoint.Behaviors.Add(new WebHttpBehavior()); 
     endpoint.Behaviors.Add(new MyForceQueryMatchBehavior()); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     SendRequest(baseAddress + "/NoQueryParams"); 
     SendRequest(baseAddress + "/NoQueryParams?format=json"); 
     SendRequest(baseAddress + "/TwoQueryParam?x=7&y=9&z=other"); 
     SendRequest(baseAddress + "/TwoQueryParam?x=7&y=9"); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 
+0

我明白這一點...然而,是否可以對其進行配置,使得如果URI模板上沒有100%的匹配響應某種錯誤? – Perpetualcoder

+2

只是爲了澄清「查詢字符串參數是可選的,而不是正式」地址的一部分「的說法。您的意思是WCF REST框架不會將查詢字符串參數視爲「地址的一部分」。但是,根據URI規範http://www.ietf.org/rfc/rfc3986.txt查詢字符串參數是資源標識的一部分。 –

+0

@達雷爾米勒感謝您的評論。由於其行爲方式,我有點重新思考我的REST概念。很有趣的是,即使FB api也能像我的API一樣工作。不過,我認爲這是一個MVC應用程序的良好行爲..但對於一個寧靜的API,我想1 URI模式=資源。我想知道OpenRasta和ServiceStack如何處理這個 – Perpetualcoder