Last active
May 10, 2022 09:08
-
-
Save LucGosso/00ac7a2ece9c135ebf83ca897a0a8ba9 to your computer and use it in GitHub Desktop.
Google Analytics Service v4 C# .netframework example with Episerver. Blogpost https://devblog.gosso.se/?p=766
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Gosso.Web.Business.Services; | |
using EPiServer.DataAbstraction; | |
using EPiServer.PlugIn; | |
using EPiServer.Scheduler; | |
using EPiServer.ServiceLocation; | |
//Episerver Schedual job to update the cache with fresh data from Google Analytics | |
namespace Gosso.Web.Business.Jobs | |
{ | |
[ScheduledPlugIn(DisplayName = "Get Statistics from Analytics (api v4)", | |
Description = | |
"Getting pagesviews from Analytics, and updates the cache")] | |
public class GetPopularItemsFromAnalyticsJob : ScheduledJobBase | |
{ | |
public override string Execute() | |
{ | |
var googleAnalyticsService = ServiceLocator.Current.GetInstance<IGoogleAnalyticsService>(); | |
//var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>(); | |
/int typeid = contentTypeRepository.Load<MyItemPage>().ID; | |
var items = googleAnalyticsService.GetItemViewsfromAnalytics(typeid: 0, useCache: false); | |
return "Found " + items.Count + " items in GA"; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using EPiServer.Core; | |
using EPiServer.Framework.Cache; | |
using EPiServer.ServiceLocation; | |
using Google.Apis.AnalyticsReporting.v4; | |
using Google.Apis.AnalyticsReporting.v4.Data; | |
using Google.Apis.Auth.OAuth2; | |
using Google.Apis.Services; | |
using System; | |
using System.Collections.Generic; | |
using System.Configuration; | |
using System.IO; | |
using System.Linq; | |
namespace Gosso.Web.Business.Services | |
{ | |
[ServiceConfiguration(typeof(IGoogleAnalyticsService), Lifecycle = ServiceInstanceScope.Singleton)] | |
public class GoogleAnalyticsService: IGoogleAnalyticsService | |
{ | |
private readonly ISynchronizedObjectInstanceCache _cache; | |
public GoogleAnalyticsService(ISynchronizedObjectInstanceCache cache) | |
{ | |
_cache = cache; | |
GetGoogleAnalyticDaysMostPopular = 15; | |
} | |
internal readonly string Key = "itemviewsGA"; | |
internal void CachePageItemsOfType(Dictionary<Guid, PageItemViews> pageitems, string cacheKey) | |
{ | |
var cache = ServiceLocator.Current.GetInstance<ISynchronizedObjectInstanceCache>(); | |
_cache.Remove(cacheKey); | |
_cache.Insert(cacheKey, pageitems, CacheEvictionPolicy.Empty); | |
} | |
public Dictionary<Guid, PageItemViews> GetItemViewsfromAnalytics(int typeid = 0, bool useCache = true) | |
{ | |
var cache = ServiceLocator.Current.GetInstance<ISynchronizedObjectInstanceCache>(); | |
var pageItemViews = cache.Get(Key + typeid) as Dictionary<Guid, PageItemViews>; | |
if (pageItemViews == null || !useCache) | |
{ | |
pageItemViews = Execute(GetService(), typeid); | |
CachePageItemsOfType(pageItemViews, Key + typeid); | |
} | |
return pageItemViews; | |
} | |
public IEnumerable<PageData> FilterItemsSortByMostPopular(Dictionary<Guid, PageItemViews> pagesViews, IEnumerable<PageData> articles, string firstSegmentUrl = null) | |
{ | |
if (pagesViews != null) | |
{ | |
var pageViewSorted = from f in pagesViews | |
orderby f.Value.PageViews descending | |
select f; | |
if (!string.IsNullOrEmpty(firstSegmentUrl)) | |
{ | |
//sort and filter | |
pageViewSorted = from f in pageViewSorted | |
where f.Value.CategoryName == firstSegmentUrl | |
orderby f.Value.PageViews descending | |
select f; | |
} | |
//match and join | |
var orderedByIdList = from i in pageViewSorted | |
join p in articles | |
on i.Key equals p.ContentGuid | |
select p; | |
return orderedByIdList.ToList(); | |
} | |
return null; | |
} | |
private AnalyticsReportingService GetService() | |
{ | |
// Google Analytics API Service Account Authentication | |
// found in developer console under APIs & auth / Credentials | |
var keyFilePath = System.Web.Hosting.HostingEnvironment.MapPath(GetGoogleAnalyticsKeyFilePath) + string.Empty; | |
// These are the scopes of permissions you need. It is best to request only what you need and not all of them | |
string[] scopes = new string[] { AnalyticsReportingService.Scope.Analytics }; // View your Google Analytics data | |
GoogleCredential credential; | |
using (var stream = new FileStream(keyFilePath, FileMode.Open, FileAccess.Read)) | |
{ | |
credential = GoogleCredential.FromStream(stream) | |
.CreateScoped(scopes); | |
} | |
// Create the Analytics service. | |
return new AnalyticsReportingService(new BaseClientService.Initializer | |
{ | |
HttpClientInitializer = credential, | |
ApplicationName = "MyApp" // not important | |
}); | |
} | |
private Dictionary<Guid, PageItemViews> Execute(AnalyticsReportingService service, int typeid) | |
{ | |
//format the profile id | |
var profileId = GetGoogleAnalyticsProfileId; | |
if (!profileId.Contains("ga:")) | |
profileId = $"ga:{profileId}"; | |
var dateRange = new DateRange | |
{ | |
StartDate = DateTime.Now.AddDays(-GetGoogleAnalyticDaysMostPopular).ToString("yyyy-MM-dd"), | |
EndDate = DateTime.Now.ToString("yyyy-MM-dd") | |
}; | |
var sessions = new Metric | |
{ | |
Expression = "ga:pageviews", | |
Alias = "Pageviews" | |
}; | |
var dimension1 = new Dimension { Name = "ga:dimension1" }; | |
var date = new Dimension { Name = "ga:date" }; | |
var pageTitle = new Dimension { Name = "ga:pageTitle" }; | |
var pagepathlevel1 = new Dimension { Name = "ga:pagepathlevel1" }; | |
var pagepathlevel2 = new Dimension { Name = "ga:pagepathlevel2" }; | |
var pagepathlevel3 = new Dimension { Name = "ga:pagepathlevel3" }; | |
var pagepathlevel4 = new Dimension { Name = "ga:pagepathlevel4" }; | |
var dimension2 = new Dimension { Name = "ga:dimension2" };//remove dimension that is not in use | |
var reportRequest = new ReportRequest | |
{ | |
DateRanges = new List<DateRange> { dateRange }, | |
Dimensions = new List<Dimension> { dimension1, date, pageTitle, pagepathlevel1, pagepathlevel2, pagepathlevel3, pagepathlevel4, dimension2 }, | |
Metrics = new List<Metric> { sessions }, | |
ViewId = profileId | |
}; | |
if (typeid > 0) | |
reportRequest.FiltersExpression = "ga:dimension2==" + typeid; | |
var getReportsRequest = new GetReportsRequest | |
{ | |
ReportRequests = new List<ReportRequest> { reportRequest } | |
}; | |
var batchRequest = service.Reports.BatchGet(getReportsRequest); | |
var response = batchRequest.Execute(); | |
var metrics = new Dictionary<Guid, PageItemViews>(); | |
return ProcessData(response, metrics); | |
} | |
private Dictionary<Guid, PageItemViews> ProcessData(GetReportsResponse response, Dictionary<Guid, PageItemViews> metrics) | |
{ | |
if (response.Reports.First().Data.Rows != null)//if null, no response back | |
{ | |
foreach (var x in response.Reports.First().Data.Rows) | |
{ | |
Guid itemId; | |
if (!Guid.TryParse(x.Dimensions[0], out itemId)) | |
continue; | |
int count = 0; | |
if (int.TryParse(x.Metrics.First().Values[0], out count)){ | |
if (!metrics.ContainsKey(itemId)) | |
{ | |
metrics.Add(itemId, | |
new PageItemViews | |
{ | |
PageViews = count, | |
CategoryName = x.Dimensions[3].TrimEnd('/').TrimStart('/') | |
}); | |
} | |
else | |
{ | |
var entry = metrics[itemId]; | |
entry.PageViews += count; | |
} | |
} | |
} | |
} | |
return metrics; | |
} | |
private string GetGoogleAnalyticsProfileId => ConfigurationManager.AppSettings["GoogleAnalyticsProfileId"]; | |
private string GetGoogleAnalyticsKeyFilePath => ConfigurationManager.AppSettings["GoogleAnalyticsKeyFilePath"]; | |
private int GetGoogleAnalyticDaysMostPopular | |
{ | |
get; | |
set; | |
} | |
} | |
public class PageItemViews | |
{ | |
public int PageViews { get; internal set; } | |
public string CategoryName { get; internal set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using EPiServer.Core; | |
using EPiServer.ServiceLocation; | |
using System.Collections.Generic; | |
namespace Bloggen.Web.Business.Services | |
{ | |
public static class GoogleAnalyticsServiceLinqExtension | |
{ | |
private static readonly IGoogleAnalyticsService GoogleAnalyticsService = ServiceLocator.Current.GetInstance<IGoogleAnalyticsService>(); | |
public static IEnumerable<PageData> OrderByMostPopular(this IEnumerable<PageData> queryable, string firstSegmentUrl = null) | |
{ | |
return GoogleAnalyticsService.FilterItemsSortByMostPopular(GoogleAnalyticsService.GetItemViewsfromAnalytics(), queryable, firstSegmentUrl); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using EPiServer.Core; | |
using System; | |
using System.Collections.Generic; | |
namespace Gosso.Web.Business.Services | |
{ | |
public interface IGoogleAnalyticsService | |
{ | |
Dictionary<Guid, PageItemViews> GetItemViewsfromAnalytics(int typeid= 0, bool useCache = true); | |
IEnumerable<PageData> FilterItemsSortByMostPopular(Dictionary<Guid, PageItemViews> pagesViews, IEnumerable<PageData> articles, string inspiration = null); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment