Skip to content

Instantly share code, notes, and snippets.

@LucGosso
Last active May 10, 2022 09:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LucGosso/00ac7a2ece9c135ebf83ca897a0a8ba9 to your computer and use it in GitHub Desktop.
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
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";
}
}
}
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; }
}
}
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);
}
}
}
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