Skip to content

Commit 072287d

Browse files
authored
Merge pull request #7678 from cornehoskam/engage/v17-update
Update Engage v17 examples & requirements
2 parents 1ec207b + 8a91a2e commit 072287d

File tree

15 files changed

+262
-162
lines changed

15 files changed

+262
-162
lines changed

17/umbraco-engage/developers/ab-testing/csharp-api.md

Lines changed: 15 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,75 +10,14 @@ description: >-
1010

1111
You can retrieve the active A/B test variants for a visitor in different ways depending on your specific scenario:
1212

13-
* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, pageId, culture, contentTypeId)`
13+
* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, contentId, culture, contentTypeId)`
1414
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces`
15-
* Retrieves active A/B test variants on a specific page, without requiring a request context.
15+
* Retrieves active A/B test variants on a specific page using numeric IDs, without requiring a request context.
1616
* The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()`
17-
* `IAbTestVisitorToVariantManager.GetActiveVisitorVariants(visitorExternalId)`
18-
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting`
19-
* Retrieves _all_ active A/B test variants for the given visitor throughout the website.
20-
* The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()`
21-
22-
### Example - Getting the A/B test variants for the current visitor
23-
24-
This example demonstrates how to create a service that retrieves the active A/B test variants for a specific visitor, content, and culture variation. The service wraps the `IAbTestingVisitorService.GetVisitorAbTestVariants()` method, using the current HttpContext and UmbracoContext to obtain the visitor ID and requested content.
25-
26-
```cs
27-
using Umbraco.Cms.Core.Models.PublishedContent;
28-
using Umbraco.Cms.Core.Web;
29-
using Umbraco.Engage.Infrastructure.AbTesting.Models;
30-
using Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces;
31-
using Umbraco.Engage.Infrastructure.Analytics.Collection.Visitor;
32-
33-
namespace Umbraco.Example;
34-
35-
public class ExampleService
36-
{
37-
private readonly IHttpContextAccessor _httpContextAccessor;
38-
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
39-
private readonly IAnalyticsVisitorExternalIdHandler _externalIdHandler;
40-
private readonly IAbTestingVisitorService _abTestingVisitorService;
41-
42-
public ExampleService(
43-
IHttpContextAccessor httpContextAccessor,
44-
IUmbracoContextAccessor umbracoContextAccessor,
45-
IAnalyticsVisitorExternalIdHandler externalIdHandler,
46-
IAbTestingVisitorService abTestingVisitorService)
47-
{
48-
_httpContextAccessor = httpContextAccessor;
49-
_umbracoContextAccessor = umbracoContextAccessor;
50-
_externalIdHandler = externalIdHandler ;
51-
_abTestingVisitorService = abTestingVisitorService;
52-
}
53-
54-
/// <summary>
55-
/// Gets the active A/B test variants for the current visitor.
56-
/// </summary>
57-
/// <returns>Active <see cref="AbTestVariant"/>s for the visitor, or an empty list if unavailable.</returns>
58-
public IEnumerable<AbTestVariant> GetCurrentVisitorActiveAbTestVariants()
59-
{
60-
if (_httpContextAccessor?.HttpContext is not HttpContext httpCtx ||
61-
_externalIdHandler.GetExternalId(httpCtx) is not Guid externalId)
62-
return [];
63-
64-
if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) ||
65-
umbCtx.PublishedRequest?.Culture is not string culture ||
66-
umbCtx.PublishedRequest?.PublishedContent is not IPublishedContent content)
67-
return [];
68-
69-
return _abTestingVisitorService.GetVisitorAbTestVariants(externalId, content.Id, culture, content.ContentType.Id);
70-
}
71-
}
72-
```
73-
74-
## Retrieving Active A/B test variants
75-
76-
You can retrieve the active A/B test variants for a visitor in different ways depending on your specific scenario:
77-
78-
* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, pageId, culture, contentTypeId)`
17+
* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, contentKey, contentTypeKey, culture)`
7918
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces`
80-
* Retrieves active A/B test variants on a specific page, without requiring a request context.
81-
* The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()`
19+
* Retrieves active A/B test variants on a specific page using GUID keys, without requiring a request context.
20+
* Preferred for new implementations as it uses Umbraco's GUID-based identifiers.
8221
* `IAbTestVisitorToVariantManager.GetActiveVisitorVariants(visitorExternalId)`
8322
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting`
8423
* Retrieves _all_ active A/B test variants for the given visitor throughout the website.
@@ -117,21 +56,26 @@ public class ExampleService
11756
}
11857

11958
/// <summary>
120-
/// Gets the active A/B test variants for the current visitor.
59+
/// Gets the active A/B test variants for the current visitor using GUID keys (recommended).
12160
/// </summary>
12261
/// <returns>Active <see cref="AbTestVariant"/>s for the visitor, or an empty list if unavailable.</returns>
12362
public IEnumerable<AbTestVariant> GetCurrentVisitorActiveAbTestVariants()
12463
{
12564
if (_httpContextAccessor?.HttpContext is not HttpContext httpCtx ||
12665
_externalIdHandler.GetExternalId(httpCtx) is not Guid externalId)
12766
return [];
128-
129-
if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) ||
130-
umbCtx.PublishedRequest?.Culture is not string culture ||
67+
68+
if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) ||
69+
umbCtx.PublishedRequest?.Culture is not string culture ||
13170
umbCtx.PublishedRequest?.PublishedContent is not IPublishedContent content)
13271
return [];
13372

134-
return _abTestingVisitorService.GetVisitorAbTestVariants(externalId, content.Id, culture, content.ContentType.Id);
73+
// Using GUID-based overload (recommended)
74+
return _abTestingVisitorService.GetVisitorAbTestVariants(
75+
externalId,
76+
content.Key,
77+
content.ContentType.Key,
78+
culture);
13579
}
13680
}
13781
```

17/umbraco-engage/developers/analytics/extending-analytics/getting-the-correct-ip-address.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,43 @@ In this case, you may need to provide a custom implementation of the `IHttpConte
1515
The default extractor looks like this:
1616

1717
```csharp
18-
using System.Web;
19-
using Umbraco.Engage.Business.Analytics.Collection.Extractors;
18+
using Microsoft.AspNetCore.Http;
19+
using Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors;
2020

21-
public string ExtractIpAddress(HttpContextBase context)
21+
public string? ExtractIpAddress(HttpContext context)
2222
{
23-
if (context?.Request?.ServerVariables["X-Forwarded-For"] is string ipAddresses)
23+
if (context?.Request?.Headers["X-Forwarded-For"].FirstOrDefault() is string ipAddresses)
2424
{
2525
var ipAddress = ipAddresses.Split(',')[0].Trim();
2626
if (System.Net.IPAddress.TryParse(ipAddress, out _)) return ipAddress;
2727
}
28-
return context?.Request?.UserHostAddress;
28+
return context?.Connection?.RemoteIpAddress?.ToString();
2929
}
3030
```
3131

3232
To override this behavior, implement your own `IHttpContextIpAddressExtractor` and instruct Umbraco to use your extractor instead of the default extractor:
3333

3434
```cs
35-
using Umbraco.Engage.Business.Analytics.Collection.Extractors;
36-
using Umbraco.Core.Composing;
37-
using Umbraco.Core;
35+
using Umbraco.Cms.Core.Composing;
36+
using Umbraco.Cms.Core.DependencyInjection;
37+
using Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors;
3838

39-
[ComposeAfter(typeof(Umbraco.Engage.Business.Analytics.Collection.Extractors.AnalyticsExtractorsComposer))]
40-
public class CustomIpExtractorUserComposer : IUserComposer
39+
[ComposeAfter(typeof(Umbraco.Engage.Infrastructure.Analytics.Collection.Extractors.AnalyticsExtractorsComposer))]
40+
public class CustomIpExtractorComposer : IComposer
4141
{
42-
public void Compose(Composition composition)
42+
public void Compose(IUmbracoBuilder builder)
4343
{
44-
composition.RegisterUnique<IHttpContextIpAddressExtractor, MyIpAddressExtractor>();
44+
builder.Services.AddUnique<IHttpContextIpAddressExtractor, MyIpAddressExtractor>();
4545
}
4646
}
4747
```
4848

4949
{% hint style="info" %}
50-
It is important that your `UserComposer` adjusts the service registration **after** Umbraco Engage has initialized.
50+
It is important that your `Composer` adjusts the service registration **after** Umbraco Engage has initialized.
5151
{% endhint %}
5252

53-
This can be enforced using the `ComposeAfterAttribute`. Failing to add this attribute may result in Umbraco running your IUserComposer before the Umbraco Engage composer, causing your changes to be overwritten.
53+
This can be enforced using the `ComposeAfterAttribute`. Failing to add this attribute may result in Umbraco running your Composer before the Umbraco Engage composer, causing your changes to be overwritten.
5454

55-
Additionally, ensure you use `RegisterUnique<...>()` instead of `Register<...>()`. While you can use Register when multiple implementations of a single service exist, in this case, you want your own extractor to be resolved exclusively. Therefore, RegisterUnique will overwrite the Umbraco Engage extractor.
55+
Additionally, ensure you use `AddUnique<...>()` instead of `AddSingleton<...>()`. While you can use AddSingleton when multiple implementations of a single service exist, in this case, you want your own extractor to be resolved exclusively. Therefore, AddUnique will overwrite the Umbraco Engage extractor.
5656

5757
After implementing both classes and running your project, your extractor should be called to resolve IP addresses. You can verify the output of your extractor by inspecting the `umbracoEngageAnalyticsIpAddress` database table. The last portion of the IP address may be anonymized (set to 0) if this option is enabled in the Umbraco Engage configuration file.

17/umbraco-engage/developers/analytics/location.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Once you have a service that can provide localization information, you must inte
1616

1717
Implement the following interface:
1818

19-
`Umbraco.Engage.Business.Analytics.Processing.Extractors.IRawPageviewLocationExtractor`
19+
`Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors.IRawPageviewLocationExtractor`
2020

2121
This interface allows information about localization for a pageview, defined as a single visitor's visit to a specific point in time. The page view contains the `IpAddress` property that can be used for Geo IP lookup.
2222

@@ -25,8 +25,10 @@ This interface allows information about localization for a pageview, defined as
2525

2626
{% code overflow="wrap" %}
2727
```cs
28-
using Umbraco.Engage.Business.Analytics.Processed;
29-
public class GeoIpLocation : ILocation {
28+
using Umbraco.Engage.Infrastructure.Analytics.Processed;
29+
30+
public class GeoIpLocation : ILocation
31+
{
3032
public string Country { get; set; }
3133
public string County { get; set; }
3234
public string Province { get; set; }
@@ -40,27 +42,29 @@ public class GeoIpLocation : ILocation {
4042

4143
{% code overflow="wrap" %}
4244
```cs
43-
using Umbraco.Engage.Business.Analytics.Processing.Extractors;
45+
using Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors;
46+
4447
public class MyCustomLocationExtractor : IRawPageviewLocationExtractor
4548
{
46-
public ILocation Extract(IRawPageview rawPageview)
49+
public ILocation? Extract(IRawPageview rawPageview)
4750
{
48-
if (!IPAddress.TryParse(rawPageview?.IpAddress, out var ipAddress) || IPAddress.IsLoopback(ipAddress)) return null;
49-
51+
if (!IPAddress.TryParse(rawPageview?.IpAddress, out var ipAddress) || IPAddress.IsLoopback(ipAddress))
52+
return null;
53+
5054
string country, county, province, city;
51-
55+
5256
//...
5357
// Perform your own GEO IP lookup here
5458
// ...
55-
59+
5660
var location = new GeoIpLocation
5761
{
5862
Country = country,
5963
County = county,
6064
Province = province,
6165
City = city
6266
};
63-
67+
6468
return location;
6569
}
6670
}
@@ -69,23 +73,23 @@ public class MyCustomLocationExtractor : IRawPageviewLocationExtractor
6973

7074
4. Let the IoC container know to use your implementation for the `IRawPageviewLocationExtractor`.
7175

72-
Umbraco Engage has a default implementation of this service, which only returns null. This default service is registered using Umbraco's `RegisterUnique` method.
76+
Umbraco Engage has a default implementation of this service, which only returns null. This default service is registered using Umbraco's `AddUnique` method.
7377

74-
5. Override this service by calling `RegisterUnique` **after** the `UmbracoEngageApplicationComposer`.
78+
5. Override this service by calling `AddUnique` **after** the `UmbracoEngageApplicationComposer`.
7579

7680
{% code overflow="wrap" %}
7781
```cs
78-
using Umbraco.Engage.Business.Analytics.Processing.Extractors;
82+
using Umbraco.Cms.Core.Composing;
83+
using Umbraco.Cms.Core.DependencyInjection;
7984
using Umbraco.Engage.Common.Composing;
80-
using Umbraco.Core;
81-
using Umbraco.Core.Composing;
82-
85+
using Umbraco.Engage.Infrastructure.Analytics.Processing.Extractors;
86+
8387
[ComposeAfter(typeof(UmbracoEngageApplicationComposer))]
84-
public class UmbracoEngageComposer: IComposer
88+
public class UmbracoEngageComposer : IComposer
8589
{
8690
public void Compose(IUmbracoBuilder builder)
8791
{
88-
builder.services.AddUnique<IRawPageviewLocationExtractor, MyCustomLocationExtractor>();
92+
builder.Services.AddUnique<IRawPageviewLocationExtractor, MyCustomLocationExtractor>();
8993
}
9094
}
9195
```

17/umbraco-engage/developers/headless/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
description: >-
3-
Discover how to integrate Umbraco.Engage.Headless package with Umbraco 12.0+
3+
Discover how to integrate `Umbraco.Engage.Headless` package with Umbraco.
44
for a Content Delivery API.
55
---
66

77
# Headless
88

9-
Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco 12.0 and later. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation.
9+
Umbraco Engage offers the **Umbraco.Engage.Headless** package for seamless integration with Umbraco. This package enables access to the Headless Content Delivery API, enabling personalized content, A/B tests, and segmentation.
1010

1111
{% hint style="info" %}
1212
All Engage features are supported except:
@@ -28,7 +28,7 @@ All Engage features are supported except:
2828

2929
To install Umbraco.Engage.Headless, ensure the following prerequisites:
3030

31-
* Umbraco v13 is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api).
31+
* The latest version of Umbraco is required to integrate with the [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api).
3232
* Enable the [Umbraco Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api#enable-the-content-delivery-api) by adding the following configuration setting in the `appsettings.json` file:
3333

3434
```json

17/umbraco-engage/developers/headless/using-the-marketing-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ To track a page view, send a POST request to:
6262
* `/umbraco/engage/api/v1/analytics/pageview/trackpageview/client`
6363

6464
* Required: `url` property of the page that a user has visited in the site
65-
* Optional: `reffererUrl` can be set to inform Umbraco Engage where the user came from.
65+
* Optional: `referrerUrl` can be set to inform Umbraco Engage where the user came from.
6666

6767
* `/umbraco/engage/api/v1/analytics/pageview/trackpageview/server`
6868

17/umbraco-engage/developers/introduction/the-umbraco-engage-cookie/module-permissions.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ description: >-
88

99
You could choose to give visitors control over these settings through a cookie bar on your site.
1010

11-
To do this you have to create an implementation of the `Umbraco.Engage.Business.Permissions.ModulePermissions.IModulePermissions` interface and override our default implementation.
11+
To do this you have to create an implementation of the `Umbraco.Engage.Infrastructure.Permissions.ModulePermissions.IModulePermissions` interface and override our default implementation.
1212

1313
This interface defines 3 methods that you will have to implement:
1414

@@ -21,7 +21,7 @@ This interface defines 3 methods that you will have to implement:
2121
/// </summary>
2222
/// <param name="context">Context of the request</param>
2323
/// <returns>True if A/B testing is allowed, otherwise false.</returns>
24-
bool AbTestingIsAllowed(HttpContextBase context);
24+
bool AbTestingIsAllowed(HttpContext context);
2525

2626
/// <summary>
2727
/// Indicates if Analytics is allowed for the given request context.
@@ -33,37 +33,37 @@ bool AbTestingIsAllowed(HttpContextBase context);
3333
/// </summary>
3434
/// <param name="context">Context of the request</param>
3535
/// <returns>True if Analytics is allowed, otherwise false.</returns>
36-
bool AnalyticsIsAllowed(HttpContextBase context);
36+
bool AnalyticsIsAllowed(HttpContext context);
3737

3838
/// <summary>
3939
/// Indicates if Personalization testing is allowed for the given request context.
4040
/// If false, the visitor will not see any personalized content.
4141
/// </summary>
4242
/// <param name="context">Context of the request</param>
4343
/// <returns>True if Personalization is allowed, otherwise false.</returns>
44-
bool PersonalizationIsAllowed(HttpContextBase context);
44+
bool PersonalizationIsAllowed(HttpContext context);
4545
```
4646
{% endcode %}
4747

48-
Using these methods you can control per visitor whether or not the modules are active. Your implementation will need to be registered with Umbraco using the `RegisterUnique()` method, overriding the default implementation which enables all modules all the time. Make sure your composer runs after the Umbraco Engage composer by using the `[ComposeAfter]` attribute.
48+
Using these methods you can control per visitor whether or not the modules are active. Your implementation will need to be registered with Umbraco using the `AddUnique()` method, overriding the default implementation which enables all modules all the time. Make sure your composer runs after the Umbraco Engage composer by using the `[ComposeAfter]` attribute.
4949

5050
It could look something like this:
5151

5252
{% code overflow="wrap" %}
5353
```csharp
54-
using Umbraco.Engage.Infrastructure.Permissions.ModulePermissions;
54+
using Umbraco.Cms.Core.Composing;
55+
using Umbraco.Cms.Core.DependencyInjection;
5556
using Umbraco.Engage.Common.Composing;
56-
using Umbraco.Core;
57-
using Umbraco.Core.Composing;
57+
using Umbraco.Engage.Infrastructure.Permissions.ModulePermissions;
5858

59-
namespace YourNamespace
59+
namespace YourNamespace
6060
{
6161
[ComposeAfter(typeof(UmbracoEngageApplicationComposer))]
6262
public class YourComposer : IComposer
6363
{
64-
public void Compose(Composition composition)
64+
public void Compose(IUmbracoBuilder builder)
6565
{
66-
composition.RegisterUnique<IModulePermissions, YourCustomModulePermissions>();
66+
builder.Services.AddUnique<IModulePermissions, YourCustomModulePermissions>();
6767
}
6868
}
6969
}

0 commit comments

Comments
 (0)