SimpleFeed 4.0.0

dotnet add package SimpleFeed --version 4.0.0
                    
NuGet\Install-Package SimpleFeed -Version 4.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SimpleFeed" Version="4.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SimpleFeed" Version="4.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SimpleFeed" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SimpleFeed --version 4.0.0
                    
#r "nuget: SimpleFeed, 4.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SimpleFeed@4.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SimpleFeed&version=4.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SimpleFeed&version=4.0.0
                    
Install as a Cake Tool

SimpleFeed

A rich and extremely tolerant .NET RSS and Atom feed parser — and, as of v4, writer. In production parsing wild real-world feeds hourly since ~2018.

The central objectives, unchanged since the beginning:

  1. Get as much information as possible from a feed — including the standard extensions (iTunes podcast tags, media RSS, Dublin Core, content:encoded, rawvoice), and Atom-namespaced elements appearing inside RSS feeds.

  2. Be extremely fault tolerant. Real-world feeds are wild: obsolete EST-style timezones, missing dates, malformed authors, bare www. links, spaces inside URLs, mis-declared encodings, garbage bytes. Parsing never throws — failures land as Error + Messages on the result, invalid pieces are skipped, absent dates report honestly as DateTimeOffset.MinValue.

  3. One set of types for both formats. A single model (SFFeed / SFFeedEntry) represents what was originally RSS or Atom — without losing the format-specific information (typed Atom texts, category schemes, rel values, the original declared mime-type string, …).

  4. v4 makes good on the old promise: serialization. The same model writes back out as clean, canonical RSS 2.0 or Atom 1.0 — so SimpleFeed can now unify any wild feed into one well-formed output.

Install

dotnet add package SimpleFeed

v4 targets .NET 10. (v3.x, targeting netstandard2.0/net6.0, lives on the master branch for legacy patch releases.)

Reading a feed

using SimpleFeed;

byte[] bytes = await httpClient.GetByteArrayAsync(feedUrl); // fetching is yours; SimpleFeed parses
SFFeed feed = SFFeed.Parse(bytes);

if(feed.Error) {
	Console.WriteLine(feed.Messages); // never throws — failures report here
	return;
}

Console.WriteLine($"{feed.Title} — {feed.Items.Count} entries ({feed.SourceFeedType})");

foreach(SFFeedEntry e in feed.Items) {
	Console.WriteLine($"{e.Published:d}  {e.Title}  by {e.Author}");

	SFLink web = e.GetFirstWebLink_AlternateWins(); // the tournament: picks "the" web link among many
	SFLink enclosure = e.GetFirstEnclosure();       // podcast audio, PDFs, images…

	if(enclosure != null)
		Console.WriteLine($"    enclosure: {enclosure.Url} ({enclosure.Type}, {enclosure.Length} bytes)");
}

Parse accepts byte[] (preferred — honors BOMs and the XML prolog's declared encoding) or string. It always returns a non-null SFFeed; check Error.

Settings

SFFeed feed = SFFeed.Parse(bytes, new SFFeedSettings() {
	AlterUTCDatesToThisTimezone = TimeZoneInfo.FindSystemTimeZoneById("America/New_York"),
	NumberOfEntriesToParseLimit = 25,
	KeepXmlDocument = true,             // retain the source XElements (off by default)
	ConvertContentUrlsToLinks = true,   // harvest bare urls out of body text into Links (marked DiscoveredLink)
	GenerateIdForEntriesWithNoId = (entry, idBase) => idBase + Guid.NewGuid(),
	AlterEntryOnComplete = entry => entry.Title == null ? null : entry, // returning null drops the entry
});

Writing a feed (new in v4)

SFFeed feed = SFFeed.Parse(bytes);   // any wild feed in…
string rss = feed.ToRssXml();        // …clean RSS 2.0 out
string atom = feed.ToAtomXml();      // …or clean Atom 1.0

Or build one from scratch:

SFFeed feed = new() {
	Title = "My Feed",
	Language = "en-us",
	Items = [
		new SFFeedEntry() {
			Id = "https://example.com/post/1",
			Title = "Hello",
			Published = DateTimeOffset.UtcNow,
			Content = "The body.",
		},
	],
};

string rss = feed.ToRssXml();

The writer carries the same spirit as the reader: it never throws over imperfect model state. Absent dates are omitted (never emitted as year 0001), XML-illegal characters are stripped, links the parser merely discovered in body text are excluded (opt-in via SFWriteSettings.IncludeDiscoveredLinks), library-generated guid prefixes are restored to their source form, inherited entry authors aren't duplicated onto every item, and the synthetic detection-only mime types (video/vimeo, video/youtube) are never emitted. Parse → write → reparse is a stable cycle, covered by the test suite.

Extension coverage

Extension Read
Atom elements inside RSS (atom:link, atom:published, atom:updated, atom:category)
iTunes podcast (author, subtitle, summary, keywords, image, duration, explicit, episode, season)
content:encoded (with the description-vs-content reconciliation RSS never specified)
Dublin Core (dc:creator, dc:date)
Media RSS (media:content, media:thumbnail)
rawvoice (metamark)
PubSubHubbub (rel="hub" / rel="self"SFFeed.Hub)

RSS 1.0/RDF is not supported (it errors cleanly).

v4 breaking changes (from v3.x)

v4 is a renewal release: .NET 10, a model/parser split, the write side, and zero dependencies (the last one, DotNetXtensions.Mini, is vendored internal as of 4.0 — only the micro string/LINQ helpers SimpleFeed actually uses, copied verbatim). The headlines:

  • Namespace is now SimpleFeed (was SimpleFeedNS).
  • SFFeed replaces the old SimpleFeed type: parse via static SFFeed.Parse(bytes) — no more constructing a feed and calling instance Parse. The result is always non-null; entries are on feed.Items (the old feed-is-an-IList face is gone).
  • The parse machinery that used to be public (RssItemToFeedEntry, AtomEntryToFeedEntry, SetItunes, …) is internal now; the public surface is the model + Parse + the write methods + the hook points.
  • BasicMimeType and friends moved into the SimpleFeed namespace (the DotNetXtensions.MimeTypes dependency was internalized).
  • Youtube/vimeo detection lives only in the SFAlterFeedLinks hook now (SFLink's detectYtubeVimeo constructor parameter is gone), under one conservative rule: a link's explicitly declared type is never overridden.
  • KeepXmlDocument now defaults to false.
  • Mutable global statics (LocalIdTag, rel dictionaries, XSimpleFeed defaults) are gone or frozen.
  • A dozen+ long-standing bugs were fixed — several change output (enclosure Length/Height/Width now carry real values; more categories and authors survive parsing; declared encodings decode correctly). Every fix, with before/after code: docs/2026-08-21-v4-bug-fixes.md.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.0 94 8/21/2026
3.6.0 1,881 8/26/2022
3.5.0 762 3/10/2022
3.4.0 656 3/9/2022
3.3.0 7,829 10/27/2020
3.2.0-beta.2 477 3/6/2020
3.2.0-beta.1 456 2/28/2020
3.1.1 878 6/18/2019
3.1.0 776 6/17/2019
3.0.1 803 5/17/2019