{"id":19335705,"url":"https://github.com/buttercms/buttercms-csharp","last_synced_at":"2025-04-23T00:32:08.016Z","repository":{"id":11806886,"uuid":"70172443","full_name":"ButterCMS/buttercms-csharp","owner":"ButterCMS","description":".NET API client for ButterCMS (https://buttercms.com)","archived":false,"fork":false,"pushed_at":"2025-04-16T11:33:47.000Z","size":190,"stargazers_count":41,"open_issues_count":0,"forks_count":15,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-20T23:04:25.168Z","etag":null,"topics":["api-client","asp-net","asp-net-mvc","cms","csharp","dotnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ButterCMS.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-06T16:33:18.000Z","updated_at":"2025-04-16T11:33:47.000Z","dependencies_parsed_at":"2024-10-28T13:41:34.577Z","dependency_job_id":"09d5bb00-c400-47e1-854d-fd3382dd1353","html_url":"https://github.com/ButterCMS/buttercms-csharp","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ButterCMS%2Fbuttercms-csharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ButterCMS%2Fbuttercms-csharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ButterCMS%2Fbuttercms-csharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ButterCMS%2Fbuttercms-csharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ButterCMS","download_url":"https://codeload.github.com/ButterCMS/buttercms-csharp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250348327,"owners_count":21415894,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","asp-net","asp-net-mvc","cms","csharp","dotnet"],"created_at":"2024-11-10T03:08:32.656Z","updated_at":"2025-04-23T00:32:08.000Z","avatar_url":"https://github.com/ButterCMS.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# buttercms-csharp\n\n.NET Standard (2.1) Library for ButterCMS API.\n\n## Documentation\n\nFor a comprehensive list of examples, check out the [API documentation](https://buttercms.com/docs/api/).\n\n\n## Installation\n\nTo install ButterCMS, run the following command in the [Package Manager Console](https://docs.nuget.org/ndocs/tools/package-manager-console)\n\n```PowerShell\nPM\u003e Install-Package ButterCMS\n```\n\nThe library can also be installed to the project via .NET CLI\n\n```bash\ndotnet add package ButterCMS\n```\n\nOr by adding the package manually to the project file\n\n\u003c!-- {x-release-please-start-version} --\u003e\n```xml\n\u003cItemGroup\u003e\n\u003cPackageReference Include=\"ButterCMS\" Version=\"2.1.0\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\u003c!-- {x-release-please-end} --\u003e\n\n## Usage\n\nTo get started with the Butter API, instantiate the ButterCMSClient with the API key found in the [Butter Admin Settings](https://buttercms.com/settings/). An optional timeout parameter can be passed as a [TimeSpan](https://msdn.microsoft.com/en-us/library/system.timespan%28v=vs.110%29.aspx); the default is 10 seconds.\n\n```C#\nusing ButterCMS;\n...\nvar butterClient = new ButterCMSClient(\"API KEY\");\n```\n\nIf the application will be making many Butter API calls, it is recommended to store and re-use the client object.\n\nEach Butter client method has a synchronous version and an asynchronous version. Asynchronous methods are appended with the word \"Async\".\n\n### Preview mode\n\nPreview mode can be used to setup a staging website for previewing content fields or for testing content during local development. To fetch content from preview mode add an additional argument, `true`, to the package initialization:\n\n```C#\nusing ButterCMS;\n...\nbool previewMode = true;\n\nvar butterClient = new ButterCMSClient(\"API KEY\", null, 3, null, previewMode);\n```\n\n## Sections\n\n* [Posts](#posts)\n* [Authors](#authors)\n* [Categories](#categories)\n* [Feeds](#feeds)\n* [Collections](#collections)\n* [Pages](#pages)\n* [Class Definitions](#class-definitions)\n* [Exceptions](#exceptions)\n\n## Posts\n\n### List Posts\n\nListing posts returns a [PostsResponse](#postsresponse-class) object. This object consists of a [metadata](#postsmeta-class) object and IEnumerable\u0026lt;[Post](#post-class)\u0026gt;\n\n#### ListPosts() Parameters\n\n| Parameter|Default|Description|\n| ---|---|---|\n| page(optional) | 1 | Used to paginate through older posts. |\n| pageSize(optional) | 10 |  Used to set the number of blog posts shown per page. |\n| excludeBody(optional) | false | When true, does not return the full post body. Useful for keeping response size down when showing a list of blog posts. |\n|authorSlug(optional) | |Filter posts by an author’s slug.|\n|categorySlug(optional) | | Filter posts by a category’s slug.\n\n#### Examples\n\n```C#\nPostsResponse posts = butterClient.ListPosts();\n\nPostsResponse filteredPosts = await butterClient.ListPostsAsync(page: 2, pageSize: 5, excludeBody: true, authorSlug: \"alice\", categorySlug: \"dot-net\");\n```\n\n### Retrieving a Single Post\n\nRetrieving a single Post will return a PostResponse object. This object consists of a single [Post](#post-class) and Post [Metadata](#postmeta-class). Post Metadata offers hints about the Previous and Next posts.\n\n#### RetrievePost() Parameters\n\n| Parameter|Description|\n| ---|---|\n| slug|The slug of the post to be retrieved.|\n\n#### Examples\n\n```C#\nPostResponse controversialPost = butterClient.RetrievePost(\"tabs-vs-spaces-throwdown\");\n\nPostResponse safePost = await butterClient.RetrievePostAsync(\"puppies-and-kittens\");\n\n```\n\n### Searching Posts\n\nSearching posts will return the same object as listing posts, [PostsResponse](#postsresponse-class)\n\n#### SearchPosts() Parameters\n\n| Parameter|Default|Description|\n| ---|---|---|\n| query |  | Search query |\n| page(optional) | 1 | Used to paginate through older posts. |\n| pageSize(optional) | 10 |  Used to set the number of blog posts shown per page. |\n\n#### Examples\n\n```C#\nPostsResponse posts = butterClient.SearchPosts(\"spaceships\");\n\nPostsResponse caffeinePosts = await butterClient.SearchPostsAsync(query: \"coffee\", page: 3, pageSize: 5);\n\n```\n\n## Authors\n\n### List Authors\n\nListing Authors returns IEnumerable\u0026lt;[Author](#author-class)\u0026gt;\n\n#### ListAuthors() Parameters\n\n| Parameter|Description|\n| ---|---|\n| includeRecentPosts(optional)|If true, will return the author's recent posts in the response|\n\n#### Examples\n\n```C#\nIEnumerable\u003cAuthor\u003e authors = butterClient.ListAuthors();\n\nIEnumerable\u003cAuthor\u003e authorsWithPosts = await butterClient.ListAuthorsAsync(includeRecentPosts: true);\n\n```\n\n### Retrieve a Single Author\n\nRetrieving an author returns an [Author](#author-class) object\n\n#### RetrieveAuthor() Parameters\n\n| Parameter|Description|\n| ---|---|\n|authorSlug|The slug of the author to be retrieved.|\n| includeRecentPosts(optional)|If true, will return the author's recent posts in the response|\n\n#### Examples\n\n```C#\nAuthor sally = butterClient.RetrieveAuthor(\"sally\");\n\nAuthor tylerAndPosts = await butterClient.RetrieveAuthorAsync(authorSlug: \"tyler\", includeRecentPosts: true);\n\n```\n\n## Categories\n\n### List Categories\n\nListing Categories returns IEnumerable\u0026lt;[Category](#category-class)\u0026gt;\n\n#### ListCategories() Parameters\n\n| Parameter|Description|\n| ---|---|\n| includeRecentPosts(optional)|If true, will return recent posts along with categories|\n\n#### Examples\n\n```C#\nIEnumerable\u003cCategory\u003e categories = butterClient.ListCategories();\n\nIEnumerable\u003cCategory\u003e categoriesWithPosts = await butterClient.ListCategoriesAsync(includeRecentPosts: true);\n\n```\n\n### Retrieve a Single Category\n\nRetrieving a single category returns [Category](#category-class)\n\n#### RetrieveCategory() Parameters\n\n| Parameter|Description|\n| ---|---|\n|categorySlug|The slug of the category to be retrieved.|\n| includeRecentPosts(optional)|If true, will return recent posts along with category|\n\n#### Examples\n\n```C#\n Category dotnetCategory = butterClient.RetrieveCategory(\"dotnet\");\n\n Category fsharpCategoryWithPosts = await butterClient.RetrieveCategoryAsync(categorySlug: \"fsharp\", includeRecentPosts: true);\n\n```\n\n## Feeds\n\nEach of the feeds methods returns an [XmlDocument](https://msdn.microsoft.com/en-us/library/system.xml.xmldocument%28v=vs.110%29.aspx).\n\n\n### RSS Feed\n\nRetrieve a fully generated RSS feed for your blog.\n\n#### Examples\n\n```C#\n XmlDocument rssFeed = butterClient.GetRSSFeed();\n\n XmlDocument rssFeed = await butterClient.GetRSSFeedAsync();\n\n```\n\n### Atom Feed\n\nRetrieve a fully generated Atom feed for your blog.\n\n#### Examples\n\n```C#\n XmlDocument atomFeed = butterClient.GetAtomFeed();\n\n XmlDocument atomFeed = await butterClient.GetAtomFeedAsync();\n\n```\n\n### Sitemap\n\nRetrieve a fully generated sitemap for your blog.\n\n#### Examples\n\n```C#\n XmlDocument siteMap = butterClient.GetSitemap();\n\n XmlDocument siteMap = await butterClient.GetSitemapAsync();\n\n```\n\n## Collections\n\n**New in version 1.3.0**\n\nBy the power of .NET generics, Collections can now be deserialized by the library! The former method that would defer deserialization is still available to ease transition.\n\n#### RetrieveContentFields() Parameters\n\n| Parameter|Description|\n| ---|---|\n|key|String array of the Collection key|\n|parameterDictionary(optional)|Dictionary of additional parameters, such as \"locale\" or \"preview\"|\n\n#### RetrieveContentFields() Exceptions:\n\n| Exception|Description|\n| ---|---|\n|[ContentFieldObjectMismatchException](#contentfieldobjectmismatchexception)|This exception will be thrown when the library can't fit the returned data into the passed object class. |\n\n#### Examples\n\n```C#\nvar key = new string[1] { \"collection_key\" };\nvar dict = new Dictionary\u003cstring, string\u003e()\n            {\n                { \"locale\", \"de\" }\n            };\nvar teamMembersAndHeadline = butterClient.RetrieveContentFields\u003cTeamMembersHeadline\u003e(key, dict);\n\n```\n\n** Collection JSON documentation** :\n\nAs demonstrated in the [Collection documentation](https://buttercms.com/docs/api/?csharp#collections), any number of user-defined Collections can be retrieved from the API, these can get complicated in C# and you may choose to handle the response yourself. The RetrieveContentFieldsJSON() method will return the raw JSON response from the Butter API.\n\n#### RetrieveContentFieldsJSON() Parameters\n\n| Parameter|Description|\n| ---|---|\n|key|String array of the Collection key|\n|parameterDictionary(optional)|Dictionary of additional parameters, such as \"locale\" or \"preview\"|\n\n#### Examples\n\n```C#\nvar key = new string[1] { \"collection_key\" };\nvar dict = new Dictionary\u003cstring, string\u003e()\n            {\n                { \"locale\", \"de\" }\n            };\nvar contentFields = await butterClient.RetrieveContentFieldsJSONAsync(key, dict);\n\n```\n\n## Pages\n\n[ButterCMS Pages](https://buttercms.com/blog/page-types-cms-powered-pages-for-any-tech-stack) can be retrieved by first defining the custom Page Type as a class. These custom Page Types are defined in the [Butter admin](https://buttercms.com/pages/).\n\n### List Pages\n\nListing Pages returns a [PagesResponse\u0026lt;T\u0026gt;](#pagesresponse-class) object. Full API documentation can be found at [https://buttercms.com/docs/api/#list-pages-for-a-page-type](https://buttercms.com/docs/api/#list-pages-for-a-page-type).\n\n#### ListPages() Parameters\n\n| Parameter|Description|\n| ---|---|\n|pageType| Desired page type|\n|parameterDictionary| Dictionary of additional parameters. These options are described in greater detail in the [full API documentation](https://buttercms.com/docs/api/#get-multiple-pages-(page-type)). |\n\n#### ListPages() Exceptions\n\n| Exception|Description|\n| ---|---|\n|[PagesObjectMismatchException](#pagesobjectmismatchexception)|This exception will be thrown when the library can't fit the returned data into the passed object class. |\n\n### Retrieve a Single Page\n\nRetrieving a single page returns a [PageResponse\u0026lt;T\u0026gt;](#page-response-class) object\n\n#### RetrievePage() Parameters\n\n| Parameter|Description|\n| ---|---|\n|pageType| Desired page type|\n|pageSlug| Slug of the desired page|\n|parameterDictionary| Dictionary of additional parameters|\n\n#### RetrievePage() Exceptions:\n| Exception|Description|\n| ---|---|\n|[PagesObjectMismatchException](#pagesobjectmismatchexception)|This exception will be thrown when the library can't fit the returned data into the passed object class. |\n\n#### Examples\n\n##### Page Type Definition in the Butter Admin\n\n![alt text](/Examples/RecipePageType.png \"Page Type Definition\")\n\n##### Controller and ViewModel examples\n\n```C#\n\npublic namespace HungryDevApp\n{\n    public class RecipePage\n    {\n        public string category { get; set; }\n        public string recipe_name { get; set; }\n        public string main_ingredient { get; set; }\n        public double estimated_cooking_time_in_minutes { get; set; }\n        public string ingredient_list { get; set; }\n        public string instructions { get; set; }\n    }\n\n    public class RecipesController : Controller\n    {\n        [Route(recipes/)]\n        public virtual ActionResult Index(int page = 1, int pageSize = 10)\n        {\n            var butterClient = new ButterCMSClient(\"API KEY\");\n\n            var parameterDict = new Dictionary\u003cstring, string\u003e()\n            {\n                {\"page\", page.ToString()},\n                {\"page_size\", pageSize.ToString()}\n            };\n\n            PagesResponse\u003cRecipePage\u003e recipePages = butterClient.ListPages\u003cRecipePage\u003e(\"recipe\", parameterDict);\n\n            var viewModel = new RecipesViewModel();\n            viewModel.PreviousPageNumber = recipePages.Meta.PreviousPage;\n            viewModel.NextPageNumber = recipePages.Meta.NextPage;\n            viewModel.PagesCount = recipePages.Meta.Count;\n\n            viewModel.Recipes = new List\u003cRecipeViewModel\u003e();\n            foreach (Page\u003cRecipePage\u003e recipe in recipePages.Data)\n            {\n                RecipeViewModel recipeViewModel = new RecipeViewModel();\n                recipeViewModel.Category = recipe.Fields.category;\n                recipeViewModel.RecipeName = recipe.Fields.recipe_name;\n                recipeViewModel.MainIngredient = recipe.Fields.main_ingredient;\n                recipeViewModel.EstimatedCookingTimeInMinutes = recipe.Fields.estimated_cooking_time_in_minutes;\n                recipeViewModel.IngredientList = recipe.Fields.ingredient_list;\n                recipeViewModel.Instructions = recipe.Fields.instructions;\n\n                viewModel.Recipes.Add(recipeViewModel);\n            }\n\n            return View(viewModel);\n        }\n\n        [Route(recipe/{slug})]\n        public virtual ActionResult Recipe(string slug)\n        {\n            var butterClient = new ButterCMSClient(\"API KEY\");\n\n            PageResponse\u003cRecipePage\u003e recipe = butterClient.RetrievePage\u003cRecipePage\u003e(\"recipe\", slug);\n\n            var viewModel = new RecipeViewModel();\n            viewModel.Category = recipe.Data.Fields.category;\n            viewModel.RecipeName = recipe.Data.Fields.recipe_name;\n            viewModel.MainIngredient = recipe.Data.Fields.main_ingredient;\n            viewModel.EstimatedCookingTimeInMinutes = recipe.Data.Fields.estimated_cooking_time_in_minutes;\n            viewModel.IngredientList = recipe.Data.Fields.ingredient_list;\n            viewModel.Instructions = recipe.Data.Fields.instructions;\n\n            return View(viewModel);\n        }\n    }\n\n    public class RecipesViewModel\n    {\n        public List\u003cRecipeViewModel\u003e Recipes { get; set; }\n        public int? PreviousPageNumber { get; set; }\n        public int? NextPageNumber { get; set; }\n        public int PagesCount { get; set; }\n    }\n\n    public class RecipeViewModel\n    {\n        public string Category { get; set; }\n        public string RecipeName { get; set; }\n        public string MainIngredient { get; set; }\n        public double EstimatedCookingTimeInMinutes { get; set; }\n        public string IngredientList { get; set; }\n        public string Instructions { get; set; }\n    }\n\n}\n\n\n```\n\n##### Example View usage for ListPages\n\n```HTML\n@using HungryDevApp\n@{\nLayout = \"~/Views/Shared/Layouts/_Layout.cshtml\";\n}\n@model RecipesViewModel\n\u003cdiv\u003e\n    \u003ca href=\"/recipes/?page=@{Model.PreviousPageNumber}\u0026pageSize=10\"\u003ePrevious page\u003c/a\u003e\n    \u003ca href=\"/recipes/?page=@{Model.NextPageNumber}\u0026pageSize=10\"\u003eNext page\u003c/a\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n    \u003cp\u003e@{Model.PagesCount} recipes total\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n    \u003cul\u003e\n        @foreach(var page in Model.Recipes)\n        {\n            \u003cli\u003e\n                \u003ca href=\"/recipe/@{page.Slug}\"\u003e@{page.RecipeName}\n            \u003c/li\u003e\n        }\n    \u003c/ul\u003e\n\u003c/div\u003e\n\n```\n\n##### Example View usage for RetrievePage\n\n```HTML\n@using HungryDevApp\n@{\nLayout = \"~/Views/Shared/Layouts/_Layout.cshtml\";\n}\n@model RecipeViewModel\n\u003cdiv\u003e\n    \u003ch2\u003e@{Model.RecipeName}\u003c/h2\u003e\n    \u003cp\u003eEstimated cooking time: @{Model.EstimatedCookingTimeInMinutes} minutes\u003c/p\u003e\n    \u003ch3\u003eIngredients:\u003c/h3\u003e\n    \u003cp\u003e@{Model.IngredientList}\u003c/p\u003e\n    \u003ch3\u003eInstructions:\u003c/h3\u003e\n    \u003cp\u003e@{Model.Instructions}\u003c/p\u003e\n\u003c/div\u003e\n\n```\n\n## Class Definitions\n\n### PostsResponse Class\n\n| Property | Type|\n|----|---|\n|Meta| [PostsMeta](#postsmeta-class)|\n|Data| IEnumerable\u0026lt;[Post](#post-class)\u0026gt;|\n\n### PostsMeta Class\n\n| Property | Type|\n|----|---|\n|Count| int|\n|NextPage| int?|\n|PreviousPage| int?|\n\n### Post Class\n\n| Property | Type|\n|----|---|\n|Url|string|\n|Created|DateTime|\n|Published|DateTime|\n|Author|[Author](#author-class)|\n|Categories|IEnumerable\u0026lt;[Category](#category-class)\u0026gt;\n|FeaturedImage| string|\n|FeaturedImageAlt| string|\n|Slug|string|\n|Title|string|\n|Body|string|\n|Summary|string|\n|SeoTitle|string|\n|MetaDescription|string|\n|Status|[StatusEnum](#statusenum)|\n|Scheduled|DateTime|\n\n### StatusEnum\n\n|Constant|Value|\n|---|---|\n|Unknown|0|\n|Draft|1|\n|Published|2|\n|Scheduled|3|\n\n\n### PostResponse Class\n\n| Property | Type|\n|----|---|\n|Meta|[PostMeta](#postmeta-class)|\n|Data|[Post](#post-class)|\n\n### PostMeta Class\n\n| Property | Type|\n|----|---|\n|NextPost|[PostLight](#postlight-class)|\n|PreviousPost|[PostLight](#postlight-class)|\n\n### PostLight Class\n\n| Property | Type|\n|----|---|\n|Slug|string|\n|Title|string|\n|FeaturedImage|string|\n\n### Author Class\n\n| Property | Type|\n|----|---|\n|FirstName| string|\n|LastName| string|\n|Email| string|\n|Slug| string|\n|Bio| string|\n|Title| string|\n|LinkedinUrl| string|\n|FacebookUrl| string|\n|InstagramUrl| string|\n|PinterestUrl| string|\n|TwitterHandle| string|\n|ProfileImage| string|\n|RecentPosts| IEnumerable\u0026lt;[Post](#post-class)\u0026gt;|\n\n### Category Class\n\n| Property | Type|\n|----|---|\n|Name| string|\n|Slug| string|\n|RecentPosts| IEnumerable\u0026lt;[Post](#post-class)\u0026gt;|\n\n### PagesResponse Class\n\n| Property | Type|\n|----|---|\n|Meta| [PageMeta](#pagemeta-class)|\n|Data| IEnumerable\u0026lt;[Page](#page-class)\u0026lt;T\u0026gt;\u0026gt;|\n\n### PageMeta Class\n\n| Property | Type|\n|----|---|\n|Count| int|\n|PreviousPage| int?|\n|NextPage| int?|\n\n### PageResponse Class\n\n| Property | Type|\n|----|---|\n|Data| [Page](#page-class)\u0026lt;T\u0026gt;|\n\n### Page Class\n\n| Property | Type|\n|----|---|\n|Slug| string|\n|Updated| DateTime|\n|Published| DateTime?|\n|PageType| string|\n|Fields|T|\n|Status|[StatusEnum](#statusenum)|\n|Scheduled| DateTime|\n\n## Exceptions\n\n## Testing\n\nTo run SDK test just simply:\n\n```\nPM\u003e dotnet test\n```\n\nOr use Visual Studio Test Explorer. \n\n### InvalidKeyException\n\nThe library throws this exception when the Butter API key used to instatiate the client was not valid.\n\n### ContentFieldObjectMismatchException\n\nThis exception will be thrown when the library can't fit the returned data from a Content Field request into the passed object class.\n\n### PagesObjectMismatchException\n\nThis exception will be thrown when the library can't fit the returned data from a Pages request into the passed object class.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuttercms%2Fbuttercms-csharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbuttercms%2Fbuttercms-csharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuttercms%2Fbuttercms-csharp/lists"}