Какой лучший способ обслуживать несколько двоичных файлов с помощью одного метода WebApi?

У меня есть метод ASP.NET MVC 4 Web Api, который получает список идентификаторов файлов и возвращает уменьшенные изображения для этих файлов.

Таким образом, клиент может передать список числовых идентификаторов (например, 10, 303, 29), а метод возвращает список, в котором ThumbnailImage выглядит примерно так:

class ThumbnailImage
{
    public int Id { get; set; }
    // Some other stuff
    public byte[] RawData { get; set; }
}

Причина, по которой вызывающий абонент переходит в список идентификаторов, а не делает один вызов для каждого элемента, должен надеяться быть очевидным - для загрузки могут быть десятки или сотни элементов, и я пытаюсь избежать всего HTTP-трафика, который необходимо загрузить их отдельно.

В настоящее время я использую RestSharp и JSON.NET, поэтому мои объекты ThumbnailImage передаются через провод как JSON. Это хорошо с точки зрения простоты кодирования, но JSON не является эффективным способом представления этих двоичных данных.

Итак, я думаю, что я должен вернуть необработанные байты в виде октетного потока... однако, хотя я могу легко сделать это для одного изображения, я не уверен, что это лучший способ сделать это для несколько изображений, особенно когда мне также нужно вернуть идентификатор и другую другую информацию для каждого файла. (Идентификатор требуется, поскольку результаты не обязательно будут возвращены в заданном порядке - и некоторые файлы могут отсутствовать).

Я мог бы просто написать все по частям в поток ответов, так что для каждого элемента я пишу идентификатор (соответствующим образом закодированный), за которым следует длина данных изображения, а затем сами данные изображения, а затем за ним следует тот же вещь для следующего элемента и т.д.

Затем вызывающий абонент просто продолжал чтение из потока до его исчерпания, делая предположения о кодировке (и длине!) идентификаторов и т.д.

Я думаю, что это сработает, но кажется неуклюжим - есть ли лучший способ?

Ответы

Ответ 1

ОК, здесь фрагмент кода, который, похоже, работает, используя MultipartContent, о котором упоминал KiranChalla. (Это всего лишь фиктивный пример, который показывает, как вернуть два файла разных типов в сочетании с JSON-кодированным "объектом" (который в этом случае является всего лишь списком целочисленных идентификаторов).

public HttpResponseMessage Get()
{
    var content = new MultipartContent();
    var ids = new List<int>() { 1, 2 };

    var objectContent = new ObjectContent<List<int>>(ids, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
    content.Add(objectContent);

    var file1Content = new StreamContent(new FileStream(@"c:\temp\desert.jpg", FileMode.Open));
    file1Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
    content.Add(file1Content);

    var file2Content = new StreamContent(new FileStream(@"c:\temp\test.txt", FileMode.Open));
    file2Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain");
    content.Add(file2Content);

    var response = new HttpResponseMessage();
    response.Content = content;
    return response;
}

Ответ 2

Одна из проблем, которую я вижу, заключается в том, что, исходя из количества отправленных изображений, вызывающий абонент должен настроить их значение тайм-аута. Если это было для книжного магазина, могло бы быть отправлено много изображений.

Что делать, если вы отправляете только обратные URL-адреса для каждого изображения и оставляете его вызывающему, чтобы получить фактическое изображение? Это означало бы немного больше трафика с несколькими вызовами, но вызывающий абонент получал информацию раньше, чем позже, а затем получал изображения на основе требования к вызывающему абоненту.

Я мог ошибаться, но я думал, что идея, лежащая в основе отдыха, заключалась в том, чтобы идентифицировать каждый ресурс и объединить кучу изображений и назвать этот ресурс. Просто мысль...

Ответ 3

Вы можете создать сжатый файл (например, ZIP файл) из всех миниатюр и отправить его обратно.

Затем вызывающему абоненту просто нужно разархивировать его в конец - отправка одного файла, содержащего несколько файлов, будет гораздо более приемлемой, чем отправка нескольких файлов в один поток.

Недостатком является то, что вы вряд ли сможете использовать кеширование (в зависимости от ваших шаблонов использования, конечно).