diff --git a/StoreLib/Services/DisplayCatalogHandler.cs b/StoreLib/Services/DisplayCatalogHandler.cs
index e3a079c..04c5045 100644
--- a/StoreLib/Services/DisplayCatalogHandler.cs
+++ b/StoreLib/Services/DisplayCatalogHandler.cs
@@ -10,6 +10,8 @@ namespace StoreLib.Services
{
public class DisplayCatalogHandler
{
+ private readonly MSHttpClient _httpClient;
+
public DisplayCatalogModel ProductListing { get; internal set; }
public Exception Error { get; internal set; }
internal Uri ConstructedUri { get; set; }
@@ -24,6 +26,9 @@ public class DisplayCatalogHandler
public DisplayCatalogHandler(DCatEndpoint SelectedEndpoint, Locale Locale)
{
+ //Adds needed headers for MS related requests. See MS_httpClient.cs
+ this._httpClient = new MSHttpClient();
+
this.SelectedEndpoint = SelectedEndpoint;
this.SelectedLocale = Locale;
}
@@ -59,14 +64,13 @@ public async Task QueryDCATAsync(string ID)
this.ID = ID;
this.ConstructedUri = Utilities.UriHelpers.CreateAlternateDCatUri(SelectedEndpoint, ID, IdentiferType.ProductID, SelectedLocale);
Result = new DisplayCatalogResult(); //We need to clear the result incase someone queries a product, then queries a not found one, the wrong product will be returned.
- MSHttpClient httpClient = new MSHttpClient(); //Adds needed headers for MS related requests. See MSHttpClient.cs
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
//We need to build the request URL based on the requested EndPoint;httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
try
{
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
}
catch (TaskCanceledException)
{
@@ -101,14 +105,13 @@ public async Task QueryDCATAsync(string ID, IdentiferType IDType)
this.ID = ID;
this.ConstructedUri = Utilities.UriHelpers.CreateAlternateDCatUri(SelectedEndpoint, ID, IDType, SelectedLocale);
Result = new DisplayCatalogResult(); //We need to clear the result incase someone queries a product, then queries a not found one, the wrong product will be returned.
- MSHttpClient httpClient = new MSHttpClient(); //Adds needed headers for MS related requests. See MSHttpClient.cs
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
//We need to build the request URL based on the requested EndPoint;httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
try
{
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
}
catch (TaskCanceledException)
{
@@ -143,15 +146,14 @@ public async Task QueryDCATAsync(string ID, IdentiferType IDType)
this.ID = ID;
this.ConstructedUri = Utilities.UriHelpers.CreateAlternateDCatUri(SelectedEndpoint, ID, IdentiferType.ProductID, SelectedLocale);
Result = new DisplayCatalogResult(); //We need to clear the result incase someone queries a product, then queries a not found one, the wrong product will be returned.
- MSHttpClient httpClient = new MSHttpClient(); //MSHttpClient extends System.Net.HttpClient to automaticly add a (needed) CorrelationVector to each request.
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
- httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authentication", AuthenticationToken);
//We need to build the request URL based on the requested EndPoint;
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
+ httpRequestMessage.Headers.TryAddWithoutValidation("Authentication", AuthenticationToken);
try
{
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
}
catch (TaskCanceledException)
{
@@ -186,15 +188,14 @@ public async Task QueryDCATAsync(string ID, IdentiferType IDType)
this.ID = ID;
this.ConstructedUri = Utilities.UriHelpers.CreateAlternateDCatUri(SelectedEndpoint, ID, IDType, SelectedLocale);
Result = new DisplayCatalogResult(); //We need to clear the result incase someone queries a product, then queries a not found one, the wrong product will be returned.
- MSHttpClient httpClient = new MSHttpClient(); //MSHttpClient extends System.Net.HttpClient to automaticly add a (needed) CorrelationVector to each request.
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
- httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authentication", AuthenticationToken);
//We need to build the request URL based on the requested EndPoint;
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, ConstructedUri);
+ httpRequestMessage.Headers.TryAddWithoutValidation("Authentication", AuthenticationToken);
try
{
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
}
catch (TaskCanceledException)
{
@@ -224,46 +225,45 @@ public async Task QueryDCATAsync(string ID, IdentiferType IDType)
/// Instance of DCatSearch, containing the returned products.
public async Task SearchDCATAsync(string Query, DeviceFamily deviceFamily)
{
- MSHttpClient httpClient = new MSHttpClient();
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
switch (deviceFamily)
{
case DeviceFamily.Desktop:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Desktop");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Xbox:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Xbox");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Universal:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Universal");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Mobile:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Mobile");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.HoloLens:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Holographic");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.IotCore:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Iot");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.ServerCore:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Server");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Andromeda:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.8828080");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.WCOS:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Core");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
}
if (httpResponse.IsSuccessStatusCode)
@@ -304,42 +304,41 @@ public async Task> GetAddonsForProductAsync()
///
public async Task SearchDCATAsync(string Query, DeviceFamily DeviceFamily, int SkipCount)
{
- MSHttpClient httpClient = new MSHttpClient();
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpRequestMessage httpRequestMessage;
switch (DeviceFamily)
{
case DeviceFamily.Desktop:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Desktop");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Xbox:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Xbox");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Universal:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Universal");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Mobile:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Mobile");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.HoloLens:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Holographic");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.IotCore:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Iot");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.ServerCore:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.Server");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
case DeviceFamily.Andromeda:
httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{Utilities.TypeHelpers.EnumToSearchUri(SelectedEndpoint)}{Query}&productFamilyNames=apps,games&platformDependencyName=Windows.8828080");
- httpResponse = await httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
+ httpResponse = await _httpClient.SendAsync(httpRequestMessage, new System.Threading.CancellationToken());
break;
}
if (httpResponse.IsSuccessStatusCode)
diff --git a/StoreLib/Services/FE3Handler.cs b/StoreLib/Services/FE3Handler.cs
index f342339..89502aa 100644
--- a/StoreLib/Services/FE3Handler.cs
+++ b/StoreLib/Services/FE3Handler.cs
@@ -15,6 +15,8 @@ namespace StoreLib.Services
{
public static class FE3Handler
{
+ private static readonly MSHttpClient _httpClient = new MSHttpClient();
+
///
/// Returns raw xml containing various (Revision, Update, Package) IDs and info.
///
@@ -22,13 +24,12 @@ public static class FE3Handler
///
public static async Task SyncUpdatesAsync(string WuCategoryID)
{
- MSHttpClient httpClient = new MSHttpClient();
HttpContent httpContent = new StringContent(String.Format(GetResourceTextFile("WUIDRequest.xml"), await GetCookieAsync(), WuCategoryID), Encoding.UTF8, "application/soap+xml"); //Load in the Xml for this FE3 request and format it a cookie and the provided WuCategoryID.
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.RequestUri = Endpoints.FE3Delivery;
httpRequest.Content = httpContent;
httpRequest.Method = HttpMethod.Post;
- HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
+ HttpResponseMessage httpResponse = await _httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
string content = await httpResponse.Content.ReadAsStringAsync();
content = HttpUtility.HtmlDecode(content);
return content;
@@ -40,14 +41,13 @@ public static async Task SyncUpdatesAsync(string WuCategoryID)
/// Cookie extracted from returned XML
public static async Task GetCookieAsync() //Encrypted Cookie Data is needed for FE3 requests. It doesn't expire for a very long time but I still refresh it as the Store does.
{
- MSHttpClient httpClient = new MSHttpClient();
XmlDocument doc = new XmlDocument();
HttpContent httpContent = new StringContent(GetResourceTextFile("GetCookie.xml"), Encoding.UTF8, "application/soap+xml");//Loading the request xml from a file to keep things nice and tidy.
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.RequestUri = Endpoints.FE3Delivery;
httpRequest.Content = httpContent;
httpRequest.Method = HttpMethod.Post;
- HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
+ HttpResponseMessage httpResponse = await _httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
doc.LoadXml(await httpResponse.Content.ReadAsStringAsync());
XmlNodeList xmlNodeList = doc.GetElementsByTagName("EncryptedData");
string cookie = xmlNodeList[0].InnerText;
@@ -84,7 +84,6 @@ public static void ProcessUpdateIDs(string Xml, out IList RevisionIDs, o
/// IList of App Package Download Uris
public static async Task> GetFileUrlsAsync(IList UpdateIDs, IList RevisionIDs)
{
- MSHttpClient httpClient = new MSHttpClient();
XmlDocument doc = new XmlDocument();
IList uris = new List();
foreach (string ID in UpdateIDs)
@@ -94,7 +93,7 @@ public static async Task> GetFileUrlsAsync(IList UpdateIDs, I
httpRequest.RequestUri = Endpoints.FE3DeliverySecured;
httpRequest.Content = httpContent;
httpRequest.Method = HttpMethod.Post;
- HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
+ HttpResponseMessage httpResponse = await _httpClient.SendAsync(httpRequest, new System.Threading.CancellationToken());
doc.LoadXml(await httpResponse.Content.ReadAsStringAsync());
XmlNodeList XmlUrls = doc.GetElementsByTagName("FileLocation");
foreach (XmlNode node in XmlUrls)
diff --git a/StoreLib/Services/MSHttpClient.cs b/StoreLib/Services/MSHttpClient.cs
index a8de687..db58538 100644
--- a/StoreLib/Services/MSHttpClient.cs
+++ b/StoreLib/Services/MSHttpClient.cs
@@ -10,23 +10,58 @@
namespace StoreLib.Services
{
public class MSHttpClient : HttpClient
- {///
- /// An override of the SendAsync Function from HttpClient. This is done to automatically add the needed MS-CV tracking header to every request (along with our user-agent).
- ///
- ///
- ///
- ///
- public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) //Overriding the SendAsync so we can easily add the CorrelationVector and User-Agent to every request.
+ {
+ private static readonly bool IsWindows = System.Runtime.InteropServices.RuntimeInformation
+ .IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
+ private static HttpClientHandler _handler
{
- using (HttpClient client = new HttpClient())
+ get
{
- CorrelationVector CV = new CorrelationVector();
- CV.Init();
- request.Headers.Add("MS-CV", CV.GetValue());
- request.Headers.TryAddWithoutValidation("User-Agent", "StoreLib");
- HttpResponseMessage response = await client.SendAsync(request);
- return response;
+ HttpClientHandler handler = new HttpClientHandler();
+ if (!IsWindows)
+ {
+ handler.ServerCertificateCustomValidationCallback = ServerCertificateValidationCallback;
+ }
+ return handler;
}
}
+
+ private static bool ServerCertificateValidationCallback(
+ object sender,
+ System.Security.Cryptography.X509Certificates.X509Certificate certificate,
+ System.Security.Cryptography.X509Certificates.X509Chain chain,
+ System.Net.Security.SslPolicyErrors sslPolicyErrors
+ )
+ {
+
+ // TODO: Refine
+ return true;
+ }
+
+ private readonly CorrelationVector _cv = new CorrelationVector();
+
+ ///
+ /// Instantiate MSHttpClient
+ ///
+ public MSHttpClient()
+ : base(_handler)
+ {
+ _cv.Init();
+ base.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "StoreLib");
+ }
+
+ ///
+ /// An override of the SendAsync Function from HttpClient. This is done to automatically add the needed MS-CV tracking header to every request (along with our user-agent).
+ ///
+ ///
+ ///
+ ///
+ public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) //Overriding the SendAsync so we can easily add the CorrelationVector and User-Agent to every request.
+ {
+ request.Headers.Add("MS-CV", _cv.GetValue());
+ _cv.Increment();
+ HttpResponseMessage response = await base.SendAsync(request);
+ return response;
+ }
}
}
diff --git a/StoreLib/Utilities/CorrelationVector.cs b/StoreLib/Utilities/CorrelationVector.cs
index f0a8651..15cebfc 100644
--- a/StoreLib/Utilities/CorrelationVector.cs
+++ b/StoreLib/Utilities/CorrelationVector.cs
@@ -65,8 +65,7 @@ internal void Init()
protected static int getCllSettingsAsInt(Settings setting)
{
- int asInt = Int32.Parse(setting.ToString());
- return asInt;
+ return (int)setting;
}
private bool CanExtend()