0

http://localhost/resourceでリソースを利用できます

http:/localhost/resource?name=john のようなルートはありません

しかし、上記の URI にアクセスしようとすると、http://localhost/resourceの結果が得られます。私は404を期待していました。

?name=john を無視して、URL を一致させる理由は??

4

1 に答える 1

0

クエリ文字列パラメーターはオプションであり、アドレスの「正式な」部分ではありません。スキームからパスへ (ホストとポートを介して) 移動します。アドレスhttp://something.com/pathで1 つの操作を行い、操作コードでクエリ文字列パラメーターを調べて決定を下すシナリオは多数あります。たとえば、以下のコードは、クエリ文字列内の「format」パラメーターを検索します。このパラメーターは、渡される場合と渡されない場合があり、すべての要求 (それを含むまたは含まない) が正しく操作にルーティングされます。

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();
    }
}
于 2012-05-03T00:23:58.333 に答える