Argotic.Core 4000.0.6

dotnet add package Argotic.Core --version 4000.0.6
                    
NuGet\Install-Package Argotic.Core -Version 4000.0.6
                    
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="Argotic.Core" Version="4000.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Argotic.Core" Version="4000.0.6" />
                    
Directory.Packages.props
<PackageReference Include="Argotic.Core" />
                    
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 Argotic.Core --version 4000.0.6
                    
#r "nuget: Argotic.Core, 4000.0.6"
                    
#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 Argotic.Core@4000.0.6
                    
#: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=Argotic.Core&version=4000.0.6
                    
Install as a Cake Addin
#tool nuget:?package=Argotic.Core&version=4000.0.6
                    
Install as a Cake Tool

Argotic.Core

The main package of the Argotic Syndication Framework — read, write and manipulate web content syndication feeds in .NET. This is the package most people install.

Supports RSS, Atom, OPML, APML, BlogML, RSD and Sitemap/SitemapIndex, a format-agnostic GenericSyndicationFeed wrapper, the Atom Publishing Protocol, and Trackback and XML-RPC clients.

Install

dotnet add package Argotic.Core

Target framework: net10.0. Requires the .NET 10 SDK or later. Earlier targets (.NET Standard 2.0/2.1, .NET 8, .NET 9) are not supported by this release.

Argotic.Core pulls in Argotic.Common and Argotic.Extensions transitively — you do not need to install them separately.

30-second start

using Argotic.Syndication;

RssFeed feed = await RssFeed.CreateAsync(new Uri("https://endjin.com/rss.xml"));

Console.WriteLine(feed.Channel.Title);
Console.WriteLine(feed.Channel.Description);

foreach (RssItem item in feed.Channel.Items)
{
    Console.WriteLine($"{item.PublicationDate:yyyy-MM-dd}  {item.Title}  {item.Link}");
}

What is in the package

Type Namespace Format
RssFeed, RssChannel, RssItem Argotic.Syndication RSS 2.0
AtomFeed, AtomEntry Argotic.Syndication Atom 1.0
OpmlDocument, OpmlOutline Argotic.Syndication OPML 2.0
Sitemap, SitemapUrl, SitemapIndex, SitemapIndexEntry Argotic.Syndication Sitemaps 0.9
GenericSyndicationFeed, GenericSyndicationItem, GenericSyndicationCategory Argotic.Syndication RSS or Atom, format-agnostic
ApmlDocument Argotic.Syndication APML 1.0
BlogMLDocument Argotic.Syndication BlogML 2.0
RsdDocument Argotic.Syndication RSD 1.0
AtomServiceDocument, AtomCategoryDocument, AtomEntryResource, AtomWorkspace, AtomMemberResources Argotic.Publishing Atom Publishing Protocol (RFC 5023)
TrackbackClient, TrackbackMessage, XmlRpcClient, XmlRpcMessage Argotic.Net Trackback, XML-RPC
ServiceCollectionExtensions, ArgoticHttpClients Argotic.Configuration Dependency injection

One shape, every format

Every resource type exposes the same members, so what you learn for RssFeed reads across to AtomFeed, OpmlDocument, Sitemap, ApmlDocument, BlogMLDocument, RsdDocument and the Atom Publishing documents unchanged.

// Synchronous, from something already in hand
void Load(IXPathNavigable source [, SyndicationResourceLoadSettings? settings]);
void Load(Stream stream          [, SyndicationResourceLoadSettings? settings]);
void Load(XmlReader reader       [, SyndicationResourceLoadSettings? settings]);

// Asynchronous, from a URL
Task LoadAsync(Uri source, CancellationToken cancellationToken = default);
Task LoadAsync(Uri source, HttpClient httpClient,
               SyndicationResourceLoadSettings? settings = null,
               SyndicationRequestOptions? requestOptions = null,
               CancellationToken cancellationToken = default);

// One-call static factory — the same two overloads, but constructing the instance for you
static Task<T> CreateAsync(Uri source, SyndicationResourceLoadSettings? settings = null,
                           CancellationToken cancellationToken = default);
static Task<T> CreateAsync(Uri source, HttpClient httpClient, …);

// Writing
void Save(Stream stream    [, SyndicationResourceSaveSettings? settings]);
void Save(XmlWriter writer [, SyndicationResourceSaveSettings? settings]);

// Plus
XPathNavigator CreateNavigator();
event EventHandler<SyndicationResourceLoadedEventArgs> Loaded;

CreateAsync is the one-call form. LoadAsync on an instance is the form that lets you subscribe to Loaded before the parse happens.

Loading from a stream, a reader or a navigator

using System.Xml;
using System.Xml.XPath;
using Argotic.Common;
using Argotic.Syndication;

RssFeed feed = new();

// From a Stream
using (Stream stream = File.OpenRead("feed.xml"))
{
    feed.Load(stream);
}

// From an XmlReader
using (XmlReader reader = XmlReader.Create("feed.xml", SyndicationEncodingUtility.CreateSafeXmlReaderSettings()))
{
    feed.Load(reader);
}

// From anything IXPathNavigable
using (XmlReader reader = XmlReader.Create("feed.xml", SyndicationEncodingUtility.CreateSafeXmlReaderSettings()))
{
    feed.Load(new XPathDocument(reader));
}

SyndicationEncodingUtility.CreateSafeXmlReaderSettings() returns the hardened reader configuration the framework uses internally — prefer it to a bare XmlReader.Create(path) when the XML is not yours.

Building and saving a feed

using System.Globalization;
using System.Xml;
using Argotic.Syndication;

RssFeed feed = new()
{
    Channel =
    {
        Title = "Dallas Times-Herald",
        Link = new Uri("https://dallas.example.com"),
        Description = "Current headlines from the Dallas Times-Herald newspaper",
        Language = new CultureInfo("en-US"),
        Copyright = "Copyright 2026 Dallas Times-Herald",
    },
};

RssItem item = new()
{
    Title = "Seventh Heaven! Ryan Hurls Another No Hitter",
    Link = new Uri("https://dallas.example.com/1991/05/02/nolan.htm"),
    Description = "Nolan Ryan hurled the seventh no-hitter of his career.",
    PublicationDate = DateTime.UtcNow,
    Guid = new RssGuid("https://dallas.example.com/1991/05/02/nolan.htm"),
};

item.Categories.Add(new RssCategory("sports"));
item.Enclosures.Add(new RssEnclosure(24_986_239L, "audio/mpeg", new Uri("https://dallas.example.com/joebob.mp3")));

feed.Channel.Items.Add(item);

// To a Stream…
using (Stream stream = File.Create("feed.xml"))
{
    feed.Save(stream);
}

// …or through an XmlWriter you configure
using (XmlWriter writer = XmlWriter.Create("feed.xml", new XmlWriterSettings { Indent = true }))
{
    feed.Save(writer);
}

Atom is the same shape with Atom's vocabulary:

using Argotic.Syndication;

AtomFeed feed = new()
{
    Id = new AtomId(new Uri("urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6")),
    Title = new AtomTextConstruct("Example Feed"),
    UpdatedOn = DateTime.UtcNow,
};

feed.Links.Add(new AtomLink(new Uri("https://example.org/")));
feed.Links.Add(new AtomLink(new Uri("/feed", UriKind.Relative), "self"));
feed.Authors.Add(new AtomPersonConstruct("John Doe"));

feed.Entries.Add(new AtomEntry
{
    Id = new AtomId(new Uri("urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a")),
    Title = new AtomTextConstruct("Atom-Powered Robots Run Amok"),
    UpdatedOn = DateTime.UtcNow,
    Summary = new AtomTextConstruct("Some text."),
});

Reading a feed without knowing its format

GenericSyndicationFeed exposes only what RSS and Atom agree on — title, description, categories, items — and hands back the underlying RssFeed or AtomFeed through Resource when you need the rest.

using Argotic.Common;
using Argotic.Syndication;

GenericSyndicationFeed feed = await GenericSyndicationFeed.CreateAsync(new Uri("https://endjin.com/rss.xml"));

foreach (GenericSyndicationItem item in feed.Items)
{
    if (item.PublishedOn > DateTime.UtcNow.AddDays(-7))
    {
        Console.WriteLine(item.Title);

        foreach (GenericSyndicationCategory category in item.Categories)
        {
            Console.WriteLine($"  #{category.Term}");
        }
    }
}

if (feed.Format == SyndicationContentFormat.Rss && feed.Resource is RssFeed rss)
{
    // Reach for RSS-only members such as rss.Channel.TimeToLive.
}

Sitemaps

using Argotic.Syndication;

Sitemap sitemap = new();

sitemap.Urls.Add(new SitemapUrl
{
    Location = new Uri("https://www.example.com/"),
    LastModified = DateTime.UtcNow,
    ChangeFrequency = SitemapChangeFrequency.Daily,
    Priority = 1.0m,
});

using Stream stream = File.Create("sitemap.xml");
sitemap.Save(stream);

For a site too large for one file, a SitemapIndex points at the individual sitemaps:

SitemapIndex index = new();
index.Sitemaps.Add(new SitemapIndexEntry(new Uri("https://www.example.com/sitemap-1.xml"), DateTime.UtcNow));

Google's News, Image, Video and Hreflang sitemap extensions ship in Argotic.Extensions, which arrives with this package.

HTTP: the shared client, timeouts and cancellation

A single process-wide HttpClientSyndicationEncodingUtility.SharedHttpClient, a Lazy<HttpClient> over a SocketsHttpHandler that rotates its own pooled connections — backs every overload that does not take a client of its own.

Timeouts do not come from HttpClient.Timeout. The shared client is deliberately built with Timeout.InfiniteTimeSpan, so reading its Timeout tells you nothing. Deadlines are enforced with CancellationTokenSource.CancelAfter, which means they cover the whole load — the response body included — and not merely the point at which the headers arrive. The default is SyndicationEncodingUtility.DefaultRequestTimeout, 100 seconds.

using Argotic.Common;
using Argotic.Syndication;

SyndicationResourceLoadSettings settings = new()
{
    Timeout = TimeSpan.FromSeconds(20),   // null means *no* deadline, not "use the default"
    RetrievalLimit = 50,                  // cap the items parsed; 0 means unlimited
    MaxResponseContentLength = 8 * 1024 * 1024,
};

SyndicationRequestOptions options = new()
{
    UserAgent = "MyAggregator/1.0 (+https://example.com/bot)",
    Accept = "application/rss+xml, application/atom+xml;q=0.9",
};

using HttpClient client = new();

RssFeed feed = new();
await feed.LoadAsync(new Uri("https://endjin.com/rss.xml"), client, settings, options, cancellationToken);

Dependency injection

Register the named client Argotic's loads should use, then hand the resolved client to LoadAsync. A syndication resource is constructed, not resolved — you write new RssFeed(), you do not ask the container for one — so the client is registered by name rather than as a typed client.

using Argotic.Configuration;
using Microsoft.Extensions.DependencyInjection;

services.AddArgoticSyndicationClient();

// …later, wherever you load a feed
IHttpClientFactory factory = provider.GetRequiredService<IHttpClientFactory>();
HttpClient client = factory.CreateClient(ArgoticHttpClients.Syndication);

RssFeed feed = await RssFeed.CreateAsync(source, client, cancellationToken: cancellationToken);

Always use the ArgoticHttpClients.Syndication constant, never the literal string: a named client is looked up by name, so a typo is not a compile error — the factory hands back a brand-new, entirely default HttpClient and every decision you configured is quietly absent.

AddXmlRpcClient and AddTrackbackClient register the two protocol clients with options binding.

Conditional GET

Poll a feed without re-downloading it when nothing changed.

using Argotic.Common;
using Argotic.Syndication;

Uri source = new("https://endjin.com/rss.xml");

// Both come from your store, recorded by the previous poll.
DateTime lastModified = previousLastModified;   // DateTime.MinValue on the first ever poll
string? entityTag = previousETag;               // null if the origin sent no ETag

using ConditionalGetResult result =
    await SyndicationDiscoveryUtility.ConditionalGetAsync(source, lastModified, entityTag);

if (result.WasModified)
{
    using Stream stream = await result.GetResponseStreamAsync();

    RssFeed feed = new();
    feed.Load(stream);

    // Persist result.LastModified and result.ETag for the next poll.
}

The Loaded event

Every resource raises Loaded after a successful parse — synchronous or asynchronous — and not at all when one throws. Subscribe on an instance and call LoadAsync on it, rather than using CreateAsync, when you want the handler to see the resource the moment it is parsed. The event arguments carry the XPathNavigator the resource was built from, and a Source only where the load began with a Uri — the stream and reader overloads have never known one.

using Argotic.Common;
using Argotic.Syndication;

RssFeed feed = new();
feed.Loaded += (sender, e) =>
{
    if (e.Source is not null)
    {
        Console.WriteLine($"Loaded from {e.Source}");
    }
};

await feed.LoadAsync(new Uri("https://endjin.com/rss.xml"));

Atom Publishing Protocol

using Argotic.Publishing;

AtomServiceDocument service = await AtomServiceDocument.CreateAsync(new Uri("https://example.com/atomsvc"));

foreach (AtomWorkspace workspace in service.Workspaces)
{
    foreach (AtomMemberResources collection in workspace.Collections)
    {
        Console.WriteLine($"{workspace.Title.Content}: {collection.Uri}");
    }
}

AtomCategoryDocument and AtomEntryResource follow the same CreateAsync/Load/Save shape.

Trackback and XML-RPC

using System.Text;
using Argotic.Net;

TrackbackClient trackback = new() { Host = new Uri("https://www.example.com/trackback/5") };

TrackbackMessage message = new(new Uri("https://www.mysite.com/post"))
{
    Encoding = Encoding.UTF8,
    WeblogName = "My Weblog",
    Title = "My Post",
    Excerpt = "An excerpt.",
};

TrackbackResponse response = await trackback.SendAsync(message);
using System.Text;
using Argotic.Net;

XmlRpcClient rpc = new() { Host = new Uri("https://bob.example.net/xmlrpcserver") };

XmlRpcMessage ping = new("pingback.ping") { Encoding = Encoding.UTF8 };
ping.Parameters.Add(new XmlRpcScalarValue("https://alice.example.org/#p123"));  // sourceURI
ping.Parameters.Add(new XmlRpcScalarValue("https://bob.example.net/#foo"));     // targetURI

XmlRpcResponse response = await rpc.SendAsync(ping);

Extensions

27 syndication extensions across 22 families — iTunes, Podcasting 2.0, Dublin Core, Yahoo Media, GeoRSS, Creative Commons, the Google sitemap extensions and more — ship in Argotic.Extensions, which this package already references. They are auto-detected on load from the XML namespaces declared on the document, and the namespace declarations written back on save are derived from the extensions actually present.

using Argotic.Extensions;
using Argotic.Extensions.Core;
using Argotic.Syndication;

if (feed.Channel.FindExtension(ITunesSyndicationExtension.MatchByType) is ITunesSyndicationExtension itunes)
{
    Console.WriteLine(itunes.Context.Author);
    Console.WriteLine(itunes.Context.Summary);
}

See the Argotic.Extensions README for the full family table, how to attach an extension before saving, and how to write your own.

Dependency chain

Argotic.Common                 (no package dependencies)
    ^
Argotic.Extensions             (references Common)
    ^
Argotic.Core                   (references Common, Extensions)  <- you are here

Argotic.Core additionally references Microsoft.Extensions.Http, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions and Microsoft.Extensions.DependencyInjection.Abstractions.

Licence and provenance

Licensed under Apache-2.0.

The Argotic Syndication Framework was created in 2007 by Brian William Kuhn. It is now maintained by endjin, and is used in production to build the Azure Weekly, Microsoft Fabric Weekly and Power BI Weekly newsletters.

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.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on Argotic.Core:

Package Downloads
Bam.Net.Syndication

Bam extensions to Argotic based rss and atom feeds

Articulate

A wonderful Blog engine built on Umbraco

Argotic.Web

A powerful and extensible .NET web content syndication framework for RSS, Atom, OPML, APML, BlogML, RSD and more. The Argotic Syndication Framework is a Microsoft .NET class library framework that enables developers to easily consume and/or generate syndicated content from within their own applications. The framework makes the reading and writing syndicated content in common formats such as RSS, Atom, OPML, APML, BlogML, and RSD very easy while still remaining extensible enough to support common/custom extensions to the syndication publishing formats. The framework includes out-of-the-box implementations of the most commonly used syndication extensions, network clients for sending and receiving peer-to-peer notification protocol messages; as well as HTTP handlers, modules, services and controls that provide rich syndication functionality to ASP.NET developers.

Bryan.Apellanes

MVC 4 Extensions and Productivity Tools

Brevitee.Syndication

Tools for programmatically interacting with command line git and TFS source control

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on Argotic.Core:

Repository Stars
Shazwazza/Articulate
A wonderful Blog engine built on Umbraco
Version Downloads Last Updated
4000.0.6 189 8/13/2026
4000.0.5 88 8/13/2026
4000.0.4 135 8/12/2026
4000.0.3 84 8/12/2026
4000.0.2 130 8/10/2026
4000.0.1 103 8/10/2026
3001.0.0 41,253 11/21/2024
3000.0.5 21,608 4/18/2023
3000.0.3 89,664 11/13/2021
3000.0.2 794 10/28/2021
3000.0.1 27,485 2/24/2021
3000.0.0 2,122 3/12/2020
2008.0.2 158,312 1/7/2011