Reporting user activity in CMS 12

Hi 

I'm trying to use the features of EPiServer.DataAbstraction.Activities to build custom reports available through the CMS edit/admin UI and I need to be able to filter by the ActionType of the Activity logged in tblActivityLog (and / or use the netActvitiyLogList stored procedure). What I can't work out is where the Action value gets set. I've dug through decompiled libraries and looked through the database and cannot see any place the values are defined - not an enum in code or a table in the DB. I think I've hacked back to the values through the markup of the Change Log feature of the CMS admin area but I need to know I have the source of the values to be able to deliver the reports with confidence. Any ideas? Perhaps there's a better way than this? The users want more than can be got through the Change Log feature.

Thanks

Daniel Lack, developer

#342707
Jun 04, 2026 15:57

Hi Daniel,

I’d probably try to go through the public activities API rather than taking the values from the Change Log markup. For content activities, I’d use ContentActionType and filter by both type and action:

var query = new ActivityQuery
{
    ActivityType = ActivityType.Content,
    Action = (int)ContentActionType.Publish
};

var activities = await activityQueryService.ListActivitiesAsync(query);

ActivityQuery.Action is documented as the action filter, and it is passed through to netActvitiyLogList as the action parameter, together with ActivityType as type.

So if you still need to call the stored procedure directly, I’d use the enum value rather than hard-coding values copied from the UI markup. I’d also keep the activity type in the filter, since the action value is tied to the activity type.

#342708
Edited, Jun 05, 2026 8:13

Hi Wojciech

Thanks for the suggestion. I had wondered if there might be a way to do this using a public API call instead of digging around in the internal details of the database. Also you have answered my query about where the values for ActionType are defined, which is very useful to know - https://world.optimizely.com/csclasslibraries/cms/EPiServer.DataAbstraction.Activities.ContentActionType?version=12.

Regards

Daniel

#342724
Jun 05, 2026 12:48

Hi Daniel,

Glad it helped!

Yes, I’d stay with ActivityQuery if it gives you enough for the reports and only drop down to the stored procedure if you hit a limitation

Regards,
Wojciech

#342725
Jun 05, 2026 14:00

Hi Wojciech

I can see that simply adding a reference to IActivityQueryService into a client class' constructor results in an implementation of that interface being injected. Do you know what magic is doing this? I would have expected to have to configure that in Startup.cs, maybe adding it to the services collection.

Thanks,

Daniel

#342743
Jun 09, 2026 14:46

Hi Daniel,

That’s Optimizely registering it for you.

The default implementation has ServiceConfiguration on it:

[ServiceConfiguration(typeof(ActivityQueryService))]
[ServiceConfiguration(typeof(IActivityQueryService))]
internal class DefaultActivityQueryService : ActivityQueryService

So CMS picks it up during startup and adds it to the service container. That’s why constructor injection works without you adding it manually in Startup.cs

For my own services I’d usually still register them explicitly, but a lot of built-in Optimizely services are registered this way

#342749
Edited, Jun 11, 2026 14:28

Hi Wojciech

Thanks so much for the insight! Optimizely / Episerver is a powerful system but I've yet to find a comprehensive guide to what's going on internally, so I must gather the clues as I explore.

Cheers,

Daniel

#342750
Jun 11, 2026 14:32

Hello, 

Yes, the official docs are usually my first stop, especially the class library docs when I’m trying to track down this kind of thing

These two might be useful here:

I also find the community blog posts really useful for the practical side of things, and if it comes down to a very specific implementation detail, looking at the assembly can help as well 

Regards,
Wojciech

#342751
Jun 11, 2026 14:36

Thanks again.

#342752
Jun 11, 2026 14:39

Two gotchas if you build a report on this, checked against the 12.x assembly: the call is IActivityQueryService.ListActivitiesAsync(query) returning IEnumerable<Activity> (cast to ContentActivity), and MaxResults defaults to 100, so page with the FromActivity cursor rather than a huge number. Also CreatedAfter/CreatedBefore are exclusive, which trips you up on month boundaries.

#342776
Jun 13, 2026 9:14
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.