Потоковая передача изображений с использованием HttpHandler

В течение долгого времени я заметил кое-что раздражающее при работе над проектами веб-приложений, использующими изображения на базе данных на моем локальном компьютере. Под локальным я подразумеваю, что это типичная среда с VS 2008 и SQL Server 2005 на моей рабочей станции. Всякий раз, когда я использую HttpHandler для отображения изображений на моем локальном компьютере, только некоторые изображения отображаются на каждой странице загрузки.

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

Вот обработчик:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class FeaturedHandler : IHttpHandler
{
    Business biz = new Business();

    public void ProcessRequest(HttpContext context)
    {
        if (context.Request.QueryString["ListingID"] != null)
        {
            int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);

            DataSet ds = biz.GetFeaturedImageByID(listingID);
            DataRow row = ds.Tables[0].Rows[0];
            byte[] featureImage = (byte[])row["Photo"];
            context.Response.ContentType = "image/jpeg";
            context.Response.OutputStream.Write(featureImage, 0, featureImage.Length);
        }
        else
            throw new ArgumentException("No ListingID parameter specified");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
} 

Я пытался использовать БД на отдельном сервере, но столкнулся с той же проблемой. Должен ли я использовать DataReader вместо этого?

ОБНОВЛЕНИЕ Я должен был использовать DataReader изначально, так как я читаю двоичные данные.

3 ответа

Решение

Я наконец получил все изображения для рендеринга, изменив значение свойства IsReusable на true:

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

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

Этим:

Всякий раз, когда я использую HttpHandler для отображения изображений на локальном компьютере, при каждой загрузке страницы отображается только часть изображений.

Вы имеете в виду, что одно и то же изображение появляется в местах, где должны появляться разные изображения, или что некоторые изображения появляются, а некоторые вообще не отображаются?

В вашем случае разница при переключении isReusable правда это new Business(); будет вызван один раз для нескольких изображений. Если isReusable ложь new Business(); будет вызываться один раз за изображение. Это означает, что если у вас есть несколько изображений на странице new Business(); будет вызываться несколько раз для этой конкретной страницы.

Также я настоятельно рекомендую изменить это:

if (context.Request.QueryString["ListingID"] != null)
{
    int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);

с:

string listingIdParam = context.Request.QueryString["ListingID"];
if (listingIdParam != null)
{
    int listingID = Convert.ToInt32(listingIdParam);

Это избавит вас от исключений нулевых ссылок, которые обычно появляются только при большой нагрузке. Также вышеизложенное предотвратит подачу неверного изображения в запрос, особенно когда isReusable имеет значение true.

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

Возможно размещение Business класс и его конструктор может пролить немного света. Также я предлагаю реализовать некоторую регистрацию ошибок, чтобы перехватывать исключения в обработчике и просматривать их.

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

Вам нужно будет обработать следующие http заголовки:

  • ETag
  • Истекает
  • Последнее изменение
  • If-Match
  • If-None-Match
  • If-Modified-Since
  • Если-Unmodified-С
  • Если-нет Modified-Since

Для примера обработчик http, который делает это, проверьте: http://code.google.com/p/talifun-web/wiki/StaticFileHandler

Другие вопросы по тегам