/// <summary> /// Helper method to handle all responses from Habitat Server (including errors) in a consistent manner /// </summary> /// <typeparam name="TR">The type of data object that's inside the ConfigResults instance returned by this method</typeparam> /// <param name="task">The response task from the HttpClient</param> private ConfigResults <TR> HandleConfigServiceResponse <TR>(Task <HttpResponseMessage> task) { ConfigResults <TR> configResults = new ConfigResults <TR>(); try { HttpResponseMessage response = task.Result; if (response.IsSuccessStatusCode) { if (response.StatusCode != HttpStatusCode.NoContent) { var dataReadTask = response.Content.ReadAsStringAsync().ContinueWith(x => ReadConfigServiceJson <TR>(x)); dataReadTask.Wait(); configResults = dataReadTask.Result; } } else { configResults.ExceptionMessage = new WebException(string.Format("Unsuccessful Request: {0}", response.StatusCode.ToString())).ToString(); } } catch (Exception exception) { configResults.ExceptionMessage = exception.ToString(); } return(configResults); }
/// <summary> /// Swaps the named config resource to another config resource /// </summary> /// <param name="firstComponentName">The source1 for the swap operation</param> /// <param name="secondComponentName">The source2 for the swap operation</param> /// <remarks> /// This call is asynchronous - SwapComponentCompleted is called automatically when the operation is complete. /// </remarks> public void SwapComponentAsync(string firstComponentName, string secondComponentName) { AsyncManager.OutstandingOperations.Increment(); // Get first config item Task <ConfigResults <ConfigRoot> > getFirstComponentTask = GetComponentInternal(firstComponentName); getFirstComponentTask.Wait(); ConfigResults <ConfigRoot> firstConfigResults = getFirstComponentTask.Result; if (firstConfigResults.ExceptionMessage != null) { CompleteAsyncOperation(new ConfigResults <List <ConfigRoot> > { Data = null, ExceptionMessage = firstConfigResults.ExceptionMessage }); return; } // Get second config item Task <ConfigResults <ConfigRoot> > getSecondComponentTask = GetComponentInternal(secondComponentName); getSecondComponentTask.Wait(); ConfigResults <ConfigRoot> secondConfigResults = getSecondComponentTask.Result; if (secondConfigResults.ExceptionMessage != null) { CompleteAsyncOperation(new ConfigResults <List <ConfigRoot> > { Data = null, ExceptionMessage = secondConfigResults.ExceptionMessage }); return; } // Swap the compnents here ConfigRoot firstConfigRoot = firstConfigResults.Data; firstConfigRoot.ComponentName = secondComponentName; firstConfigRoot.Data.Name = firstConfigRoot.ComponentName; ConfigRoot secondConfigRoot = secondConfigResults.Data; secondConfigRoot.ComponentName = firstComponentName; secondConfigRoot.Data.Name = secondConfigRoot.ComponentName; Task <ConfigResults <ConfigRoot> > createSwapTask = SaveComponentInternal(firstComponentName, secondConfigRoot); createSwapTask.ContinueWith( first => SaveComponentInternal(secondComponentName, firstConfigRoot).ContinueWith( second => CompleteAsyncOperation(new ConfigResults <List <ConfigRoot> > { Data = new List <ConfigRoot> { first.Result.Data, second.Result.Data } }))); }
/// <summary> /// Copies the named config resource to a new resource with a new name /// </summary> /// <param name="existingComponentName">The source for the copy operation</param> /// <param name="newComponentName">The destination for the copy operation</param> /// <remarks> /// This call is asynchronous - CopyComponentCompleted is called automatically when the operation is complete. /// </remarks> public void CopyComponentAsync(string existingComponentName, string newComponentName) { AsyncManager.OutstandingOperations.Increment(); // Get existing config item Task <ConfigResults <ConfigRoot> > getComponentTask = GetComponentInternal(existingComponentName); getComponentTask.Wait(); ConfigResults <ConfigRoot> configResults = getComponentTask.Result; if (configResults.ExceptionMessage != null) { CompleteAsyncOperation(configResults); return; } // Create a copy with a new name ConfigRoot newConfigRoot = configResults.Data; newConfigRoot.ComponentName = newComponentName; newConfigRoot.Data.Name = newConfigRoot.ComponentName; Task <ConfigResults <ConfigRoot> > createCopyTask = AddNewComponentInternal(newConfigRoot); createCopyTask.ContinueWith(x => CompleteAsyncOperation(x.Result)); }
/// <summary> /// Helper method to parse Habitat Server responses as the appropriate JSON type and format for readability. /// </summary> /// <typeparam name="TR">The type of data object that's inside the ConfigResults instance returned by this method</typeparam> /// <param name="readTask">The Habitat Server response task that provides the JSON values</param> private ConfigResults <TR> ReadConfigServiceJson <TR>(Task <string> readTask) { ConfigResults <TR> configResults = new ConfigResults <TR>(); try { if (readTask.Result != null) { TR tempResults = JsonConvert.DeserializeObject <TR>(readTask.Result.ToString()); configResults.Data = tempResults; } } catch (Exception exception) { configResults.ExceptionMessage = exception.ToString(); } return(configResults); }
/// <summary> /// Signals receipt of all application components that are registered in the configuration system paired with their URLs. /// </summary> /// <param name="configResults">The data returned by the async operation</param> /// <returns>A JSON array of the components, or an exception message</returns> public JsonResult GetComponentListCompleted(ConfigResults <List <string> > configResults) { return(Json(configResults)); }
/// <summary> /// Signals that the given config results are complete and we're ready to return a JsonResult /// </summary> /// <typeparam name="TR">The type of data object that's inside the ConfigResults instance</typeparam> /// <param name="configResults">The config results to send</param> private void CompleteAsyncOperation <TR>(ConfigResults <TR> configResults) { AsyncManager.Parameters["configResults"] = configResults; AsyncManager.OutstandingOperations.Decrement(); }
/// <summary> /// Signals completion of the Import operation /// </summary> /// <param name="configResults">The data returned by the async operation</param> /// <returns>A JSON object containing per-item details about the import operation, or an exception message.</returns> public JsonResult ImportConfigCompleted(ConfigResults <ImportResult> configResults) { return(Json(configResults)); }
/// <summary> /// Internal method used to import a set of configuration entries in one operation /// </summary> /// <param name="configEntries">The config entries to import. Invalid entries will not be imported. Duplicates will be given a new name.</param> /// <param name="existingComponentListTaskResults">The results of the GetComponentList operation. Contains the names of all existing configured components</param> /// <returns>The results of the import task</returns> private ConfigResults <ImportResult> ImportConfigInternal(List <ConfigRoot> configEntries, ConfigResults <List <string> > existingComponentListTaskResults) { if (existingComponentListTaskResults.ExceptionMessage != null) { return(new ConfigResults <ImportResult> { ExceptionMessage = existingComponentListTaskResults.ExceptionMessage }); } try { // For each item being imported, assign a new (hopefully unique) name, and perform an Add List <string> namesOfAllExistingComponents = existingComponentListTaskResults.Data; IEnumerable <ConfigRoot> importComponentsThatHaveNameConflicts = configEntries.Join(namesOfAllExistingComponents, x => x.ComponentName.ToLower(), y => y.ToLower(), (x, y) => x).ToArray(); IEnumerable <ConfigRoot> importComponentsThatHaveUniqueNames = configEntries.Except(importComponentsThatHaveNameConflicts).ToArray(); var currentTimestamp = _dateProvider.Now.DateTimeInstance; foreach (var importComponent in importComponentsThatHaveNameConflicts) { importComponent.ComponentName = string.Format("{0}Imported{1:MMddyyyyHHmmss}", importComponent.ComponentName, currentTimestamp); importComponent.Data.Name = importComponent.ComponentName; } var importSuccesses = new List <string>(); var importWarnings = new List <string>(); List <ConfigRoot> allImportComponents = importComponentsThatHaveNameConflicts.Union(importComponentsThatHaveUniqueNames).ToList(); foreach (ConfigRoot importComponent in allImportComponents) { var addComponentTask = AddNewComponentInternal(importComponent).ContinueWith(x => x.Result, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted); if (addComponentTask.Result.ExceptionMessage != null) { importWarnings.Add(string.Format("Component '{0}' NOT imported successfully. It may contain invalid contents. Error Message: {1}", importComponent.ComponentName, addComponentTask.Result.ExceptionMessage)); } else { importSuccesses.Add(string.Format("Component '{0}' imported successfully.", importComponent.ComponentName)); } } return(new ConfigResults <ImportResult> { Data = new ImportResult { ImportSuccesses = importSuccesses, ImportWarnings = importWarnings } }); } catch (Exception exception) { return(new ConfigResults <ImportResult> { ExceptionMessage = exception.ToString() }); } }
/// <summary> /// Signals completion of the Export operation /// </summary> /// <param name="configResults">The data returned by the async operation</param> /// <returns>A JSON object containing the full set of configuration data, or an exception message</returns> public JsonResult ExportConfigCompleted(ConfigResults <List <ConfigRoot> > configResults) { return(Json(configResults)); }
/// <summary> /// Signals completion of the Swap operation /// </summary> /// <param name="configResults">The data returned by the async operation</param> /// <returns>A JSON object containing the new configuration, or an exception message</returns> public JsonResult SwapComponentCompleted(ConfigResults <List <ConfigRoot> > configResults) { return(Json(configResults)); }
/// <summary> /// Signals completion of the Copy operation /// </summary> /// <param name="configResults">The data returned by the async operation</param> /// <returns>A JSON object containing the new configuration, or an exception message</returns> public JsonResult CopyComponentCompleted(ConfigResults <ConfigRoot> configResults) { return(Json(configResults)); }