0
我在 http://localhost/resourceWCF休息怪異路由行爲
可用的資源,我沒有像 HTTP任何路線:/本地主機/資源名稱=約翰
但是當我試着打以上URI我得到http://localhost/resource的結果。我期待一個404.
任何想法爲什麼它忽略?名稱=約翰和匹配的網址?
我在 http://localhost/resourceWCF休息怪異路由行爲
可用的資源,我沒有像 HTTP任何路線:/本地主機/資源名稱=約翰
但是當我試着打以上URI我得到http://localhost/resource的結果。我期待一個404.
任何想法爲什麼它忽略?名稱=約翰和匹配的網址?
查詢字符串參數是可選的,不是地址的「正式」部分 - 它從方案到路徑(通過主機和端口)。有許多情況下,您在操作代碼的地址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();
}
}
我明白這一點...然而,是否可以對其進行配置,使得如果URI模板上沒有100%的匹配響應某種錯誤? – Perpetualcoder
只是爲了澄清「查詢字符串參數是可選的,而不是正式」地址的一部分「的說法。您的意思是WCF REST框架不會將查詢字符串參數視爲「地址的一部分」。但是,根據URI規範http://www.ietf.org/rfc/rfc3986.txt查詢字符串參數是資源標識的一部分。 –
@達雷爾米勒感謝您的評論。由於其行爲方式,我有點重新思考我的REST概念。很有趣的是,即使FB api也能像我的API一樣工作。不過,我認爲這是一個MVC應用程序的良好行爲..但對於一個寧靜的API,我想1 URI模式=資源。我想知道OpenRasta和ServiceStack如何處理這個 – Perpetualcoder