Как определить службу NET 4 REST WCF для приема строковых параметров в кодировке URL - PullRequest
1 голос
/ 06 февраля 2012

У меня есть служба WCF REST в NET4, определенная следующим образом:

[WebInvoke(UriTemplate = "/", Method = "POST")]
public Stream ProcessPost(string p1, string p2, string p3, string p4)
{
    return Execute(p1, p2, p3, p4);
}

Мне нужно позвонить с клиентов с POST, которые публикуют данные в виде кодов в форме

    HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";

    string paramz = string.Format("p1={0}&p2={1}&p3={2}&p4={3}", 
        HttpUtility.UrlEncode("str1"),
        HttpUtility.UrlEncode("str2"),
        HttpUtility.UrlEncode("str3"),
        HttpUtility.UrlEncode("str4")
        );

    // Encode the parameters as form data:
    byte[] formData =
        UTF8Encoding.UTF8.GetBytes(paramz);
    req.ContentLength = postData.Length;

    // Send the request:
    using (Stream post = req.GetRequestStream())
    {
        post.Write(formData, 0, formData.Length);
    }

Как мне определить UriTemplate или какие другие атрибуты я должен добавить, чтобы служба могла принимать параметры, отправленные клиентским кодом, показанным выше?

Спасибо

1 Ответ

4 голосов
/ 06 февраля 2012

Вы можете использовать пользовательский форматировщик сообщений, который знает, как работать с этим форматом, поскольку он не поддерживается "из коробки" WCF, как показано в коде ниже. Вы также можете взглянуть на проект Web API в codeplex (http://wcf.codeplex.com),, который изначально поддерживает этот формат.

public class StackOverflow_9153898
{
    [ServiceContract]
    public class Service
    {
        [WebInvoke(UriTemplate = "/", Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
        public Stream ProcessPost(string p1, string p2, string p3, string p4)
        {
            return Execute(p1, p2, p3, p4);
        }

        private Stream Execute(string p1, string p2, string p3, string p4)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
            string response = p1 + "-" + p2 + "-" + p3 + "-" + p4;
            return new MemoryStream(Encoding.UTF8.GetBytes(response));
        }
    }

    public class MyFormsUrlEncodedBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

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

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            foreach (OperationDescription operationDescription in endpoint.Contract.Operations)
            {
                var dispatchOperation = endpointDispatcher.DispatchRuntime.Operations[operationDescription.Name];
                dispatchOperation.Formatter = new MyFormsUrlEncodedDispatchFormatter(operationDescription, dispatchOperation.Formatter);
            }
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }

    class MyFormsUrlEncodedDispatchFormatter : IDispatchMessageFormatter
    {
        OperationDescription operation;
        IDispatchMessageFormatter originalFormatter;

        public MyFormsUrlEncodedDispatchFormatter(OperationDescription operation, IDispatchMessageFormatter originalFormatter)
        {
            this.operation = operation;
            this.originalFormatter = originalFormatter;
        }

        public void DeserializeRequest(Message message, object[] parameters)
        {
            var reqProp = message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
            if (reqProp.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded")
            {
                var bodyReader = message.GetReaderAtBodyContents();
                var bodyBytes = bodyReader.ReadElementContentAsBase64();
                var body = Encoding.UTF8.GetString(bodyBytes);
                NameValueCollection pairs = HttpUtility.ParseQueryString(body);
                DeserializeParameters(pairs, parameters);
                return;
            }

            this.originalFormatter.DeserializeRequest(message, parameters);
        }

        private void DeserializeParameters(NameValueCollection pairs, object[] parameters)
        {
            foreach (var part in this.operation.Messages[0].Body.Parts)
            {
                string name = part.Name;
                string value = pairs[name];
                switch (Type.GetTypeCode(part.Type))
                {
                    case TypeCode.Boolean:
                        parameters[part.Index] = Convert.ToBoolean(value);
                        break;
                    case TypeCode.Byte:
                        parameters[part.Index] = Convert.ToByte(value);
                        break;
                    case TypeCode.Char:
                        parameters[part.Index] = Convert.ToChar(value);
                        break;
                    // Skipped many others
                    case TypeCode.String:
                        parameters[part.Index] = value;
                        break;
                    default:
                        throw new NotImplementedException("Not implemented for type " + part.Type);
                }
            }
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            return this.originalFormatter.SerializeReply(messageVersion, parameters, result);
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
        endpoint.Behaviors.Add(new WebHttpBehavior());

        // this needs to go *after* the WebHttpBehavior
        endpoint.Behaviors.Add(new MyFormsUrlEncodedBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        c.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
        Console.WriteLine(c.UploadString(baseAddress + "/", "p1=str1&p2=str2&p3=str3&p4=str4"));

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