Потоковая обработка изображений с использованием 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 вместо этого?
UPDATE
Я должен был использовать DataReader изначально, так как я читаю двоичные данные.
Ответы
Ответ 1
Наконец, я получил все изображения для рендеринга, изменив значение свойства IsReusable на true:
public bool IsReusable
{
get
{
return true;
}
}
По-видимому, это удерживает обработчик в памяти и способно обрабатывать несколько запросов. Когда установлено значение false, ему нужно было создать новый экземпляр обработчика для каждого входящего запроса.
Ответ 2
Таким образом:
Всякий раз, когда я использую HttpHandler для отображать изображения на моем локальном, только часть изображений, отображаемых на каждом Загрузка страницы.
Вы имеете в виду, что одно и то же изображение появляется в местах, где должны отображаться разные изображения или появляются некоторые изображения, а некоторые вообще не отображаются?
В вашем случае разница при переключении isReusable
в true заключается в том, что new Business();
будет вызываться один раз для нескольких изображений. Если isReusable
false, 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 является истинным.
Я не могу определить, в чем проблема, но я могу определенно сказать, что установка флага isReusable была всего лишь обходным решением и не устраняет вашу проблему. Также, когда подобная проблема воспроизводится только в определенной среде, это означает, что либо это проблема потока, либо есть некоторая разница в обработке запросов (другой веб-сервер - IIS6, IIS7, сервер разработки).
Возможно публикация класса Business
, и конструктор может пролить некоторый свет.
Кроме того, я предлагаю внедрить некоторую регистрацию ошибок для исключения ошибок в обработчике и их просмотра.
Ответ 3
Если вы обслуживаете изображения напрямую, не забудьте установить правильные заголовки кеширования, т.е. etags и срок действия. Если вы этого не сделаете, вы действительно сильно ударяете свою базу данных и используете свою пропускную способность.
Вам нужно будет обрабатывать следующие заголовки http:
- ETag
- Истекает
- Last-Modified
- Если-Match
- If-None-Match
- If-Modified-Since
- Если-Unmodified-С
- Unless-Modified-Since
Для примера обработчик http, который делает это:
http://code.google.com/p/talifun-web/wiki/StaticFileHandler