Метод WebClient.UploadString не создает спецификацию. Зачем? - PullRequest
4 голосов
/ 20 апреля 2011

Цель следующего кода - опубликовать данные, которые начинаются с метки порядка байтов (BOM) по HTTP.

var client = new WebClient();
client.Encoding = new UTF8Encoding(true /* encoderShouldEmitUTF8Identifier */);
client.UploadString(url, data);

Однако, согласно Fiddler, в начале тела запроса нет спецификации. Спецификация не отправляется, даже если я использую UnicodeEncoding вместо UTF8Encoding.

Итак, вопрос в том, что я делаю не так?

Примечание : я знаю, что могу обойти эту проблему, используя WebClient.UploadData в сочетании с методом Encoding.GetPreamble, однако мне интересно, почему UploadString не работает, как я ожидал.

1 Ответ

1 голос
/ 24 июня 2011

Вы не делаете ничего плохого, просто WebClient.UploadString не вызывает Encoding.GetPreamble - он просто вызывает Encoding.GetBytes для строки, которую вы передали. В HTTP-запросах, если вы передаете строки, вы обычно указываете кодировку в заголовке типа содержимого (параметр charset) вместо встроенного в файле (см. Пример ниже). UploadString делает это (он приспособлен для «общего случая»). Как вы упомянули, если вы хотите что-то дополнительное, вы можете загрузить байты напрямую.

public class StackOverflow_5731102
{
    [ServiceContract]
    public class Service
    {
        [WebInvoke]
        public Stream Process(Stream input)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var header in WebOperationContext.Current.IncomingRequest.Headers.AllKeys)
            {
                sb.AppendLine(string.Format("{0}: {1}", header, WebOperationContext.Current.IncomingRequest.Headers[header]));
            }

            string contentType = WebOperationContext.Current.IncomingRequest.ContentType;
            Encoding encoding = Encoding.GetEncoding(contentType.Substring(contentType.IndexOf('=') + 1));
            WebOperationContext.Current.OutgoingResponse.ContentType = WebOperationContext.Current.IncomingRequest.ContentType;
            return new MemoryStream(encoding.GetBytes(sb.ToString()));
        }
    }

    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");

        foreach (var encoding in new Encoding[] { new UTF8Encoding(true), new UnicodeEncoding(false, true) })
        {
            Console.WriteLine("Sending encoding = {0}", encoding.WebName);
            WebClient client = new WebClient();
            client.Headers[HttpRequestHeader.ContentType] = "text/plain; charset=" + encoding.WebName;
            client.Encoding = encoding;
            string url = baseAddress + "/Process";
            string data = "hello";
            string result = client.UploadString(url, data);
            Console.WriteLine(result);

            Console.WriteLine(string.Join(",", encoding.GetBytes(data).Select(b => b.ToString("X2"))));
        }

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