What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
SDKs
Upgrade the Agility CMS .NET Management SDK from 1.x to 2.0: setup, options, behaviour changes, renamed models, and a map from every 1.x method to its 2.0 replacement.
Version 2.0 of the .NET Management SDK is a rewrite. The Management API it calls is the same, but the SDK's shape changed: one consistent argument order, async methods with cancellation, models named after the API's schemas, typed errors, and saves that wait for their batch. This guide maps each 1.x call to its 2.0 replacement.
Using 1.x? Version 1.x targets .NET 6, so it runs on .NET 6 or later, and it gets fixes only. .NET 6 and 7 are already out of support, and .NET 8 and 9 reach end of support on November 10, 2026, so move to .NET 10 and SDK 2.0 for new and upgraded projects. The 1.x documentation and source are in the 1.0.12-beta release on GitHub, and the package is Agility.Management.SDK 1.0.12-beta on NuGet. Use 1.0.12-beta or later: earlier 1.x versions remove every zone's default components when they save a page model.
net10.0 first.Agility.Management.SDK. Update it to 2.0:dotnet add package Agility.Management.SDK --version 2.0.0
For an introduction to the 2.0 client, see the Management SDK intro.
// 1.x
var clientInstance = new ClientInstance(new Options { token = token });
var item = await clientInstance.contentMethods.GetContentItem(42, guid, "en-us");
// 2.0
using var client = new AgilityManagementClient(new AgilityManagementOptions { AccessToken = token });
var item = await client.Content.GetContentItemAsync(guid, "en-us", 42);
management.api.sdk is now Agility.Management.Sdk. The area clients are in Agility.Management.Sdk.Clients. agility.models and agility.enums are both now Agility.Management.Sdk.Models.(id, guid, locale) and (guid, locale, id).*Methods properties become area properties: contentMethods becomes client.Content, pageMethods becomes client.Pages, and so on.GetContentListAsync (ContentListOptions), SavePageAsync (SavePageOptions) and GetContainerListPagedAsync (ContainerListOptions).Async and takes a CancellationToken.services.AddAgilityManagement(...).1.x Options | 2.0 AgilityManagementOptions |
|---|---|
token | AccessToken |
refresh_token (unused in 1.x) | RefreshToken: the client now uses it to get and renew access tokens |
baseUrl (ignored in 1.x) | BaseUrl: now honoured |
duration (ms between batch checks) | BatchPolling.Interval (a TimeSpan) |
retryCount (batch checks) | BatchPolling.Timeout (a TimeSpan, default 15 minutes) |
Local / BaseLocalURL environment variables | BaseUrl |
| Area | 1.x | 2.0 |
|---|---|---|
| Page model saves | Sent every zone's default components as [], clearing them | Leaves DefaultModules out unless you set it. A read-then-save keeps them. |
| Batch operations | Returned the first item's ID, or threw ApplicationException on timeout | Return a BatchResult (batch ID, every item ID, the batch). Failed items throw AgilityBatchException. |
| Batch wait | Stopped at half the configured budget (the counter was decremented twice per check) | Waits the full BatchPolling.Timeout |
| Errors | ApplicationException with a message | AgilityManagementException with status code, API message, body and request ID |
| Retries | None | Reads are retried on transient failures; writes never are |
| Content lists | Called a hidden GET route that ignored filter | Calls the documented POST route with a ContentListFilterModel |
USA 2 region (-us2) | Sent to the USA host | Sent to mgmt-usa2.aglty.io |
| Unknown GUID suffix | Silently used the USA host | Throws ArgumentException |
| Query values | Not URL-encoded | Encoded (fixes emails with +, folders with spaces) |
| Async | Blocked on .Result inside async methods | Fully asynchronous |
For how batches, errors and retries work in 2.0, see the intro.
Models are generated from the API's OpenAPI schemas, so some names changed, and properties are PascalCase.
| 1.x | 2.0 |
|---|---|
Container | ContentContainer |
Model, ModelField | ContentModel, ContentModelField |
Media | AssetMedia |
PagedResult<Container> | ContentContainerPagedResult |
ContentItem.contentID, .properties, .fields | ContentItem.ContentID, .Properties, .Fields |
ContentItem.fields (Dictionary<string, object>) | ContentItem.Fields (JsonObject) |
ContentItem.GetField(name, type) | item.Fields?[name]?.GetValue<T>() |
ContentList.items (ArrayList) | ContentList.Items (List<JsonNode>) |
Collections on models are null until you set them (1.x initialised some to empty lists). Before adding to one on a new object, create it:
zone.DefaultModules ??= [];
Leaving a collection null means "don't change it". See Null means omit.
Every 2.0 method below also takes the instance GUID as its first argument (shown as guid). Methods marked † return a BatchResult instead of an ID: use result.ItemId for the old return value.
assetMethods becomes client.Assets. See Assets.
| 1.x | 2.0 |
|---|---|
Upload(files, guid, folderPath, groupingID) | UploadAsync(guid, folderPath, [new AssetUpload(name, stream)], galleryId) |
CreateFolder(originKey, guid) | CreateFolderAsync(guid, originKey) |
DeleteFile(mediaID, guid) | DeleteAssetAsync(guid, mediaId) |
MoveFile(mediaID, newFolder, guid) | MoveAssetAsync(guid, mediaId, newFolder) |
GetMediaList(pageSize, recordOffset, guid) | GetMediaListAsync(guid, pageSize, recordOffset) |
GetGalleries(guid, search, pageSize, rowIndex) | GetGalleriesAsync(guid, search, pageSize, rowIndex) |
GetGalleryById(guid, id) | GetGalleryAsync(guid, galleryId) |
GetGalleryByName(guid, name) | GetGalleryByNameAsync(guid, galleryName) |
GetDefaultContainer(guid) | GetDefaultContainerAsync(guid) |
SaveGallery(guid, gallery) | SaveGalleryAsync(guid, gallery) |
DeleteGallery(guid, id) | DeleteGalleryAsync(guid, galleryId) |
GetAssetByID(mediaID, guid) | GetAssetAsync(guid, mediaId) |
GetAssetByURL(url, guid) | GetAssetByUrlAsync(guid, url) |
batchMethods becomes client.Batches.
| 1.x | 2.0 |
|---|---|
GetBatch(id, guid) | GetBatchAsync(guid, batchId) |
Retry(func) | WaitForBatchAsync(guid, batchId); batch operations wait on their own |
contentMethods.GetBatchObject / pageMethods.GetBatchObject | GetBatchAsync(guid, batchId) |
containerMethods becomes client.Containers. See Containers.
| 1.x | 2.0 |
|---|---|
GetContainerById(id, guid) | GetContainerAsync(guid, containerId) |
GetContainerByReferenceName(name, guid) | GetContainerByReferenceNameAsync(guid, referenceName) |
GetContainersByModel(modelId, guid) | GetContainersByModelAsync(guid, modelId) |
GetContainerSecurity(id, guid) | GetContainerSecurityAsync(guid, containerId) |
GetContainerList(guid) | GetContainerListAsync(guid) |
GetContainerListPaged(guid, ...) | GetContainerListPagedAsync(guid, new ContainerListOptions { ... }) |
GetNotificationList(id, guid) | GetNotificationsAsync(guid, containerId) |
SaveContainer(container, guid) | SaveContainerAsync(guid, container) |
DeleteContainer(id, guid) | DeleteContainerAsync(guid, containerId) |
contentMethods becomes client.Content. See Content.
| 1.x | 2.0 |
|---|---|
GetContentItem(contentID, guid, locale) | GetContentItemAsync(guid, locale, contentId) |
GetContentItems(referenceName, guid, locale, filter, fields, sortDirection, sortField, take, skip) | GetContentListAsync(guid, locale, referenceName, new ContentListOptions { Filter, Take, Skip, Fields, SortField, SortDirection }) |
SaveContentItem(item, guid, locale) † | SaveContentItemAsync(guid, locale, item) |
SaveContentItems(items, guid, locale) | SaveContentItemsAsync(guid, locale, items): use result.ItemIds. Failures throw instead of appearing as strings in the list. |
DeleteContent(contentID, guid, locale, comments) † | DeleteContentItemAsync(guid, locale, contentId, comments) |
PublishContent(...) † | PublishContentItemAsync(guid, locale, contentId, comments) |
UnPublishContent(...) † | UnpublishContentItemAsync(guid, locale, contentId, comments) |
ApproveContent(...) † | ApproveContentItemAsync(guid, locale, contentId, comments) |
DeclineContent(...) † | DeclineContentItemAsync(guid, locale, contentId, comments) |
ContentRequestApproval(...) † | RequestApprovalContentItemAsync(guid, locale, contentId, comments) |
Note: In 2.0,
ContentListOptions.Filteris aContentListFilterModel, not a string. Thefilterstring from 1.x is gone, because the route 1.x called ignored it.
instanceUserMethods becomes client.InstanceUsers. See Instance Users.
| 1.x | 2.0 |
|---|---|
GetUsers(guid) | GetUsersAsync(guid) |
SaveUser(email, roles, guid, first, last) | SaveUserAsync(guid, email, roles, firstName, lastName) |
DeleteUser(userID, guid) | DeleteUserAsync(guid, userId) |
modelMethods becomes client.Models. See Models.
| 1.x | 2.0 |
|---|---|
GetContentModel(id, guid) | GetModelAsync(guid, modelId) |
GetModelByReferenceName(name, guid) | GetModelByReferenceNameAsync(guid, referenceName) |
GetContentModules(includeDefaults, guid, includeModules) | GetContentModelsAsync(guid, includeDefaults, includeModules) |
GetPageModules(guid, includeDefault) | GetComponentModelsAsync(guid, includeDefault) |
SaveModel(model, guid) | SaveModelAsync(guid, model) |
DeleteModel(id, guid) | DeleteModelAsync(guid, modelId) |
pageMethods becomes client.Pages. See Pages.
| 1.x | 2.0 |
|---|---|
GetSiteMap(guid, locale) | GetSitemapAsync(guid, locale) |
GetPage(pageID, guid, locale) | GetPageAsync(guid, locale, pageId) |
SavePage(page, guid, locale, parentPageID, placeBeforePageItemID, pageIDInOtherLocale, otherLocale) † | SavePageAsync(guid, locale, page, new SavePageOptions { ParentPageId, PlaceBeforePageId, OtherLocale, PageIdInOtherLocale }): settings left null use the API's defaults |
DeletePage(...) † | DeletePageAsync(guid, locale, pageId, comments) |
PublishPage / UnPublishPage / ApprovePage / DeclinePage / PageRequestApproval † | PublishPageAsync / UnpublishPageAsync / ApprovePageAsync / DeclinePageAsync / RequestApprovalPageAsync, each (guid, locale, pageId, comments) |
GetPageTemplates(guid, locale, includeModuleZones, searchFilter) | GetPageTemplatesAsync(guid, locale, includeModuleZones, searchFilter) |
GetPageTemplate(guid, locale, id) | GetPageTemplateAsync(guid, locale, pageTemplateId) |
GetPageTemplateByName(guid, locale, name) | GetPageTemplateByNameAsync(guid, locale, templateName) |
GetPageItemTemplates(guid, locale, id) | GetPageTemplateZonesAsync(guid, locale, pageTemplateId) |
SavePageTemplate(guid, locale, template) | SavePageTemplateAsync(guid, locale, template) |
DeletePageTemplate(guid, locale, id) | DeletePageTemplateAsync(guid, locale, pageTemplateId) |
Delete methods that returned the API's message string now return Task. A failure throws.
ClientInstance, Options and the *Methods classes. Use AgilityManagementClient, AgilityManagementOptions and the area properties, as above.ContentItem.GetField. Read Fields directly.filter string on content lists.System.Net.Http and source-generated System.Text.Json. RestSharp is no longer a dependency.null properties are left out of requests. The API keeps a stored list it isn't sent, and rejects an explicit null for many properties.User-Agent (agility-management-sdk-dotnet/<version>), with an optional application name from ApplicationName, and an X-Agility-SDK header with the same product token.2.0 covers every operation in the Management API's OpenAPI spec. New areas and operations include:
The API coverage table on GitHub lists every API operation and the SDK method that calls it. The full list of changes is in the changelog.