Статьи

Призрак SyndicationFeed

Итак, давайте поговорим о чтении RSS-каналов в .NET-приложении. Когда кто-то упоминает RSS или Atom, я автоматически считаю SyndicationFeed краеугольным камнем решения. Действительно, это приемлемый объект для большинства случаев. Или это?

Недавно я получил электронное письмо от человека, который тестировал мой RSS-ридер для Windows Phone 7 (вы можете прочитать об этом здесь и здесь ). Он работал нормально для большинства каналов, но не для этого:

http://feeds.feedburner.com/LeadStoriesFromAol

Я уверен, что это не единственный канал, который может вызвать проблемы, но он был включен в отчет, поэтому я решил проверить его. Когда пользователь предоставил этот канал для приобретения, приложение упало, выдав ошибку:

образ

Глубокая проблема заключается в неправильно отформатированной дате, присутствующей в элементе фида (или нескольких элементах в этом отношении). Интересно, что это было не так для многих других каналов, которые были проверены мной, когда я выпустил проект. Человек, написавший мне электронное письмо, ссылался на этот вопрос в StackOverflow — кто-то уже сообщал об этой проблеме. Очевидно, об этом также сообщалось в Microsoft Connect . Тем не менее, он помечен как закрытый (фиксированный) .

образ

Но это даже не близко к тому, чтобы быть фактически исправленным — я создал пример проекта .NET 4.0, и проблема сохраняется. Возможно, была исправлена ​​другая сторона проблемы, но неверная дата, переданная внутри канала, по-прежнему вызывает сбой.

Как правило, в моем устройстве для чтения RSS я бы использовал WebClient для загрузки строки канала и затем анализировал ее через SyndicationFeed . Я бы вызвал событие DownloadStringCompleted и использовал следующий код:

XmlReader reader = XmlReader.Create(new StringReader(e.Result));
SyndicationFeed feed = SyndicationFeed.Load(reader);
foreach (SyndicationItem sItem in feed.Items)
{
if ((sItem != null) && (sItem.Summary != null) && (sItem.Title != null))
{
App.Model.FeedItems.Add(
new ViewModel.ItemModel()
{
ItemDetails = sItem.Summary.Text,
ItemTitle = sItem.Title.Text,
ItemLink = sItem.Links[0].Uri.ToString()
}
);
}
} 

Но поскольку ошибка неизбежна для недопустимых потоков, я решил ее устранить и использовать вместо нее XDocument . С помощью простого запроса LINQ я извлекаю необходимые данные и передаю их в мою модель представления .

XDocument document = XDocument.Parse(e.Result);
var x = from c in document.Root.Element("channel").Elements("item") select c;
foreach (XElement unit in x)
{
App.Model.FeedItems.Add(
new ViewModel.ItemModel()
{
ItemDetails = unit.Element("description").Value,
ItemTitle = unit.Element("title").Value,
ItemLink = unit.Element("link").Value
}
);
} 

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

Я обновил свой проект для чтения фидов WP7, и вы можете скачать новый источник здесь . Я попытался выделить части кода, которые были изменены, чтобы избежать ошибки.