/// <summary> /// Initializes a new instance of the <see cref="ApplicationInstallStatusEventArgs"/> class. /// </summary> /// <param name="status">Install status</param> /// <param name="phase">Install phase</param> /// <param name="message">Install message</param> internal ApplicationInstallStatusEventArgs( ApplicationInstallStatus status, ApplicationInstallPhase phase, string message = "") { this.Status = status; this.Phase = phase; this.Message = message; }
/// <summary> /// Sends application install status. /// </summary> /// <param name="status">Status of the installation.</param> /// <param name="phase">Current installation phase (ex: Uninstalling previous version)</param> /// <param name="message">Optional error message describing the install status.</param> private void SendAppInstallStatus( ApplicationInstallStatus status, ApplicationInstallPhase phase, string message = "") { this.AppInstallStatus?.Invoke( this, new ApplicationInstallStatusEventArgs(status, phase, message)); }
/// <summary> /// Installs an app package application with Windows Device Portal. /// </summary> /// <param name="appFilePath">The app package file path.</param> /// <param name="dependentAppsFilePaths">The dependent app packages file paths.</param> /// <param name="certFilePath">The certificate file path.</param> /// <param name="ipAddress">The ip address of the device to install the app on.</param> /// <exception cref="FileNotFoundException"> /// </exception> public static async Task InstallAppWithWDP(string appFilePath, List <string> dependentAppsFilePaths, string certFilePath, string ipAddress = "localhost") { ApplicationInstallStatus status = ApplicationInstallStatus.InProgress; if (!File.Exists(appFilePath)) { throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Resources.FileNotFoundException, appFilePath)); } if (dependentAppsFilePaths != null) { foreach (var app in dependentAppsFilePaths) { if (!File.Exists(app)) { throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Resources.FileNotFoundException, app)); } } } if (certFilePath != null) { if (!File.Exists(certFilePath)) { throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Resources.FileNotFoundException, certFilePath)); } } CreateAppInstallEndpointAndBoundaryString(Path.GetFileName(appFilePath), ipAddress, out var uri, out _); using (var content = CreateAppInstallContent(appFilePath, dependentAppsFilePaths, certFilePath)) { await WdpHttpClient.PostAsync(uri, content); } while (status == ApplicationInstallStatus.InProgress) { await Task.Delay(500); status = await GetInstallStatusAsync(ipAddress); } }
/// <summary> /// Registers a loose app on the console /// </summary> /// <param name="folderName">Relative folder path where the app can be found.</param> /// <returns>Task for tracking async completion.</returns> public async Task RegisterApplication(string folderName) { if (this.Platform != DevicePortalPlatforms.XboxOne) { throw new NotSupportedException("This method is only supported on Xbox One."); } await this.Post( RegisterPackageApi, string.Format("folder={0}", Utilities.Hex64Encode(folderName))); // Poll the status until complete. ApplicationInstallStatus status = ApplicationInstallStatus.InProgress; do { await Task.Delay(TimeSpan.FromMilliseconds(500)); status = await this.GetInstallStatus(); }while (status == ApplicationInstallStatus.InProgress); }
private static async Task <ApplicationInstallStatus> GetInstallStatusAsync(string ipAddress = "localhost") { ApplicationInstallStatus status = ApplicationInstallStatus.None; Uri uri = BuildEndpoint( new Uri($"http://{ipAddress}"), "api/app/packagemanager/state"); using (HttpResponseMessage response = await WdpHttpClient.GetAsync(uri).ConfigureAwait(false)) { if (response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.OK) { // Status code: 200 if (response.Content == null) { status = ApplicationInstallStatus.Completed; } else { // If we have a response body, it's possible this was an error // (even though we got an HTTP 200). using (Stream dataStream = new MemoryStream()) { using (HttpContent content = response.Content) { await content.CopyToAsync(dataStream).ConfigureAwait(false); // Ensure we point the stream at the origin. dataStream.Position = 0; } if (dataStream.Length > 0) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse)); HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream); if (errorResponse.Success) { status = ApplicationInstallStatus.Completed; } else { throw new Exception(string.Format(CultureInfo.CurrentCulture, Resources.WDPError, errorResponse.Reason)); } } else { throw new Exception(string.Format(CultureInfo.CurrentCulture, Resources.WDPHttpError, response.StatusCode)); } } } } else if (response.StatusCode == HttpStatusCode.NoContent) { // Status code: 204 status = ApplicationInstallStatus.InProgress; } } else { throw new Exception(string.Format(CultureInfo.CurrentCulture, Resources.WDPHttpError, response.StatusCode)); } } return(status); }
/// <summary> /// API for getting installation status. /// </summary> /// <returns>The status</returns> #pragma warning disable 1998 public async Task <ApplicationInstallStatus> GetInstallStatusAsync() { ApplicationInstallStatus status = ApplicationInstallStatus.None; Uri uri = Utilities.BuildEndpoint( this.deviceConnection.Connection, InstallStateApi); HttpBaseProtocolFilter httpFilter = new HttpBaseProtocolFilter(); httpFilter.AllowUI = false; if (this.deviceConnection.Credentials != null) { httpFilter.ServerCredential = new PasswordCredential(); httpFilter.ServerCredential.UserName = this.deviceConnection.Credentials.UserName; httpFilter.ServerCredential.Password = this.deviceConnection.Credentials.Password; } using (HttpClient client = new HttpClient(httpFilter)) { this.ApplyHttpHeaders(client, HttpMethods.Get); using (HttpResponseMessage response = await client.GetAsync(uri)) { if (response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.Ok) { // Status code: 200 if (response.Content != null) { Stream dataStream = null; IBuffer dataBuffer = null; using (IHttpContent messageContent = response.Content) { dataBuffer = await messageContent.ReadAsBufferAsync(); if (dataBuffer != null) { dataStream = dataBuffer.AsStream(); } } if (dataStream != null) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse)); HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream); if (errorResponse.Success) { status = ApplicationInstallStatus.Completed; } else { throw new DevicePortalException(response.StatusCode, errorResponse, uri); } } else { throw new DevicePortalException(HttpStatusCode.Conflict, "Failed to deserialize GetInstallStatus response."); } } } else if (response.StatusCode == HttpStatusCode.NoContent) { // Status code: 204 status = ApplicationInstallStatus.InProgress; } } else { throw await DevicePortalException.CreateAsync(response); } } } return(status); }
/// <summary> /// API for getting installation status. /// </summary> /// <returns>The status</returns> public async Task <ApplicationInstallStatus> GetInstallStatusAsync() { ApplicationInstallStatus status = ApplicationInstallStatus.Completed; return(await Task.FromResult(status)); }
/// <summary> /// Installs an application /// </summary> /// <param name="appName">Friendly name (ex: Hello World) of the application. If this parameter is not provided, the name of the package is assumed to be the app name.</param> /// <param name="packageFileName">Full name of the application package file.</param> /// <param name="dependencyFileNames">List containing the full names of any required dependency files.</param> /// <param name="certificateFileName">Full name of the optional certificate file.</param> /// <param name="stateCheckIntervalMs">How frequently we should check the installation state.</param> /// <param name="timeoutInMinutes">Operation timeout.</param> /// <param name="uninstallPreviousVersion">Indicate whether or not the previous app version should be uninstalled prior to installing.</param> /// <remarks>InstallApplication sends ApplicationInstallStatus events to indicate the current progress in the installation process. /// Some applications may opt to not register for the AppInstallStatus event and await on InstallApplication.</remarks> /// <returns>Task for tracking completion of install initialization.</returns> public async Task InstallApplication( string appName, string packageFileName, List <string> dependencyFileNames, string certificateFileName = null, short stateCheckIntervalMs = 500, short timeoutInMinutes = 15, bool uninstallPreviousVersion = true) { string installPhaseDescription = string.Empty; try { FileInfo packageFile = new FileInfo(packageFileName); // If appName was not provided, use the package file name if (string.IsNullOrEmpty(appName)) { appName = packageFile.Name; } // Uninstall the application's previous version, if one exists. if (uninstallPreviousVersion) { installPhaseDescription = string.Format("Uninstalling any previous version of {0}", appName); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.UninstallingPreviousVersion, installPhaseDescription); AppPackages installedApps = await this.GetInstalledAppPackages(); foreach (PackageInfo package in installedApps.Packages) { if (package.Name == appName) { await this.UninstallApplication(package.FullName); break; } } } // Create the API endpoint and generate a unique boundary string. Uri uri; string boundaryString; this.CreateAppInstallEndpointAndBoundaryString( packageFile.Name, out uri, out boundaryString); using (MemoryStream dataStream = new MemoryStream()) { byte[] data; // Copy the application package. installPhaseDescription = string.Format("Copying: {0}", packageFile.Name); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.CopyingFile, installPhaseDescription); data = Encoding.ASCII.GetBytes(string.Format("--{0}\r\n", boundaryString)); dataStream.Write(data, 0, data.Length); CopyFileToRequestStream(packageFile, dataStream); // Copy dependency files, if any. foreach (string dependencyFile in dependencyFileNames) { FileInfo fi = new FileInfo(dependencyFile); installPhaseDescription = string.Format("Copying: {0}", fi.Name); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.CopyingFile, installPhaseDescription); data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}\r\n", boundaryString)); dataStream.Write(data, 0, data.Length); CopyFileToRequestStream(fi, dataStream); } // Copy the certificate file, if provided. if (!string.IsNullOrEmpty(certificateFileName)) { FileInfo fi = new FileInfo(certificateFileName); installPhaseDescription = string.Format("Copying: {0}", fi.Name); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.CopyingFile, installPhaseDescription); data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}\r\n", boundaryString)); dataStream.Write(data, 0, data.Length); CopyFileToRequestStream(fi, dataStream); } // Close the installation request data. data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}--\r\n", boundaryString)); dataStream.Write(data, 0, data.Length); dataStream.Position = 0; string contentType = string.Format("multipart/form-data; boundary={0}", boundaryString); // Make the HTTP request. await this.Post(uri, dataStream, contentType); } // Poll the status until complete. ApplicationInstallStatus status = ApplicationInstallStatus.InProgress; do { installPhaseDescription = string.Format("Installing {0}", appName); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.Installing, installPhaseDescription); await Task.Delay(TimeSpan.FromMilliseconds(stateCheckIntervalMs)); status = await this.GetInstallStatus(); }while (status == ApplicationInstallStatus.InProgress); installPhaseDescription = string.Format("{0} installed successfully", appName); this.SendAppInstallStatus( ApplicationInstallStatus.Completed, ApplicationInstallPhase.Idle, installPhaseDescription); } catch (Exception e) { DevicePortalException dpe = e as DevicePortalException; if (dpe != null) { this.SendAppInstallStatus( ApplicationInstallStatus.Failed, ApplicationInstallPhase.Idle, string.Format("Failed to install {0}: {1}", appName, dpe.Reason)); } else { this.SendAppInstallStatus( ApplicationInstallStatus.Failed, ApplicationInstallPhase.Idle, string.Format("Failed to install {0}: {1}", appName, installPhaseDescription)); } } }
/// <summary> /// Installs an application /// </summary> /// <param name="appName">Friendly name (ex: Hello World) of the application. If this parameter is not provided, the name of the package is assumed to be the app name.</param> /// <param name="packageFileName">Full name of the application package file.</param> /// <param name="dependencyFileNames">List containing the full names of any required dependency files.</param> /// <param name="certificateFileName">Full name of the optional certificate file.</param> /// <param name="stateCheckIntervalMs">How frequently we should check the installation state.</param> /// <param name="timeoutInMinutes">Operation timeout.</param> /// <param name="uninstallPreviousVersion">Indicate whether or not the previous app version should be uninstalled prior to installing.</param> /// <remarks>InstallApplication sends ApplicationInstallStatus events to indicate the current progress in the installation process. /// Some applications may opt to not register for the AppInstallStatus event and await on InstallApplication.</remarks> /// <returns>Task for tracking completion of install initialization.</returns> public async Task InstallApplicationAsync( string appName, string packageFileName, List <string> dependencyFileNames, string certificateFileName = null, short stateCheckIntervalMs = 500, short timeoutInMinutes = 15, bool uninstallPreviousVersion = true) { string installPhaseDescription = string.Empty; try { FileInfo packageFile = new FileInfo(packageFileName); // If appName was not provided, use the package file name if (string.IsNullOrEmpty(appName)) { appName = packageFile.Name; } // Uninstall the application's previous version, if one exists. if (uninstallPreviousVersion) { installPhaseDescription = string.Format("Uninstalling any previous version of {0}", appName); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.UninstallingPreviousVersion, installPhaseDescription); AppPackages installedApps = await this.GetInstalledAppPackagesAsync(); foreach (PackageInfo package in installedApps.Packages) { if (package.Name == appName) { await this.UninstallApplicationAsync(package.FullName); break; } } } // Create the API endpoint and generate a unique boundary string. Uri uri; string boundaryString; this.CreateAppInstallEndpointAndBoundaryString( packageFile.Name, out uri, out boundaryString); installPhaseDescription = string.Format("Copying: {0}", packageFile.Name); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.CopyingFile, installPhaseDescription); var content = new HttpMultipartFileContent(); await content.Add(packageFile.FullName); await content.AddRange(dependencyFileNames); await content.Add(certificateFileName); await this.PostAsync(uri, content); // Poll the status until complete. ApplicationInstallStatus status = ApplicationInstallStatus.InProgress; do { installPhaseDescription = string.Format("Installing {0}", appName); this.SendAppInstallStatus( ApplicationInstallStatus.InProgress, ApplicationInstallPhase.Installing, installPhaseDescription); await Task.Delay(TimeSpan.FromMilliseconds(stateCheckIntervalMs)); status = await this.GetInstallStatusAsync().ConfigureAwait(false); }while (status == ApplicationInstallStatus.InProgress); installPhaseDescription = string.Format("{0} installed successfully", appName); this.SendAppInstallStatus( ApplicationInstallStatus.Completed, ApplicationInstallPhase.Idle, installPhaseDescription); } catch (Exception e) { DevicePortalException dpe = e as DevicePortalException; if (dpe != null) { this.SendAppInstallStatus( ApplicationInstallStatus.Failed, ApplicationInstallPhase.Idle, string.Format("Failed to install {0}: {1}", appName, dpe.Reason)); } else { this.SendAppInstallStatus( ApplicationInstallStatus.Failed, ApplicationInstallPhase.Idle, string.Format("Failed to install {0}: {1}", appName, installPhaseDescription)); } } }
/// <summary> /// API for getting installation status. /// </summary> /// <returns>The status</returns> public async Task <ApplicationInstallStatus> GetInstallStatus() { ApplicationInstallStatus status = ApplicationInstallStatus.None; Uri uri = Utilities.BuildEndpoint( this.deviceConnection.Connection, InstallStateApi); WebRequestHandler handler = new WebRequestHandler(); handler.UseDefaultCredentials = false; handler.Credentials = this.deviceConnection.Credentials; handler.ServerCertificateValidationCallback = this.ServerCertificateValidation; using (HttpClient client = new HttpClient(handler)) { this.ApplyHttpHeaders(client, HttpMethods.Get); Task <HttpResponseMessage> getTask = client.GetAsync(uri); await getTask.ConfigureAwait(false); getTask.Wait(); using (HttpResponseMessage response = getTask.Result) { if (response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.OK) { // Status code: 200 if (response.Content == null) { status = ApplicationInstallStatus.Completed; } else { // If we have a response body, it's possible this was an error // (even though we got an HTTP 200). Stream dataStream = null; using (HttpContent content = response.Content) { dataStream = new MemoryStream(); Task copyTask = content.CopyToAsync(dataStream); await copyTask.ConfigureAwait(false); copyTask.Wait(); // Ensure we point the stream at the origin. dataStream.Position = 0; } if (dataStream != null) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse)); HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream); if (errorResponse.Success) { status = ApplicationInstallStatus.Completed; } else { throw new DevicePortalException(response.StatusCode, errorResponse, uri); } } else { throw new DevicePortalException(response.StatusCode, "Failed to deserialize GetInstallStatus response."); } } } else if (response.StatusCode == HttpStatusCode.NoContent) { // Status code: 204 status = ApplicationInstallStatus.InProgress; } } else { throw new DevicePortalException(response); } } } return(status); }
/// <summary> /// Gets the status of a pending or most recent installation, if any. /// </summary> /// <returns>The status</returns> public async Task <ApplicationInstallStatus> GetInstallStatusAsync() { ApplicationInstallStatus status = ApplicationInstallStatus.None; Uri uri = Utilities.BuildEndpoint( this.deviceConnection.Connection, InstallStateApi); using (HttpResponseMessage response = await this.HttpClient.GetAsync(uri).ConfigureAwait(false)) { if (response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.OK) { // Status code: 200 if (response.Content == null) { status = ApplicationInstallStatus.Completed; } else { // If we have a response body, it's possible this was an error // (even though we got an HTTP 200). Stream dataStream = null; using (HttpContent content = response.Content) { dataStream = new MemoryStream(); await content.CopyToAsync(dataStream).ConfigureAwait(false); // Ensure we point the stream at the origin. dataStream.Position = 0; } if (dataStream != null) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse)); HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream); if (errorResponse.Success) { status = ApplicationInstallStatus.Completed; } else { throw new DevicePortalException(response.StatusCode, errorResponse, uri); } } else { throw new DevicePortalException(response.StatusCode, "Failed to deserialize GetInstallStatus response."); } } } else if (response.StatusCode == HttpStatusCode.NoContent) { // Status code: 204 status = ApplicationInstallStatus.InProgress; } } else { throw await DevicePortalException.CreateAsync(response); } } return(status); }