o365rwsclient/ReportingStream.cs

224 строки
8.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Xml;
namespace Microsoft.Office365.ReportingWebServiceClient
{
public class ReportingStream
{
#region Privates
private ReportingContext reportingContext;
private ReportProvider reportProvider;
private Type reportType;
private string streamIdentifier = string.Empty;
private string progressFilePath = string.Empty;
#endregion Privates
#region Constructors
/// <summary>
///
/// </summary>
/// <param name="serviceEndpoint"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
public ReportingStream(ReportingContext context, string reportType, string streamIdentifier, string progressFilePath = null)
{
this.reportingContext = context;
this.streamIdentifier = streamIdentifier;
this.progressFilePath = progressFilePath;
this.reportProvider = new ReportProvider(context.WebServiceUrl, context.UserName, context.Password, context.TraceLogger);
this.reportType = Type.GetType("Microsoft.Office365.ReportingWebServiceClient.TenantReport." + reportType);
if (!this.reportType.IsSubclassOf(typeof(ReportObject)) || !this.reportType.IsSerializable)
{
throw new ArgumentException(string.Format("Report Type Must be Subclass of ReportObject and Serializable: {0}", this.reportType.FullName));
}
}
#endregion Constructors
#region Private methods
/// <summary>
///
/// </summary>
/// <param name="visitor"></param>
/// <returns>The count of data returned</returns>
private int RetrieveData(IReportVisitor visitor, QueryFilter filter)
{
int totalResultCount = 0;
//If the TopCount is 0, then it was not specified, hence we take the constant value
if (filter.TopCount == 0)
filter.TopCount = Constants.ResultPageSize;
List<XmlNode> resultNodes = reportProvider.GetResponseXml(this.reportType, filter);
if (resultNodes.Count >= Constants.ResultPageSize && filter.SkipCount == 0)
{
reportingContext.TraceLogger.LogInformation("Result is exceeding limit, dividing the range.");
List<QueryRange> subRangeList = filter.QueryRange.GetDividedRanges();
if (subRangeList != null && subRangeList.Count > 0)
{
foreach (QueryRange range in subRangeList)
{
filter.QueryRange = range;
totalResultCount += RetrieveData(visitor, filter);
}
}
else
{
VisitXmlNodes(resultNodes, visitor);
totalResultCount = resultNodes.Count;
reportingContext.TraceLogger.LogInformation(string.Format("Retrieved [{0}] rows of data...", totalResultCount));
reportingContext.TraceLogger.LogInformation("Divided range is null, using Skips.");
int subResult;
filter.SkipCount = 0;
do
{
filter.SkipCount += Constants.ResultPageSize;
subResult = RetrieveData(visitor, filter);
totalResultCount += subResult;
} while (subResult >= Constants.ResultPageSize);
filter.SkipCount = 0;
}
}
else
{
VisitXmlNodes(resultNodes, visitor);
totalResultCount = resultNodes.Count;
reportingContext.TraceLogger.LogInformation(string.Format("Retrieved [{0}] rows of data...", resultNodes.Count));
}
StreamProgress progress = new StreamProgress(this.progressFilePath, streamIdentifier, filter.QueryRange.EndDate, false);
progress.SaveProgress();
return totalResultCount;
}
/// <summary>
///
/// </summary>
/// <typeparam name="TReport"></typeparam>
/// <param name="nodes"></param>
/// <param name="visitor"></param>
/// <returns></returns>
private List<ReportObject> VisitXmlNodes(List<XmlNode> nodes, IReportVisitor visitor)
{
List<ReportObject> list = new List<ReportObject>();
DateTime lastTimeStamp = DateTime.MinValue;
visitor.Reset();
foreach (XmlNode node in nodes)
{
ReportObject report = (ReportObject)Activator.CreateInstance(this.reportType);
report.LoadFromXml(node);
list.Add(report);
visitor.AddReportToBatch(report);
lastTimeStamp = (lastTimeStamp < report.Date) ? report.Date : lastTimeStamp;
}
visitor.VisitBatchReport();
StreamProgress progress = new StreamProgress(this.progressFilePath, streamIdentifier, lastTimeStamp, true);
progress.SaveProgress();
return list;
}
#endregion Private methods
/// <summary>
/// This is a simple method that tries to fetch 1 record of the specified report
/// and if 0 or 1 record return then the authN & authZ to this report is validated
/// otherwise throws an exception
/// </summary>
/// <returns></returns>
public bool ValidateAccessToReport()
{
try
{
IReportVisitor visitor = new DefaultReportVisitor();
int res = RetrieveData(visitor, new QueryFilter() { TopCount = 1 });
if (res == 0 || res == 1)
return true;
else
throw new ApplicationException("Tried to validate your credentials against the report specified, however the response we received from the server did not match what we expected to receive. Please try again.");
}
catch (Exception ex)
{
if (ex is AggregateException)
{
if (ex.InnerException is HttpRequestException)
{
//Indicates that this is an HTTP request unauthorized exception
if (ex.InnerException.Message.Contains("401"))
return false;
else
throw ex;
}
else
throw ex;
}
else
throw ex;
}
}
/// <summary>
///
/// </summary>
public void ClearProgress()
{
StreamProgress progress = new StreamProgress(this.progressFilePath, this.streamIdentifier);
progress.ClearProgress();
}
/// <summary>
/// This RetrieveData method the built-in ReportVisitor (Console)
/// </summary>
public void RetrieveData()
{
IReportVisitor visitor = new DefaultReportVisitor();
RetrieveData(visitor);
}
/// <summary>
///
/// </summary>
/// <param name="visitor"></param>
public void RetrieveData(IReportVisitor visitor)
{
reportingContext.TraceLogger.LogInformation(string.Format("Start Retrieving Data For Report {0}", this.reportType.Name));
QueryFilter queryFilter = new QueryFilter();
queryFilter.QueryRange.StartDate = this.reportingContext.FromDateTime;
queryFilter.QueryRange.EndDate = this.reportingContext.ToDateTime;
queryFilter.CustomFilter = this.reportingContext.DataFilter;
StreamProgress progress = new StreamProgress(this.progressFilePath, this.streamIdentifier);
progress = progress.GetProgress();
DateTime progressTimestamp = progress.TimeStamp;
if (queryFilter.QueryRange.StartDate < progressTimestamp)
queryFilter.QueryRange.StartDate = progressTimestamp;
queryFilter.ExcludeStartItem = progress.ExcludeStartItem;
int totalCount = RetrieveData(visitor, queryFilter);
reportingContext.TraceLogger.LogInformation(string.Format("Retrieve Data Completed. Totally [{0}] of Data Retrieved.", totalCount));
}
}
}