Страницы

Поиск по вопросам

среда, 19 июня 2019 г.

Вернуть правильное значение Content-Length при HEAD запросе к WCF службе

Есть self-hosted WCF служба со следующим контрактом:
[ServiceContract] interface IMyService { [OperationContract] [WebInvoke(Method = "HEAD", UriTemplate = "Files/{fileName}")] void GetFileInfo(string fileName);
[OperationContract] [WebGet(UriTemplate = "Files/{fileName}")] Stream StreamFile(string fileName); }
Упрощённая реализация её такова:
class MyService : IMyService { public void GetFileInfo(string fileName) { string filePath = Path.Combine("Files", fileName); FileInfo fi = new FileInfo(filePath);
var response = WebOperationContext.Current.OutgoingResponse; response.ContentType = "application/octet-stream"; response.ContentLength = fi.Length; response.StatusCode = HttpStatusCode.OK; response.SuppressEntityBody = true; }
public Stream StreamFile(string fileName) { ... } }
Проблема в методе GetFileInfo. Когда происходит HEAD запрос к службе (например, с помощью WebRequest):
var uri = new Uri("http://localhost:8733/MyService/Files/test.dat"); var req = WebRequest.Create(uri); req.Method = "HEAD"; using (var resp = req.GetResponse() as HttpWebResponse) { Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription); foreach (string header in resp.Headers) Console.WriteLine("{0}: {1}", header, resp.Headers[header]); }
то в ответ приходит:
HTTP/1.1 200 OK Content-Length: 1234 Content-Type: application/octet-stream Date: Wed, 22 Jun 2016 10:17:38 GMT Server: Microsoft-HTTPAPI/2.0
но это в случае, если длина запрашиваемого файла не превышает int.MaxValue. Если же длина файла превышает int.MaxValue то Content-Length в ответе имеет значение 0:
Content-Length: 0
Как это победить? Как заставить возвращать нормальную длину для больших файлов?
Конфигурация WCF-службы (если это важно):


Ответ

Похоже, что это ошибка в коде System.ServiceModel, а конкретно - вот в этом участке. Интересно то, что проблема сохраняется и при хостинге сервиса в IIS.
Как вариант исправления - создать кастомный байндинг, наследующий от WebHttpBinding, с кастомным transport channel, и в нем организовать правильную расстановку заголовков у HttpListener (этот класс используется при self-хостинге сервисов с http-транспортом).
IMHO, это неоправданно сложно. Проще пойти на нарушение принципов RESTful-архитектуры и сделать запрос размера файла через POST с результатом в теле ответа. Или отправлять длину в другом заголовке.

Проблемные участки кода
// HttpChannelHelpers.cs, line 2988 if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0) { int contentLength = -1; if (httpMethodIsHead && int.TryParse(value, out contentLength)) { this.SetContentLength(contentLength); } // else //this will be taken care of by System.Net when we write to the content }
и
// HttpChannelHelpers.cs, line 3061 protected override void SetContentLength(int contentLength) { listenerResponse.ContentLength64 = contentLength; }

Комментариев нет:

Отправить комментарий