On-Prem AEM 6.5 SP 21
I'm building an application to create pages automatically based on an input file. I can get the page created, but the created page is not showing the sub-nodes (components) which should appear because of the use of the template page. I have read that in order to resolve this I need to call a "replicate" action on the page i just created to have it "sync" and build the child nodes from the template on the target page.
The problem is the code below is what I'm using and regardless of what environment i try it on I'm getting either unauthorized or invalid request for responses to the replicate call. Even when working on a local development copy using the admin account I encounter this issue.
Looking for assistance in debugging where I'm going wrong with this approach or what else should be checked?
It's the line:
var response = await client.PostAsync($"{aemUrl}/bin/replicate.json", content);
whose result is the error.
public static async Task ReplicateAemPage(string aemUrl, string pagePath, string username, string password)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (HttpClient client = new HttpClient())
{
// 2. Network Credential
var credentials = new NetworkCredential(ConfigurationManager.AppSettings["aemUserID"], ConfigurationManager.AppSettings["aemPassword"]);
var handler = new HttpClientHandler { Credentials = credentials };
using (var clientWithHandler = new HttpClient(handler))
{
var content = new MultipartFormDataContent();
content.Add(new StringContent(pagePath), "path");
content.Add(new StringContent("true"), "ignoredeactivated"); // often needed
content.Add(new StringContent("replicate"), "cmd");
try
{
var response = await client.PostAsync($"{aemUrl}/bin/replicate.json", content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Page '{pagePath}' replicated successfully.");
}
else
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error replicating page: Status code: {response.StatusCode}, Response: {responseContent}");
throw new Exception($"Error replicating page: Status code: {response.StatusCode}, Response: {responseContent}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error during replication: {ex.Message}");
}
}
}
}
public static async Task CreateAemPage(string aemUrl, string parentPath, string pageName, string pageTitle, string templatePath, string username, string password)
{
string slingResourceType = templatePath.Replace("/conf/soi/settings/wcm/templates", "soi/components/structure");
using (var httpClientHandler = new HttpClientHandler() { Credentials = new NetworkCredential(username, password) })
using (var client = new HttpClient(httpClientHandler))
{
var content = new MultipartFormDataContent();
//Required properties for creating a page
content.Add(new StringContent("cq:Page"), "jcr:primaryType");
content.Add(new StringContent("cq:PageContent"), "jcr:content/jcr:primaryType");
content.Add(new StringContent(templatePath), "jcr:content/cq:template");
content.Add(new StringContent(pageTitle), "jcr:content/jcr:title");
content.Add(new StringContent(slingResourceType), "jcr:content/sling:resourceType"); //Change to your page resource type
//content.Add(new StringContent(pageTitle), "jcr:content/par/title/title"); // Set the title component's title property.
//content.Add(new StringContent("nt:unstructured"), "jcr:content/par/text/jcr:primaryType");
//content.Add(new StringContent("my-site/components/text"), "jcr:content/par/text/sling:resourceType"); // Change to your text component resource type
//content.Add(new StringContent($"<h1>{pageTitle}</h1>"), "jcr:content/par/text/text"); // Use the h1 value.
try
{
// Ensure the URL ends with a slash if needed by AEM
string fullUrl = $"{aemUrl}{parentPath}/{pageName}";
if (!fullUrl.EndsWith("/"))
{
fullUrl = fullUrl.TrimEnd('/');
}
var response = await client.PostAsync(fullUrl, content);
// Improved error handling
if (response.IsSuccessStatusCode)
{
string pagePath = $"{parentPath}/{pageName}";
await ReplicateAemPage(aemUrl, pagePath, username, password); // Implement this function
Console.WriteLine($"Page '{pageName}' created successfully.");
}
else
{
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating page: Status code: {response.StatusCode}, Response: {responseContent}");
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error creating page: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
}
}
}
解決済! 解決策の投稿を見る。
トピックはコミュニティのコンテンツの分類に役立ち、関連コンテンツを発見する可能性を広げます。
表示
返信
いいね!の合計
I actually found a better way to do it where it doesn't require a secondary call. For those curious the revised code is below. Obviously there is more error checking and exception handling needed, but it got me past the issue.
public static async Task CreateAemPageWithWcmCommand(string aemUrl, string parentPath, string pagename, string pagetitle, string templatePath, string pageContent,string username, string password)
{
string templatePathDefault = "/conf/soi/settings/wcm/templates/agency-left-navigation-page";
string template = templatePath.Replace("/conf/soi/settings/wcm/templates/", "");
using (var httpClientHandler = new HttpClientHandler() { Credentials = new NetworkCredential(username, password) })
using (var client = new HttpClient(httpClientHandler))
{
var content = new MultipartFormDataContent();
content.Add(new StringContent("createPage"), "cmd");
content.Add(new StringContent(pagename), "label");
content.Add(new StringContent(parentPath), "parentPath");
content.Add(new StringContent(templatePath), "template");
content.Add(new StringContent(pagetitle), "title");
try
{
var response = await client.PostAsync($"{aemUrl}/bin/wcmcommand", content);
response.EnsureSuccessStatusCode(); // Throw exception for non-success status codes
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Page creation successful. Response: {responseContent}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error creating page: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
}
string textComponentPath = "";
// 2. Populate the Text Component using Sling POST servlet
switch (template)
{
case "agency-left-navigation-page":
textComponentPath = $"{parentPath}/{pagename}/jcr:content/responsivegrid/container/container_293684588/container/text"; // Set component path for left-nav pages
break;
case "agency-full-width-open-page":
textComponentPath = $"{parentPath}/{pagename}/jcr:content/responsivegrid/container/container/text"; // Set component path for left-nav pages
break;
default:
break ;
}
if (textComponentPath != "")
{
var textContentData = new MultipartFormDataContent();
textContentData.Add(new StringContent(pageContent), "text");
var textResponse = await client.PostAsync($"{aemUrl}{textComponentPath}", textContentData);
textResponse.EnsureSuccessStatusCode();
string textResponseContent = await textResponse.Content.ReadAsStringAsync();
Console.WriteLine($"Text component populated. Response: {textResponseContent}");
}
else
{
Console.WriteLine($"No component path set for this information");
}
}
}
Hi @ShaggySPFLD ,
Do you send credentials as a Basic Auth? Your request to AEM should contain basic Authorization header like:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Best regards,
Kostiantyn Diachenko.
When you encounter issues with APIs, you can open a browser window on the AEM page you're interested in. Then, access the Network tab in the developer tools, where all requests are listed. Perform the action you want to investigate (for example, replication) with UI. Once the corresponding call appears in the Network tab, you can right-click on it and select "Copy as cURL." This will provide you with a fully functional request that includes all headers and cookies, allowing you to troubleshoot any differences between this request and your code.
I actually found a better way to do it where it doesn't require a secondary call. For those curious the revised code is below. Obviously there is more error checking and exception handling needed, but it got me past the issue.
public static async Task CreateAemPageWithWcmCommand(string aemUrl, string parentPath, string pagename, string pagetitle, string templatePath, string pageContent,string username, string password)
{
string templatePathDefault = "/conf/soi/settings/wcm/templates/agency-left-navigation-page";
string template = templatePath.Replace("/conf/soi/settings/wcm/templates/", "");
using (var httpClientHandler = new HttpClientHandler() { Credentials = new NetworkCredential(username, password) })
using (var client = new HttpClient(httpClientHandler))
{
var content = new MultipartFormDataContent();
content.Add(new StringContent("createPage"), "cmd");
content.Add(new StringContent(pagename), "label");
content.Add(new StringContent(parentPath), "parentPath");
content.Add(new StringContent(templatePath), "template");
content.Add(new StringContent(pagetitle), "title");
try
{
var response = await client.PostAsync($"{aemUrl}/bin/wcmcommand", content);
response.EnsureSuccessStatusCode(); // Throw exception for non-success status codes
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Page creation successful. Response: {responseContent}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error creating page: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
}
string textComponentPath = "";
// 2. Populate the Text Component using Sling POST servlet
switch (template)
{
case "agency-left-navigation-page":
textComponentPath = $"{parentPath}/{pagename}/jcr:content/responsivegrid/container/container_293684588/container/text"; // Set component path for left-nav pages
break;
case "agency-full-width-open-page":
textComponentPath = $"{parentPath}/{pagename}/jcr:content/responsivegrid/container/container/text"; // Set component path for left-nav pages
break;
default:
break ;
}
if (textComponentPath != "")
{
var textContentData = new MultipartFormDataContent();
textContentData.Add(new StringContent(pageContent), "text");
var textResponse = await client.PostAsync($"{aemUrl}{textComponentPath}", textContentData);
textResponse.EnsureSuccessStatusCode();
string textResponseContent = await textResponse.Content.ReadAsStringAsync();
Console.WriteLine($"Text component populated. Response: {textResponseContent}");
}
else
{
Console.WriteLine($"No component path set for this information");
}
}
}