コミュニティアチーブメントバーを展開する。

解決済み

How to call replicate on API created page

Avatar

Level 2

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}");
        }
    }
}

 

トピック

トピックはコミュニティのコンテンツの分類に役立ち、関連コンテンツを発見する可能性を広げます。

1 受け入れられたソリューション

Avatar

正解者
Level 2

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");
        }

    }
}

元の投稿で解決策を見る

3 返信

Avatar

Level 9

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.

Avatar

Level 5

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.

chrome-copy-as-curl.png

Avatar

正解者
Level 2

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");
        }

    }
}