### Install Wiki Client Library Packages Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Install the core WCL package and optional extensions using NuGet Package Manager Console or the .NET CLI. ```powershell # Package Manager Console Install-Package CXuesong.MW.WikiClientLibrary Install-Package CXuesong.MW.WikiClientLibrary.Wikibase Install-Package CXuesong.MW.WikiClientLibrary.Flow # .NET CLI dotnet add package CXuesong.MW.WikiClientLibrary dotnet add package CXuesong.MW.WikiClientLibrary.Wikibase dotnet add package CXuesong.MW.WikiClientLibrary.Flow ``` -------------------------------- ### Install WikiClientLibrary Package Source: https://github.com/cxuesong/wikiclientlibrary/blob/master/README.md Use these commands to install the main WikiClientLibrary package via Package Management Console or .NET CLI. ```powershell # Package Management Console Install-Package CXuesong.MW.WikiClientLibrary ``` ```bash # .NET CLI dotnet add package CXuesong.MW.WikiClientLibrary ``` -------------------------------- ### Connect to a MediaWiki Site Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Create a WikiSite instance to represent a MediaWiki installation. Ensure site initialization is awaited before performing operations. ```csharp using WikiClientLibrary.Sites; var client = new WikiClient { ClientUserAgent = "MyBot/1.0" }; // Standard construction — must await Initialization before use var site = new WikiSite(client, "https://en.wikipedia.org/w/api.php"); await site.Initialization; Console.WriteLine(site.SiteInfo.SiteName); // "Wikipedia" Console.WriteLine(site.SiteInfo.Generator); // "MediaWiki 1.xx.x" Console.WriteLine(site.AccountInfo.Name); // current user (IP if anonymous) Console.WriteLine($"{site.Namespaces.Count} namespaces"); Console.WriteLine($"{site.Extensions.Count} extensions"); // Alternatively use the static factory method var site2 = await WikiSite.CreateAsync(client, "https://test2.wikipedia.org/w/api.php"); // For FANDOM / Wikia sites use WikiaSite for extra Wikia-specific support // var site = new WikiaSite(client, "https://community.fandom.com/api.php"); // await site.Initialization; ``` -------------------------------- ### C# Example: Hello Wiki World Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Getting-started Demonstrates a comprehensive workflow including client creation, site connection, user login, page content retrieval, editing, and logout. Ensure you have the necessary using directives for MediaWiki API operations. ```csharp static async Task HelloWikiWorld() { // Create a MediaWiki API client. var wikiClient = new WikiClient { // UA of Client Application. The UA of WikiClientLibrary will // be append to the end of this when sending requests. ClientUserAgent = "ConsoleTestApplication1/1.0", }; // Create a MediaWiki Site instance with the URL of API endpoint. var site = await WikiSite.CreateAsync(wikiClient, "https://test2.wikipedia.org/w/api.php"); // Access site information via WikiSite.SiteInfo Console.WriteLine("API version: {0}", site.SiteInfo.Generator); // Access user information via WikiSite.UserInfo Console.WriteLine("Hello, {0}!", site.AccountInfo.Name); // Site login Console.WriteLine("We will edit [[Project:Sandbox]]."); if (Confirm($"Do you want to login into {site.SiteInfo.SiteName}?")) { LOGIN_RETRY: try { await site.LoginAsync(Input("User name"), Input("Password")); } catch (OperationFailedException ex) { Console.WriteLine(ex.ErrorMessage); goto LOGIN_RETRY; } Console.WriteLine("You have successfully logged in as {0}.", site.AccountInfo.Name); Console.WriteLine("You're in the following groups: {0}.", string.Join(",", site.AccountInfo.Groups)); } // Page Operations // Fetch information and content var page = new WikiPage(site, site.SiteInfo.MainPage); Console.WriteLine("Retriving {0}...", page); await page.RefreshAsync(PageQueryOptions.FetchContent); Console.WriteLine("Last touched at {0}.", page.LastTouched); Console.WriteLine("Last revision {0} by {1} at {2}.", page.LastRevisionId, page.LastRevision.UserName, page.LastRevision.TimeStamp); Console.WriteLine("Content length: {0} bytes ----------", page.ContentLength); Console.WriteLine(page.Content); // Purge the page if (await page.PurgeAsync()) Console.WriteLine(" The page has been purged successfully."); // Edit the page page = new WikiPage(site, "Project:Sandbox"); await page.RefreshAsync(PageQueryOptions.FetchContent); if (!page.Exists) Console.WriteLine("Warning: The page {0} doesn't exist.", page); page.Content += "\n\n'''Hello''' ''world''!"; await page.UpdateContentAsync("Test edit from WikiClientLibrary."); Console.WriteLine("{0} has been saved. RevisionId = {1}.", page, page.LastRevisionId); // Find out more operations in WikiPage class, such as // page.MoveAsync() // page.DeleteAsync() // Logout await site.LogoutAsync(); Console.WriteLine("You have successfully logged out."); } ``` -------------------------------- ### Setup WikiClient and WikiSite Loggers Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Common]-Logging Assign an ILogger instance created from an ILoggerFactory to the Logger property of WikiClient and WikiSite objects to enable logging. ```csharp ILoggerFactory loggerFactory = ...; // Set up your LoggerFactory here. var client = new WikiClient { Logger = loggerFactory.CreateLogger("WikiClient") }; var site = new WikiSite("https://en.wikipedia.org/w/api.php") { Logger = loggerFactory.CreateLogger("enwp") }; ``` -------------------------------- ### Initialize WikiClient, WikiSite, and Use Generators Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Generators Provides a comprehensive example of initializing `WikiClient` and `WikiSite`, then using `AllPagesGenerator` to list pages and `CategoryMembersGenerator` to list subcategories. It demonstrates fetching page details like content length and last touched date. ```csharp static async Task HelloWikiGenerators() { // Create a MediaWiki API client. var wikiClient = new WikiClient(); // Create a MediaWiki site instance. var site = await WikiSite.CreateAsync(wikiClient, "https://en.wikipedia.org/w/api.php"); // List all pages starting from item "Wiki", without redirect pages. var allpages = new AllPagesGenerator(site) { StartTitle = "Wiki", RedirectsFilter = PropertyFilterOption.WithoutProperty }; // Take the first 1000 results var pages = await allpages.EnumPagesAsync().Take(1000).ToList(); foreach (var p in pages) Console.WriteLine("{0, -30} {1, 8}B {2}", p, p.ContentLength, p.LastTouched); // List the first 10 subcategories in Category:Cats Console.WriteLine(); Console.WriteLine("Cats"); var catmembers = new CategoryMembersGenerator(site, "Category:Cats") { MemberTypes = CategoryMemberTypes.Subcategory }; pages = await catmembers.EnumPagesAsync().Take(10).ToList(); foreach (var p in pages) Console.WriteLine("{0, -30} {1, 8}B {2}", p, p.ContentLength, p.LastTouched); } ``` -------------------------------- ### Example Scope-Enabled Logger Output Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Common]-Logging This is an example of the output from scope-enabled loggers, which includes contextual information about the operation, site, and page. ```text Debug: WikiClientLibrary.Sites.WikiSite -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() Edit: Wikipedia:Sandbox#51235807: Waiting for delay 00:00:05. Debug: WikiClientLibrary.Sites.WikiSite -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() -> Wikipedia -> ::FetchTokenAsyncCore(csrf) Sending request 452849D100000008, SuppressAccountAssertion=True Trace: WikiClientLibrary.Client.WikiClient -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() -> Wikipedia -> ::FetchTokenAsyncCore(csrf) -> WikiClient#17363659 -> ::InvokeAsync(452849D100000008) Initiate request to: https://test2.wikipedia.org/w/api.php. Trace: WikiClientLibrary.Client.WikiClient -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() -> Wikipedia -> ::FetchTokenAsyncCore(csrf) -> WikiClient#17363659 -> ::InvokeAsync(452849D100000008) HTTP 200, elapsed: 00:00:00.3663925 Debug: WikiClientLibrary.Sites.WikiSite -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() Sending request 452849D100000007, SuppressAccountAssertion=False Trace: WikiClientLibrary.Client.WikiClient -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() -> WikiClient#17363659 -> ::InvokeAsync(452849D100000007) Initiate request to: https://test2.wikipedia.org/w/api.php. Trace: WikiClientLibrary.Client.WikiClient -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() -> WikiClient#17363659 -> ::InvokeAsync(452849D100000007) HTTP 200, elapsed: 00:00:00.5573600 Information: WikiClientLibrary.Sites.WikiSite -> Wikipedia -> WikiPage{Wikipedia:Sandbox}::UpdateContentAsync() Edited page. New revid=329827. ``` -------------------------------- ### List All Pages with AllPagesGenerator Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Generators Shows how to use `AllPagesGenerator` to iterate through all pages in a specific namespace, starting from a given title. It demonstrates fetching page content and handling enumeration with a `CancellationToken`. ```csharp static async Task ShowAllTemplatesAsync() { var generator = new AllPagesGenerator(myWikiSite) { StartTitle = "A", NamespaceId = BuiltInNamespaces.Template, PaginationSize = 50 }; // You can specify EnumPagesAsync(PageQueryOptions.FetchContent), // if you are interested in the content of each page using (var enumerator = generator.EnumPagesAsync().GetEnumerator()) { int index = 0; // Before the advent of "async for" (might be introduced in C# 8), // to handle the items in sequence one by one, we need to use // the expanded for-each pattern. while (await enumerator.MoveNext(CancellationToken.None)) { var page = enumerator.Current; Console.WriteLine("{0}: {1}", index, page); index++; // Prompt user to continue listing, every 50 pages. if (index % 50 == 0) { Console.WriteLine("Esc to exit, any other key for next page."); if(Console.ReadKey().Key == ConsoleKey.Escape) break; } } } } ``` -------------------------------- ### Wikibase Entity Data Output Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Wikibase]-Getting-started This is an example of the structured data output for a Wikibase entity, showing claims, references, and qualifiers. ```plaintext Mount Everest Earth's highest mountain, with a peak at 8,848 metres (29,029 feet) above sea level, part of the Himalaya mountain range between Nepal and China once in India Claims P17 = Q837 Reference: fa278ebfc458360e5aed63d5058cca83c46134f1 P143 = Q328 P31 = Q8502 Reference: fa278ebfc458360e5aed63d5058cca83c46134f1 P143 = Q328 P373 = Mount Everest P242 = Nepal relief location map.jpg P227 = 4040417-1 Reference: c3ba0a726da807d2aa00570597c7b1a29267e529 P143 = Q1961887 P214 = 247168735 Reference: c3ba0a726da807d2aa00570597c7b1a29267e529 P143 = Q1961887 P349 = 00628288 P625 = 27.988055555556°N 86.925277777778°E Reference: 9a24f7c0208b05d6be97077d855671d1dfdbc0dd P143 = Q48183 P30 = Q48 Reference: 3bf39867b037e8e494a8389ae8a03bad6825a7fc P143 = Q191168 P910 = Q7278710 P935 = ཇོ་མོ་གླང་མ Reference: 3bf39867b037e8e494a8389ae8a03bad6825a7fc P143 = Q191168 P18 = Mount everest.jpg Qualifier: P2096 = [en]Mount Everest seen from base camp one. Qualifier: P585 = 2007-06-07 Reference: c0623aeb5e42745314018466233282526f7d8c9c P854 = https://www.flickr.com/photos/rupertuk/534748923/ P138 = Q217119 Qualifier: P580 = Y1865 Qualifier: P805 = Q2517025 Reference: 2fb5f1d401c2603010edadf139a9c20538df8604 P248 = Q23763219 P646 = /m/0blbd Reference: 2b00cb481cddcac7623114367489b5c194901c4a P248 = Q15241312 P577 = 2013-10-28 P244 = sh85045978 P948 = Mount Everest banner 2.jpg P1566 = 1283416 Reference: 64133510dcdf15e7943de41e4835c673fc5d6fe4 P143 = Q830106 P793 = Q1194369 Qualifier: P585 = 1953-05-29 Qualifier: P710 = Q33817 Qualifier: P710 = Q80732 Qualifier: P805 = Q4567715 P2044 = 8848(http://www.wikidata.org/entity/Q11573) Reference: fa278ebfc458360e5aed63d5058cca83c46134f1 P143 = Q328 P268 = 15289744k Reference: d4bd87b862b12d99d26e86472d44f26858dee639 P143 = Q8447 P268 = 11963711d P2660 = 8848(http://www.wikidata.org/entity/Q11573) Reference: 796948eaf1c20bd9c2250838151b820ef78011d8 P854 = http://www.peakbagger.com/peak.aspx?pid=10640 P3109 = 10640 P1296 = 0025628 P3221 = destination/mount-everest P706 = Q924257 Reference: fa278ebfc458360e5aed63d5058cca83c46134f1 P143 = Q328 P1667 = 7001423 P2924 = 1952857 P3309 = 150230 P3417 = Mount-Everest P131 = Q837 Qualifier: P17 = Q837 Reference: 9a24f7c0208b05d6be97077d855671d1dfdbc0dd P143 = Q48183 P3513 = 80 P1465 = Q8366750 P3018 = Q2211959 P972 = Q5460604 P361 = Q5451 P361 = Q208126 P361 = Q2 P361 = Q48 P2659 = 40008(http://www.wikidata.org/entity/Q11573) P2347 = 116445 P1225 = 10038395 ``` -------------------------------- ### GetPageImagesAsync Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Querying-for-other-page-properties Fetches thumbnail images for a list of pages. This example shows how to use `PageImagesPropertyProvider` to specify the thumbnail size. ```APIDOC ## GetPageImagesAsync ### Description Fetches thumbnail images for a list of pages. This example shows how to use `PageImagesPropertyProvider` to specify the thumbnail size. ### Method ```csharp static async Task GetPageImagesAsync() ``` ### Parameters This method does not take any direct parameters, but it operates on an array of `WikiPage` objects. ### Request Example ```csharp var pages = new[] { new WikiPage(myWikiSite, "Albert Einstein"), new WikiPage(myWikiSite, "Isaac Newton") }; await pages.RefreshAsync(new WikiPageQueryProvider { Properties = { new PageImagesPropertyProvider {ThumbnailSize = 100} } }); Console.WriteLine("Thumbnails:"); foreach (var page in pages) { Console.WriteLine("{0}: {1}", page, page.GetPropertyGroup().ThumbnailImage.Url); } ``` ### Response #### Success Response The `RefreshAsync` method populates the `WikiPage` objects with properties. The `ThumbnailImage.Url` property of the `PageImagesPropertyGroup` will contain the URL of the thumbnail image. ``` -------------------------------- ### WikiSite Login/Logout Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Provides examples for logging into and out of a MediaWiki site using `LoginAsync` and `LogoutAsync`. It highlights internal token management and mentions the use of Bot Passwords for FANDOM sites. ```APIDOC ## WikiSite.LoginAsync / LogoutAsync — Authentication Log in and out with simple async methods. Tokens are managed internally. For FANDOM sites migrated to MW 1.33+ (UCP), use Bot Passwords. ```csharp using WikiClientLibrary.Sites; var client = new WikiClient { ClientUserAgent = "MyBot/1.0" }; var site = new WikiSite(client, "https://test2.wikipedia.org/w/api.php"); await site.Initialization; try { await site.LoginAsync("MyBotName", "MyBotPassword"); Console.WriteLine($"Logged in as: {site.AccountInfo.Name}"); Console.WriteLine($"Groups: {string.Join(", ", site.AccountInfo.Groups)}"); // => Groups: bot, editor, *, user, autoconfirmed } catch (OperationFailedException ex) { // ex.ErrorCode: "wrongpassword", "notexists", etc. Console.WriteLine($"Login failed: {ex.ErrorMessage}"); } // Work with the site... await site.LogoutAsync(); Console.WriteLine("Logged out."); client.Dispose(); ``` ``` -------------------------------- ### Get Page Images Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Querying-for-other-page-properties Retrieves thumbnails for multiple pages. Configure `PageImagesPropertyProvider` with the desired `ThumbnailSize` and call `RefreshAsync` on a collection of `WikiPage` objects. ```csharp static async Task GetPageImagesAsync() { var pages = new[] { new WikiPage(myWikiSite, "Albert Einstein"), new WikiPage(myWikiSite, "Isaac Newton") }; await pages.RefreshAsync(new WikiPageQueryProvider { Properties = { new PageImagesPropertyProvider {ThumbnailSize = 100} } }); Console.WriteLine("Thumbnails:"); foreach (var page in pages) { Console.WriteLine("{0}: {1}", page, page.GetPropertyGroup().ThumbnailImage.Url); } } ``` -------------------------------- ### Connect, Login, and Logout with WikiClientLibrary Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Getting-started Demonstrates how to initialize a WikiClient, connect to a MediaWiki site, log in with user credentials, perform basic site information retrieval, and finally log out. Includes error handling for login failures. Ensure to replace placeholder credentials and user agent. ```csharp class Program { static void Main(string[] args) { MainAsync().Wait(); } static async Task MainAsync() { // A WikiClient has its own CookieContainer. var client = new WikiClient { ClientUserAgent = "WCLQuickStart/1.0 (your user name or contact information here)" }; // You can create multiple WikiSite instances on the same WikiClient to share the state. var site = new WikiSite(client, "https://test2.wikipedia.org/w/api.php"); // Wait for initialization to complete. // Throws error if any. await site.Initialization; try { await site.LoginAsync("User name", "password"); } catch (WikiClientException ex) { Console.WriteLine(ex.Message); // Add your exception handler for failed login attempt. } // Do what you want Console.WriteLine(site.SiteInfo.SiteName); Console.WriteLine(site.AccountInfo); Console.WriteLine("{0} extensions", site.Extensions.Count); Console.WriteLine("{0} interwikis", site.InterwikiMap.Count); Console.WriteLine("{0} namespaces", site.Namespaces.Count); // We're done here await site.LogoutAsync(); client.Dispose(); // Or you may use `using` statement. } } ``` -------------------------------- ### Initialize WikiClient with Logging Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Initialize a WikiClient instance, optionally configuring logging using Microsoft.Extensions.Logging for detailed diagnostics. ```csharp using Microsoft.Extensions.Logging; using WikiClientLibrary.Client; // Basic setup var wikiClient = new WikiClient { ClientUserAgent = "MyBot/1.0 (https://example.com/contact)" }; // With logging (Microsoft.Extensions.Logging) var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Information) .AddSimpleConsole(o => o.IncludeScopes = true)); var wikiClientWithLogging = new WikiClient { ClientUserAgent = "MyBot/1.0", Logger = loggerFactory.CreateLogger() }; // With custom HTTP handler (e.g. for HTTP Basic Auth on a private wiki) var handler = new HttpClientHandler { Credentials = new NetworkCredential("user", "pass") }; var wikiClientWithAuth = new WikiClient(handler) { ClientUserAgent = "MyBot/1.0" }; // Always dispose when done wikiClient.Dispose(); ``` -------------------------------- ### GeoSearchGenerator Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Finds wiki pages near a given geographic coordinate. This generator requires the GeoData MediaWiki extension to be installed. ```APIDOC ## GeoSearchGenerator — Geospatial Page Search Find wiki pages near a given geographic coordinate (requires the GeoData MediaWiki extension). ```csharp using WikiClientLibrary.Generators; // Pages within 10 km of the Eiffel Tower (48.858°N, 2.295°E) var geoGen = new GeoSearchGenerator(site) { OriginCoordinate = new GeoCoordinate(48.858, 2.295), Radius = 10000, // metres PaginationSize = 50, }; var results = await geoGen.EnumItemsAsync().Take(20).ToListAsync(); foreach (var item in results) Console.WriteLine($"{item.Title,-40} dist={item.Distance:F0}m ({item.Coordinate})"); ``` ``` -------------------------------- ### Connection, Login, and Logout Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Getting-started This snippet demonstrates how to initialize a WikiClient, create a WikiSite, connect to a MediaWiki instance, log in, perform basic information retrieval, and finally log out. ```APIDOC ## Connection, Login, and Logout This example shows the basic workflow for connecting to a MediaWiki site, logging in, retrieving some site information, and logging out. ### Code Example ```csharp // A WikiClient has its own CookieContainer. var client = new WikiClient { ClientUserAgent = "WCLQuickStart/1.0 (your user name or contact information here)" }; // You can create multiple WikiSite instances on the same WikiClient to share the state. var site = new WikiSite(client, "https://test2.wikipedia.org/w/api.php"); // Wait for initialization to complete. // Throws error if any. await site.Initialization; try { await site.LoginAsync("User name", "password"); } catch (WikiClientException ex) { Console.WriteLine(ex.Message); // Add your exception handler for failed login attempt. } // Do what you want Console.WriteLine(site.SiteInfo.SiteName); Console.WriteLine(site.AccountInfo); Console.WriteLine("{0} extensions", site.Extensions.Count); Console.WriteLine("{0} interwikis", site.InterwikiMap.Count); Console.WriteLine("{0} namespaces", site.Namespaces.Count); // We're done here await site.LogoutAsync(); client.Dispose(); // Or you may use `using` statement. ``` ### Notes * Uses C# 7.1 `static async Task Main()` or C# 9.0 top-level statements for application entry point. * Prefer `WikiaSite` for FANDOM/Wikia sites for better specific support. ``` -------------------------------- ### Generate Wikibase JSON Dump Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Wikibase]-Working-with-JSON-dump Use this command to generate a JSON dump of your Wikibase entities. Ensure you are at the root of your MediaWiki installation. ```bash php ./extensions/Wikibase/repo/maintenance/dumpJson.php --no-cache --output=entities.json ``` -------------------------------- ### WikiClient Initialization Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Demonstrates how to initialize the WikiClient, which manages HTTP connections, cookies, and retry logic. It can be configured with a custom user agent, logging, or custom HTTP handlers. ```APIDOC ## WikiClient — HTTP Client Initialization `WikiClient` is the low-level HTTP client that manages cookies, user-agent, retry behaviour, and the underlying `HttpClient`. Multiple `WikiSite` instances can share one `WikiClient` to share cookie state and connection pooling. ```csharp using Microsoft.Extensions.Logging; using WikiClientLibrary.Client; // Basic setup var wikiClient = new WikiClient { ClientUserAgent = "MyBot/1.0 (https://example.com/contact)" }; // With logging (Microsoft.Extensions.Logging) var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Information) .AddSimpleConsole(o => o.IncludeScopes = true)); var wikiClientWithLogging = new WikiClient { ClientUserAgent = "MyBot/1.0", Logger = loggerFactory.CreateLogger() }; // With custom HTTP handler (e.g. for HTTP Basic Auth on a private wiki) var handler = new HttpClientHandler { Credentials = new NetworkCredential("user", "pass") }; var wikiClientWithAuth = new WikiClient(handler) { ClientUserAgent = "MyBot/1.0" }; // Always dispose when done wikiClient.Dispose(); ``` ``` -------------------------------- ### Instantiate WikiSite Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Wikibase]-Getting-started Instantiates a WikiClient and a WikiSite for interacting with a Wikibase instance like Wikidata. Ensure to set a descriptive ClientUserAgent. ```csharp var client = new WikiClient { ClientUserAgent = "..." }; var myWikiDataSite = new WikiSite(client, "https://www.wikidata.org/w/api.php"); ``` -------------------------------- ### Get Page Geographical Coordinates Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Querying-for-other-page-properties Fetches geographical coordinates for a given page. Ensure `GeoCoordinatesPropertyProvider` is added to the query provider and `RefreshAsync` is called. ```csharp static async Task GetPageGeoCoordinatesAsync() { var page = new WikiPage(myWikiSite, "france"); // This will populate "provider" with some basic IWikiPagePropertyProviders, // which will make most of the properties in WikiPage have valid values. // You can simply use // provider = new WikiPageQueryProvider() // if you are not interested in other ordinary properties in WikiPage. var provider = WikiPageQueryProvider.FromOptions(PageQueryOptions.None); provider.Properties.Add(new GeoCoordinatesPropertyProvider { QueryPrimaryCoordinate = true, QuerySecondaryCoordinate = true, }); await page.RefreshAsync(provider); Console.WriteLine("{0}, located at {1}", page.Title, page.GetPropertyGroup().PrimaryCoordinate); } ``` -------------------------------- ### Query WikiPage with Extracts Property Provider Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Retrieve the introduction text of a WikiPage using the ExtractsPropertyProvider. Configure options like AsPlainText, IntroductionOnly, and MaxSentences for customized output. ```csharp using WikiClientLibrary.Pages; using WikiClientLibrary.Pages.Queries; using WikiClientLibrary.Pages.Queries.Properties; // Page extract (introduction text) var extractPage = new WikiPage(site, "Eiffel Tower"); await extractPage.RefreshAsync(new WikiPageQueryProvider { Properties = { new ExtractsPropertyProvider { AsPlainText = true, IntroductionOnly = true, MaxSentences = 2, } } }); Console.WriteLine(extractPage.GetPropertyGroup().Extract); ``` -------------------------------- ### Wikibase Entity JSON Structure Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Wikibase]-Working-with-JSON-dump This is an example of the structure of a single Wikibase entity within the JSON dump. It includes type, sitelinks, descriptions, ID, claims, aliases, and labels. ```json { "type": "item", "sitelinks": [ // ... ], "descriptions": { "en": { "language": "en", "value": "totality of space and all matter and radiation in it, including planets, galaxies, light, and us; may include their properties such as energy; may include time/spacetime" }, "zh": { "language": "zh", "value": "一切空间、时间、物质和能量构成的总体" }, // ... }, "id": "Q2", "claims": { "P2": [{ "type": "statement", "references": [], "mainsnak": { "snaktype": "value", "property": "P2", "datavalue": { "value": "Q1", "type": "string" }, "datatype": "external-id" }, "qualifiers": [], "id": "Q2$997A7A7B-8737-49B6-9386-BD934CE9E2A7", "rank": "normal" }], "P3": [{ "type": "statement", "references": [{ "hash": "0e556569b6638a2a8a6ee29edef2644b2fc29c15", "snaks-order": ["P2"], "snaks": { "P2": [{ "snaktype": "value", "property": "P2", "datavalue": { "value": "Q1$8983b0ea-4a9c-0902-c0db-785db33f767c", "type": "string" }, "datatype": "external-id" }] } }], "mainsnak": { "snaktype": "somevalue", "property": "P3", "datatype": "wikibase-item" }, "qualifiers": [], "id": "Q2$47BA934E-9A36-42C5-8767-C4D8D6A3F333", "rank": "normal" }], // ... }, "aliases": { "en": [{ "language": "en", "value": "Our Universe" }, { "language": "en", "value": "The Universe" }, { "language": "en", "value": "Universe (Ours)" }, { "language": "en", "value": "cosmos" }] }, "labels": { "en": { "language": "en", "value": "Universe" }, "zh": { "language": "zh", "value": "宇宙" }, // ... } } ``` -------------------------------- ### Fetch Page Information and Content Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Instantiate a WikiPage cheaply and call RefreshAsync to populate its properties. Supports fetching full content, resolving redirects, and batch requests. ```csharp using WikiClientLibrary.Pages; // Fetch a single page with full content, following redirects var page = new WikiPage(site, "France"); await page.RefreshAsync(PageQueryOptions.FetchContent | PageQueryOptions.ResolveRedirects); Console.WriteLine(page.Title); // "France" Console.WriteLine(page.Exists); // true Console.WriteLine(page.ContentLength); // bytes Console.WriteLine(page.LastRevisionId); Console.WriteLine(page.LastRevision?.UserName); Console.WriteLine(page.Content?.Substring(0, 200)); // wikitext ``` ```csharp // Fetch a category and inspect its metadata var catPage = new WikiPage(site, "Category:Featured articles"); await catPage.RefreshAsync(); var catInfo = catPage.GetPropertyGroup(); Console.WriteLine($"{catPage.Title}: {catInfo.MembersCount} members, {catInfo.SubcategoriesCount} subcategories") ``` ```csharp // Fetch by page ID var pageById = new WikiPage(site, 12345); await pageById.RefreshAsync(); Console.WriteLine($"ID 12345 → {pageById.Title}") ``` ```csharp // Batch refresh — only 1 API request for all pages var pages = new[] { "Main Page", "Project:Sandbox", "NonExistentPage12345" } .Select(t => new WikiPage(site, t)) .ToArray(); await pages.RefreshAsync(); foreach (var p in pages) Console.WriteLine($"{p.Title}: exists={p.Exists}") ``` -------------------------------- ### WikiSite Connection Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Explains how to create and initialize a WikiSite instance, which represents a connection to a specific MediaWiki site. It covers standard construction and the static factory method, and mentions the WikiaSite for FANDOM/Wikia sites. ```APIDOC ## WikiSite — Connecting to a MediaWiki Site `WikiSite` represents a single MediaWiki installation. After construction, await `site.Initialization` before performing any operations. Site metadata (namespaces, extensions, interwiki map, account info) is populated automatically during initialization. ```csharp using WikiClientLibrary.Sites; var client = new WikiClient { ClientUserAgent = "MyBot/1.0" }; // Standard construction — must await Initialization before use var site = new WikiSite(client, "https://en.wikipedia.org/w/api.php"); await site.Initialization; Console.WriteLine(site.SiteInfo.SiteName); // "Wikipedia" Console.WriteLine(site.SiteInfo.Generator); // "MediaWiki 1.xx.x" Console.WriteLine(site.AccountInfo.Name); // current user (IP if anonymous) Console.WriteLine($"{site.Namespaces.Count} namespaces"); Console.WriteLine($"{site.Extensions.Count} extensions"); // Alternatively use the static factory method var site2 = await WikiSite.CreateAsync(client, "https://test2.wikipedia.org/w/api.php"); // For FANDOM / Wikia sites use WikiaSite for extra Wikia-specific support // var site = new WikiaSite(client, "https://community.fandom.com/api.php"); // await site.Initialization; ``` ``` -------------------------------- ### Enable TLS 1.2 for Secure Connections Source: https://github.com/cxuesong/wikiclientlibrary/wiki/Troubleshooting Use this code to ensure your application supports TLS 1.2, which is required by many MediaWiki sites. Apply this setting before establishing the first connection. ```cs using System.Net; ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; ``` -------------------------------- ### Patrol Recent Changes with RecentChangesEntry.PatrolAsync Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Mark a recent change entry as patrolled using the PatrolAsync method. This requires the 'patrol' or 'autopatrol' right. The example first retrieves an unpatrolled change and then marks it. ```csharp using WikiClientLibrary.Generators; var rcg = new RecentChangesGenerator(site) { TypeFilters = RecentChangesFilterTypes.Create, PaginationSize = 5, PatrolledFilter = PropertyFilterOption.WithoutProperty, }; var rc = await rcg.EnumItemsAsync().FirstOrDefaultAsync(); if (rc == null) { Console.WriteLine("Nothing to patrol."); return; } Console.WriteLine($"Unpatrolled: {rc.Title} by {rc.UserName} at {rc.TimeStamp}"); await rc.PatrolAsync(); Console.WriteLine("Marked as patrolled."); ``` -------------------------------- ### Edit Wiki Page Content Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Edit a page's content with optional edit summary, minor flag, and bot flag. Tokens are handled automatically. Appends to existing content in this example. ```csharp using WikiClientLibrary.Pages; var page = new WikiPage(site, "Project:Sandbox"); await page.RefreshAsync(PageQueryOptions.FetchContent); if (!page.Exists) Console.WriteLine("Warning: page does not exist yet."); // Append to existing content await page.EditAsync(new WikiPageEditOptions { Content = page.Content + "\n\n'''Hello''' from WikiClientLibrary!", Summary = "Test edit via WCL", Minor = false, Bot = true, }); Console.WriteLine($"Saved. New revision ID: {page.LastRevisionId}") ``` -------------------------------- ### Login to Private Wiki Constructor Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Advanced-usages Use this constructor to log in to private wikis where anonymous users have no read access. Ensure initialization completes before other operations. ```csharp public WikiSite( IWikiClient wikiClient, SiteOptions options, string userName, string password ) ``` -------------------------------- ### Private Wiki Login with Credentials Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Supply credentials directly in the constructor for private wikis where anonymous reads are forbidden. Login occurs before initialization queries are sent. ```csharp using WikiClientLibrary.Sites; var client = new WikiClient { ClientUserAgent = "MyBot/1.0" }; var options = new SiteOptions("https://private.example.com/api.php"); // Credentials are used during the initialization request itself var site = new WikiSite(client, options, "BotUser", "BotPassword"); try { await site.Initialization; // throws on login failure Console.WriteLine($"Connected to private wiki as {site.AccountInfo.Name}"); } catch (WikiClientException ex) { Console.WriteLine($"Could not access private wiki: {ex.Message}"); } ``` -------------------------------- ### Enumerate Entities with Generators Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Wikibase]-Getting-started Use `AllPagesGenerator` to enumerate entities starting from a specific title. The `PaginationSize` option controls how many items are fetched per request. Press 'Esc' to exit early. ```csharp static async Task EnumerateEntitiesAsync() { var generator = new AllPagesGenerator(myWikiDataSite) { StartTitle = "Q1", PaginationSize = 50 }; using (var enumerator = generator.EnumItemsAsync().Buffer(50).GetEnumerator()) { while (await enumerator.MoveNext()) { var pageStubs = enumerator.Current; var entities = pageStubs.Select(stub => new Entity(myWikiDataSite, stub.Title)).ToArray(); await entities.RefreshAsync(EntityQueryOptions.FetchLabels); foreach (var entity in entities) { Console.WriteLine("{0} ({1})", entity.Labels["en"], entity.Id); } Console.WriteLine("Esc to exit, any other key for next page."); if (Console.ReadKey().Key == ConsoleKey.Escape) break; } } } ``` -------------------------------- ### Search Wiki Pages with SearchGenerator Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[MediaWiki]-Generators Demonstrates how to use `SearchGenerator` to find pages based on a keyword. It shows how to set pagination size and retrieve a limited number of search results with snippets. ```csharp static async Task SearchAsync() { Console.Write("Enter your search keyword: "); var generator = new SearchGenerator(myWikiSite, Console.ReadLine()) { PaginationSize = 22 }; // We are only interested in the top 20 items. foreach (var item in await generator.EnumItemsAsync().Take(20).ToList()) { Console.WriteLine(item); Console.WriteLine("\t{0}", item.Snippet); } } ``` -------------------------------- ### Fetch and Edit Wikibase Entities Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Demonstrates fetching entity details (labels, descriptions, claims) and performing edits such as updating claims, adding labels, and removing claims. Requires initialization of WikiClient and WikiSite. ```csharp using WikiClientLibrary.Wikibase; using WikiClientLibrary.Wikibase.DataTypes; var client = new WikiClient { ClientUserAgent = "MyBot/1.0" }; var wikidata = new WikiSite(client, "https://www.wikidata.org/w/api.php"); await wikidata.Initialization; // Fetch entity Q513 (Mount Everest) var entity = new Entity(wikidata, "Q513"); await entity.RefreshAsync(EntityQueryOptions.FetchAllProperties); Console.WriteLine(entity.Labels["en"]); // "Mount Everest" Console.WriteLine(entity.Descriptions["en"]); // "Earth's highest mountain..." foreach (var claim in entity.Claims) { Console.WriteLine($" {claim.MainSnak.PropertyId} = {claim.MainSnak.DataValue}"); foreach (var q in claim.Qualifiers) Console.WriteLine($" qualifier: {q.PropertyId} = {q.DataValue}"); } // Edit entity: update a claim, add a label, remove a claim await entity.RefreshAsync(EntityQueryOptions.FetchClaims); var coordClaim = entity.Claims["P625"].First(); coordClaim.MainSnak.DataValue = new WbGlobeCoordinate( 27.988, 86.925, 0.001, WbUri.Get("http://www.wikidata.org/entity/Q2")); var edits = new List { new EntityEditEntry(nameof(Entity.Labels), new WbMonolingualText("en", "Mount Everest")), new EntityEditEntry(nameof(Entity.Descriptions),new WbMonolingualText("en", "Highest mountain on Earth")), new EntityEditEntry(nameof(Entity.Claims), coordClaim), // update new EntityEditEntry(nameof(Entity.Claims), entity.Claims["P948"].Last(), WbEntityEditEntryState.Removed), // remove }; await entity.EditAsync(edits, "Update coordinate and tidy claims", EntityEditOptions.Bot); Console.WriteLine("Entity edited successfully."); ``` -------------------------------- ### Configure Logging with Microsoft.Extensions.Logging Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Integrate Microsoft.Extensions.Logging with WikiClient and WikiSite by assigning ILogger instances. This enables capturing trace and debug output with full scope context, useful for debugging. ```csharp using Microsoft.Extensions.Logging; using WikiClientLibrary.Client; using WikiClientLibrary.Sites; var loggerFactory = LoggerFactory.Create(builder => builder .SetMinimumLevel(LogLevel.Trace) .AddSimpleConsole(o => { o.IncludeScopes = true; o.SingleLine = false; })); var client = new WikiClient { ClientUserAgent = "MyBot/1.0", Logger = loggerFactory.CreateLogger(), }; var site = new WikiSite(client, "https://test2.wikipedia.org/w/api.php") { Logger = loggerFactory.CreateLogger(), }; await site.Initialization; // Trace output example (scoped): // Trace: WikiClient → Wikipedia → WikiPage{Sandbox}::UpdateContentAsync → ::InvokeAsync(...) // Initiate request to: https://test2.wikipedia.org/w/api.php. // Trace: WikiClient → ... HTTP 200, elapsed: 00:00:00.366 // Information: WikiSite → Wikipedia → WikiPage{Sandbox}::UpdateContentAsync // Edited page. New revid=329827. ``` -------------------------------- ### Enumerate All Pages Source: https://context7.com/cxuesong/wikiclientlibrary/llms.txt Lists all pages in a namespace, with options for title prefix, redirect status, and pagination. Returns `IAsyncEnumerable` or `IAsyncEnumerable`. Requires `WikiClientLibrary.Generators`. ```csharp using WikiClientLibrary.Generators; var generator = new AllPagesGenerator(site) { StartTitle = "Wiki", NamespaceId = BuiltInNamespaces.Main, RedirectsFilter = PropertyFilterOption.WithoutProperty, PaginationSize = 50, }; // Enumerate first 1000 non-redirect pages starting with "Wiki" var pages = await generator.EnumPagesAsync().Take(1000).ToListAsync(); foreach (var p in pages) Console.WriteLine($"{p.Title,-40} {p.ContentLength,8}B {p.LastTouched}"); // For title-only work, EnumItemsAsync is faster (no per-page property fetch) await foreach (var stub in generator.EnumItemsAsync().Take(100)) Console.WriteLine($"{stub.Title} (ns={stub.NamespaceId})"); ``` -------------------------------- ### C# Credential Manager for Unit Tests Source: https://github.com/cxuesong/wikiclientlibrary/wiki/[Development]-Unit-tests This C# code defines a partial class `CredentialManager` to initialize test credentials. It includes handlers for setting up API entry points and performing logins for different MediaWiki sites. Ensure valid usernames and passwords are provided. ```csharp using System; using WikiClientLibrary; using WikiClientLibrary.Sites; namespace UnitTestProject1 { partial class CredentialManager { static partial void Initialize() { // A place to perform page moving and deleting // You should have the bot or sysop right there DirtyTestsEntryPointUrl = "https://test2.wikipedia.org/w/api.php"; // A private wiki API endpoint, where anonymous // users have no read permission. PrivateWikiTestsEntryPointUrl = null; LoginCoreAsyncHandler = async site => { var url = site.ApiEndpoint; // See Endpoints.cs for a complete list of MediaWiki sites we are accessing. // We'll make changes to test2.wikipedia.org if (Regex.IsMatch(url, @"(wikipedia|wikidata|beta.wmflabs).org", RegexOptions.IgnoreCase)) await site.LoginAsync("Alice", "password"); // We'll make changes to MediaWiki 119 test Wiki else if (Regex.IsMatch(url, @"wikia.com|wikia.org|fandom.com", RegexOptions.IgnoreCase)) await site.LoginAsync("Bob", "password"); // Add other login routines if you need to. else if (url.Contains("domain.com")) await site.LoginAsync("Calla", "password"); else throw new NotSupportedException(); }; EarlyLoginCoreAsyncHandler = async (client, options) => { var url = options.ApiEndpoint; WikiSite site = null; // We are testing login to wikipedia.org via WikiSite constructor. // Place sensitive information here. if (url.Contains("wikipedia.org")) site = new WikiSite(client, options, "Alice", "password"); if (site != null) await site.Initialization; return site; }; } } } ```