---
title: "Generate public links containing the asset filename"
slug: "generate-public-links-containing-the-asset-filename"
abstract: "Web script example that shows how to automatically generate public links containing the filenames of all associated assets."
---
# Generate public links containing the asset filename

This action script example describes how to create a public link that includes the filename of its associated asset. The action occurs in the *pre-commit* phase (in-process), meaning the script is executed before the triggering changes are made – in this example, it happens whenever a public link is created.

> [!note]
> **Before you begin**
> -   Confirm that the schema includes the necessary properties for generating public links, such as asset identifiers.
>
> -   Ensure that users or roles who run this script have the correct permissions that allow public link generation.

## Script

```csharp
using System.Linq;

var publicLink = Context.Target as IEntity;

// Ensure that the following members are loaded
await publicLink.LoadMembersAsync(new PropertyLoadOption("RelativeUrl", "Resource"), new RelationLoadOption("AssetToPublicLink"));
var assetToPublicLinkRelation = publicLink.GetRelation<IChildToManyParentsRelation>("AssetToPublicLink");
var assetToPublicLinkRelationValues = assetToPublicLinkRelation.GetIds();

// Ensure that the public link is linked to an asset, exit otherwise
if (assetToPublicLinkRelationValues?.Count > 0)
    MClient.Logger.Info(String.Join(",", assetToPublicLinkRelationValues.Select(x => x.ToString())));
else
{
    MClient.Logger.Warn($"Public link with id {publicLink.Id} is not associated with an asset");
    return;
}

// Get the asset id
var assetId = assetToPublicLinkRelationValues.First();

// Populate the load configuration
var loadConfig = new EntityLoadConfiguration(
    CultureLoadOption.Default,
    new PropertyLoadOption("FileName"),
    RelationLoadOption.None);

// Load the asset
var asset = await MClient.Entities.GetAsync(assetId, loadConfig);
if (asset == null)
{
    MClient.Logger.Error($"Could not load asset with id: {assetId}");
    return;
}

// Generate a prefix in case we have multiple public links with the same resource/rendition
var prefix = Guid.NewGuid().ToString("n").Substring(0, 8);

// Properties required for the relative url
var filename = asset.GetPropertyValue<string>("FileName");
var resource = publicLink.GetPropertyValue<string>("Resource");

// Compose the relative url
var relativeUrl = $"{prefix}-{resource}-{filename}";

// Update the relative url
publicLink.SetPropertyValue("RelativeUrl", relativeUrl);

```

## Script explanation

This section steps through the script in execution order, explaining each part. The numbered items describe the sequence, not instructions to perform.

1. Include the following [libraries](https://doc.sitecore.com/ch/en/developers/cloud-dev/script-restriction.html "Script restriction"):

    ```csharp
    using System.Linq;
    using Stylelabs.M.Base.Querying;
    using Stylelabs.M.Base.Querying.Filters;
    using Stylelabs.M.Sdk.Contracts.Base;
    using System.Threading.Tasks;
    using Newtonsoft.Json.Linq;
    using Newtonsoft.Json;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using Stylelabs.M.Framework.Essentials.LoadConfigurations;
    ```

2. Retrieve the `Target` object from the `Context` and casts it to `IEntity`. The `Target` represents the public link being processed. If the `TargetId` is `null`, the script ends without performing any further actions.

    ```csharp
    if (Context.TargetId == null) return;

    var publicLink = Context.Target as IEntity;
    ```

3. Ensure that specific properties (`RelativeUrl`, `Resource`) and relations (`AssetToPublicLink`) are loaded for the public link entity. This is necessary for the script to manipulate these properties and relations later.

    ```text
    await publicLink.LoadMembersAsync(new PropertyLoadOption("RelativeUrl", "Resource"), new RelationLoadOption("AssetToPublicLink"));
    ```

4. Retrieve the ID of the asset associated with the public link via the `AssetToPublicLink` relation. If the public link is not associated with an asset, the script logs a warning and then exits.

    ```csharp
    var assetToPublicLinkRelation = publicLink.GetRelation<IChildToManyParentsRelation>("AssetToPublicLink");
    var assetToPublicLinkRelationValues = assetToPublicLinkRelation.GetIds();

    if (assetToPublicLinkRelationValues?.Count > 0)
        MClient.Logger.Info(String.Join(",", assetToPublicLinkRelationValues.Select(x => x.ToString())));
    else
    {
        MClient.Logger.Warn($"Public link with id {publicLink.Id} is not associated with an asset");
        return;
    }
    ```

5. If the public link is associated with an asset, retrieve the asset's ID and loads the corresponding asset entity. The script specifically loads the `FileName` property of the asset, which it will use to generate the URL.

    ```csharp
    var assetId = assetToPublicLinkRelationValues.First();

    var loadConfig = new EntityLoadConfiguration(
        CultureLoadOption.Default,
        new PropertyLoadOption("FileName"),
        RelationLoadOption.None);

    var asset = await MClient.Entities.GetAsync(assetId, loadConfig);
    if (asset == null)
    {
        MClient.Logger.Error($"Could not load asset with id: {assetId}");
        return;
    }
    ```

6. Generate a unique prefix using a GUID (globally unique identifier). This prefix helps ensure that the relative URL is unique, especially when multiple public links might point to the same resource or rendition.

    ```text
    var prefix = Guid.NewGuid().ToString("n").Substring(0, 8);
    ```

7. Create the relative URL by combining the generated prefix, the resource name from the public link, and the file name of the associated asset. This relative URL is then set as the value of the `RelativeUrl` property of the public link entity.

    ```

    var filename = asset.GetPropertyValue<string>("FileName");
    var resource = publicLink.GetPropertyValue<string>("Resource");

    var relativeUrl = $"{prefix}-{resource}-{filename}";
    publicLink.SetPropertyValue("RelativeUrl", relativeUrl);
    ```

8. Save the updated public link entity, ensuring that the changes are persisted.

    ```text
    await MClient.Entities.SaveAsync(publicLink).ConfigureAwait(false);
    ```

## Setup

To set up your script, action, and trigger:

1. [Create a script](https://doc.sitecore.com/ch/en/developers/cloud-dev/work-with-scripts.html "Work with scripts") of the *Action* type; save your changes, build and publish the script, and then enable it.
2. [Create an action](https://doc.sitecore.com/ch/en/developers/cloud-dev/create-an-action.html "Create an action") of the *Action script* type and link it to your script.
3. [Create a trigger](https://doc.sitecore.com/ch/en/developers/cloud-dev/triggers.html "Triggers"):
    - On the **General** tab, set the *Objective* to *Entity creation*.
    - On the **General** tab, set the *Execution type* to *In process*.
    - On the **Conditions** tab, add a condition for the *M.PublicLink* entity definition.
    - Under this definition, add a new condition for the *Assets(AssetToPublicLink)* entity definition and set it to *has changed*.
    - On the **Actions** tab, add the action created in step 2 under *Pre-commit actions*.
    - Save and activate the trigger.