Потоковая передача изображений с использованием 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