RSS figuruje dnes již na mnoha stránkách. Je několik způsobů, jak vystavit RSS feed – bohužel nejčastějším způsobem je výpis kódu ve formátu RSS na .aspx stránku. Existuje ale elegantnější a hlavně výkonnější řešení, v podobě vlastního HTTP handleru.

Co je to RSS?

Odpověď na tuto otázku v tomto článku nehledejte. Na Intervalu najdete celkem solidní informace o RSS, které by vám měli postačovat k pochopení poslání a syntaxe jednotlivých verzí RSS. Nebudu vás zde opět unavovat informacemi, které jste si už přečetli někde jinde. Pokud však se však v RSS problematice necítíte pevní v kramflecích, podívejte se například na článek RSS? RSS! a související.

Co je to ASP.NET HTTP handler

Tímto bych se zde ale trochu zabývat měl. Takzvaný ASP.NET HTTP handler je proces, který je spuštěn jako odpověď na požadavek na ASP.NET aplikaci. Nepochybně nejpoužívanější HTTP handlerem je handler obsluhující požadavek na .aspx stránku. Dalším poměrně často používaným handlerem je handler webové služby .asmx. Váš vlastní ASP.NET HTTP handler může mít jakoukoli příponu, ta ale musí být v IIS namapována tak, aby byl tento požadavek předán ASP.NET ke zpracování. Velmi často se pro vlastní handlery používá přípona .ashx. Pokud však máte možnost upravit nastavení IIS, bylo by docela pěkné pro účely diskutované v tomto dokumentu namapovat například příponu .rss na ASP.NET. Umožnilo by vám to tvořit například handlery reagující na požadavek ve tvaru novinky.rss nebo nejctenejsi.rss. Tímto se ale zabývat nebudu a pro demonstraci použiji příponu .ashx, která, co si budeme povídat, bude asi nejvíce využita. Už jen z toho důvodu, že ne každý má možnost upravovat nastavení IIS, protože málokterá hostingová společnost vás k němu pustí.

Proč HTTP handler

Ačkoli především v začínajících programátorech vyvolávají HTTP handlery respekt, není tvorba vlastního HTTP handleru vůbec složitá záležitost a přináší nám navíc několik nezanedbatelných výhod. Při použití této techniky máme absolutní kontrolu nad tím, co a jakým způsobem vypustíme do světa, a tudíž nezatěžujeme počítač a síť informacemi, které pro nás v tuto chvíli nejsou naprosto vůbec užitečné, ale které v sobě třída System.Web.UI.Page nese, ať chceme nebo ne. Pomocí vlastního HTTP handleru posíláme klientovi opravdu jen to, co se po nás chce.

Rozhraní IHttpHandler

Chceme-li si vytvořit vlastní třídu HTTP handleru, musíme implementovat rozhraní IHttpHander. Toto rozhraní definuje pouze dva členy, které musí třída implementovat. První je booleovská vlastnost IsReuseable, která indikuje, jestli může jiný proces využít instanci daného HTTP handleru. Druhým členem, který nám rozhraní IHttpHandler přikazuje vytvořit, je vlastně jádrem nového handleru. Je to metoda ProcessRequest(). Uvnitř této metody se nachází kód, který posílá do světa informace, jež jsou požadovány. Při tvorbě handleru máte přes parametr typu HttpContext metody ProcessRequest k dispozici většinu objektů, se kterými pracujete v klasické ASP.NET stránce, jako jsou Cache, Application, Session, konfigurační nastavení a další, můžete tedy využít prakticky všech možností, které se vám při tvorbě klasických ASP.NET stránek nabízejí.

Myslím, že pro naše účely jsme si připravili solidní základy a můžeme si předvést nějakou tu ukázku. Nejdříve vytvoříme jednoduchý ASP.NET HTTP handler, jehož výstupem je prostý text. Ukážeme si také dvě cesty, jakými se můžete vydat při tvorbě svých HTTP handlerů.

Jednoduchý HTTP handler

O pár řádků výše jsem slíbil, že vám ukážu dvě cesty, jak se dají vytvářet vlastní ASP.NET HTTP handlery. První z nich spočívá ve vytvoření souboru s příponou .ashx. Máte-li Visual Web Developer 2005, můžete najít v nabídce nových souborů položku Generic Handler. Využijete-li této možnosti, připraví VWD za vás kostru nové třídy:

<%@ WebHandler Language=“C#“ Class=“SimpleHandler“ %>
using System;
using System.Web;
public class SimpleHandler : IHttpHandler
{
 public void ProcessRequest (HttpContext context)
 {
  context.Response.ContentType = „text/html“;
  context.Response.Write(“ <html><body> Ahoj!!</body></html>“);
 }
 public bool IsReusable
 {
  get { return false; }
 }
}

Tato třída implementuje rozhraní IHttpHandler a zavádí oba členy, které toto rozhraní přikazuje použít. Pokud zavoláte tento handler, bude jeho výstupem pouze jednoduchý HTML kód.

Nyní zkusíme využít jiné techniky pro tvorbu ASP.NET HTTP handlerů. Vytvořte nový soubor SimpleHandler.cs (v ASP.NET 2.0 je vhodné ho umístit do složky App_Code) a vložte do něj kód uvedený výše, ovšem bez úvodní direktivy. V souboru web.config pak musíte tuto třídu handleru zaregistrovat a sdělit ASP.NET, jaký požadavek má na ni mapovat:

<configuration>
 <system.web>
  <httpHandlers>
   <add verb=“*“ path=“SimpleHandler.ashx“
    type=“SimpleHandler“ />
  </httpHandlers>
 <system.web>
</configuration>

Je jen na vás, který z postupů si vyberete. Já osobně jsem v tomto směru dost schizofrenní. První způsob, tedy fyzické soubory .ashx, volím především v případě jednoduššího handleru a pokud je počet souborů v projektu menší. Je to technika dle mého názoru přehlednější – nemusím zkoumat v několika souborech, co reaguje na který požadavek. V případě složitějšího projektu se však mohou dodatečné soubory na přehlednosti projevit spíše negativně. Tvorba handlerů v .cs souboru má svůj přínos především v ;tom, že můžete handler vytvořit jako samostatnou Class Library, zkompilovat a využívat ji ve více projektech jednodušším způsobem.

HTTP handler pro RSS feed

S tímto teoretickým i praktickým základem byste již při znalosti formátu RSS měli být schopni napsat svůj HTTP handler, jehož výstupem budou například novinky na vašem serveru.

První změnu, kterou musíme oproti předchozímu příkladu provést, je úprava ContentType na application/rss+xml. Poté ještě musíme vymodelovat XML dokument v duchu RSS a vypustit ho do světa. Přejděme tedy ke výslednému kódu:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Caching;
using System.Xml;
public class Rss : IHttpHandler
{
 public void ProcessRequest(HttpContext context)
 {
  context.Response.ContentType = „application/rss+xml“;
  context.Response.Write(„<?xml version=\“1.0\“ encoding=\“utf-8\“ ?>\r\n“);
  object rawFeed = HttpContext.Current.Cache[„RssFeed“];
  XmlDocument feed = rawFeed == null ? GetXmlFeed() : (XmlDocument)rawFeed;
  context.Response.Write(feed.InnerXml);
 }
 private XmlDocument GetXmlFeed()
 {
  XmlDocument doc = new XmlDocument();
  XmlElement root = doc.CreateElement(„rss“);
  XmlAttribute rootAttr = doc.CreateAttribute(„version“);
  rootAttr.Value = „0.91“;
  root.Attributes.Append(rootAttr);
  XmlElement channel = doc.CreateElement(„channel“);
  XmlElement title = doc.CreateElement(„title“);
  title.InnerText = ConfigurationManager.AppSettings[„SiteName“];
  channel.AppendChild(title);
  XmlElement link = doc.CreateElement(„link“);
  link.InnerText = ConfigurationManager.AppSettings[„BaseUrl“];
  channel.AppendChild(link);
  XmlElement description = doc.CreateElement(„description“);
  description.InnerText = „Výpis nejnovějších článků našeho magazínu.“;
  channel.AppendChild(description);
  XmlElement language = doc.CreateElement(„language“);
  language.InnerText = „cs“;
  channel.AppendChild(language);
  using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[„ConnectionString“].ConnectionString))
  {
   conn.Open();
   SqlCommand cmd = new SqlCommand();
   cmd.Connection = conn;
   cmd.CommandText = String.Format(„SELECT TOP {0} [ articleId], [title], [prepend] FROM [tbArticles] WHERE ORDER BY [articleId] DESC“, ConfigurationManager.AppSettings[„RssFeedArticlesCount“]);
   using (SqlDataReader sqlreader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
   {
    while (sqlreader.Read())
    {
     XmlElement item = doc.CreateElement(„item“);
     XmlElement itemTitle = doc.CreateElement(„title“);
     itemTitle.InnerText = (string)sqlreader[„title“];
     item.AppendChild(itemTitle);
     XmlElement itemDesc = doc.CreateElement(„description“);
     itemDesc.InnerText = (string)sqlreader[„prepend“];
     item.AppendChild(itemDesc);
     XmlElement itemLink = doc.CreateElement(„link“);
     itemLink.InnerText = String.Format(ConfigurationManager.AppSettings[„BaseUrl“] + „article.aspx?id={0}“, sqlreader[„articleId“]);
     item.AppendChild(itemLink);
     channel.AppendChild(item);
    }
   }
  }
  root.AppendChild(channel);
  doc.AppendChild(root);
  HttpContext.Current.Cache.Add(„RssFeed“, doc, null, DateTime.Now.AddHours(3), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
  return doc;
 }
 public bool IsReusable
 {
  get
  {
   return false;
  }
 }
}

Souhrn

Z tohoto článku byste si měli odnést především jiný pohled na tvorbu RSS v ASP.NET. Je opravdu zbytečné zatěžovat IIS požadavkem na .aspx stránku, když můžeme celkem snadno využít výkonnějšího způsobu. Dále bych byl rád, kdyby se o HTTP handlery začalo zajímat více programátorů. Věřím, že jsem vás přesvědčil, že vytvořit ASP.NET HTTP handler není nic složitého a že možností je opravdu mnoho.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět