To raczej post informujący, bo ostatnio na kilku forach natrafiłem na to samo pytanie: czym i w jaki sposób może utworzyć i/lub przeczytać RSS/ATOM feed?

Odpowiedź jeszcze nie dawno nie była by taka prosta, ale ogólnie teraz jest :) Chłopaki od WCFa utworzyli specjalną przestrzeń nazw: System.ServiceModel.Syndication znajdującą się w bibliotece System.ServiceModel.dll. Dzięki klasom w niej zawartych jesteśmy wstanie nie tylko pobrać i przetworzyć feed z sieci, ale także utworzyć własnego RSS/ATOM dla naszej witryny.

Wszystko składa się na kilka prostych komend, i tak jak na przykład chcielibyśmy pobrać sobie feeda z pytaniami dot. C# to możemy napisać sobie taki o to fragment kodu:

string url = "http://devpytania.pl/feeds/tag/c%23";

SyndicationFeed feed = SyndicationFeed.Load(XmlReader.Create(url));

var items = from item in feed.Items
            orderby item.PublishDate descending
            select item;

Console.WriteLine(feed.Title.Text);

foreach (SyndicationItem item in items)
{
    Console.WriteLine("t{0}: {1}", item.PublishDate.Date.ToShortDateString(), item.Title.Text);
}

Console.WriteLine();

Sortowanie, które wykonuje nie jest niezbędne, ale dla przykładu mogę podać RSS dario-g, którego feedy z niewiadomych mi przyczyn wyświetlają się od końca – nie zależnie z jakiego framework (Google feeds API czy .NET) do pobierania RSSu korzystam. Więc ta operacja nie jest niezbędna ale może się przydać :)

Oczywiście można do tego podejść w inny sposób i na przykład załadować sobie feed za pomocą HttpWebRequest i potem pobrać HttpWebResponse i z response pobrać sobie strumień – ale to jest tak naprawdę nie ważne :) w jaki sposób i jak pobierzecie RSSa to już do was należy, jedyna rzecz jaka jest wymagana to, że musi być możliwość utworzenia z niego XmlReadera który jest jedynym parametrem jaki przyjmuje metoda Load od SyndicationFeed.

Zaś tworzenie własnego feeda jest banalnie proste ale linijko żerne:

SyndicationPerson person = new SyndicationPerson("[email protected]", "Gutek", "http://blog.gutek.pl");
SyndicationCategory category = new SyndicationCategory("pro");

List<SyndicationItem> items = new List<SyndicationItem>();
            
SyndicationItem item = new SyndicationItem();
item.Authors.Add(person);
item.Categories.Add(category);
item.Links.Add(SyndicationLink.CreateAlternateLink(new Uri("http://linkDoElementu")));
item.Summary = TextSyndicationContent.CreatePlaintextContent("dzis poruszymy temat cuuukierkow");
item.PublishDate = DateTimeOffset.Now;
item.Title = TextSyndicationContent.CreatePlaintextContent("Cukierki");
item.BaseUri = new Uri("http://linkDoElementu");
            
items.Add(item);
            
SyndicationFeed feed = new SyndicationFeed();
feed.Title = TextSyndicationContent.CreatePlaintextContent("Moj testowy feed");
feed.Description = TextSyndicationContent.CreatePlaintextContent("opis mojego feeda");
feed.Links.Add(SyndicationLink.CreateAlternateLink(new Uri("http://blog.gutek.pl")));
feed.Authors.Add(person);
feed.Categories.Add(category);
feed.Language = "pl-pl";
feed.Copyright = TextSyndicationContent.CreatePlaintextContent("a tam taka notka");
feed.Items = items;

XmlWriter writer = XmlWriter.Create(Console.Out, null);
feed.SaveAsRss20(writer);
//feed.SaveAsAtom10(writer);
writer.Flush();

Oczywiście ja tylko tak poruszyłem temat, w netcie można dużo więcej na ten temat znaleźć, część źródeł niestety zawiera błędne fragmenty kodu na przykład przypisanie do feed.Title bezpośrednio stringa co powoduje, że kod się nie kompiluje. Ale łatwo takie coś wychwycić na szczęście.

Fajnie zaś można się pobawić z LINQ na przykład gdzieś w sieci widziałem taki fragment kodu:

string[] urls = {
                    "http://feeds.feedburner.com/devblogi",
                    "http://feeds.feedburner.com/szymonpobiega",
                    "http://geekswithblogs.net/kobush/Rss.aspx"
                };
var items =
    from url in urls
    let feed = SyndicationFeed.Load(XmlReader.Create(url))
    from item in feed.Items
    select item;

foreach (SyndicationItem item in items.Take(5))
{
    Console.WriteLine("{0} : {1}",
        item.PublishDate.Date.ToShortDateString(),
        item.Title.Text);
}

Jedyny minus powyższego przykładu to taki, że pobieranie zawartości feeda działa wyłącznie synchronicznie (powyższy kod więc zajmie trochę czasu nim się wykona, teraz dodajmy tam jeszcze 20-30 dodatkowych adresów i możemy iść na kawę), więc jeżeli chcemy osiągnąć asynchroniczne pobieranie RSSów to trzeba trochę obudować funkcję pobierania feeda na przykład poprzez wspomniany wcześniej HttpWebRequest.

Jedynej rzeczy jakiej mi brakuje to możliwość określenia liczby elementów do pobrania, jednakże widząc przypadek Dario-g, nawet się trochę cieszę, że nie ma takiej możliwości :) Dzięki czemu nie robi się „wyjątku” dla jednego adresu, tylko trzeba takie samo podejście zastosować do wszystkich feedów.

Miałeś już okazję współpracować z SyndicationFeed w .NET? jakie są Twoje odczucia, może na rynku jest dostępna lepsza i sprawniejsza biblioteka?

1 KOMENTARZ

  1. Dzięki za komentarz, jesteś pierwszą obcą mi osobą, która przeczytała mój post :D a wracając do tematu: oczywiście mogłem skorzystać SyndicationFeed, ale wydaje mi się to w przypadku mojej aplikacji o wiele bardziej złożone od sposobu, który wykorzystałem. Jest on nieco ‘sztywny’, ale w aktualnej wersji ‘BlogMaker’ w 100% wystarczający.

Comments are closed.