I am currently building a WebApi service that connects with the backoffice of my application allowing the user to click a button an trigger a series of web service requests that trigger my Umbraco website to updated with content.
The class for my WebApi service is setup as so:
public class MyController : UmbracoApiController{
// Global variable declarations go here
private MyController(){
// assign actual values to global variables here
}
public string GetAllUpdates(){
try{
GetCountries();
GetAreas();
GetCities();
...
}
catch (TimeoutException ex)
{
Log.Error("Web Service Timeout", ex);
return "Failed to contact web services.";
}
catch (Exception ex)
{
Log.Error("Exception", ex);
return "An error has occurred.";
}
}
public string GetCountries(){
try{
// Main code here
}
catch(TimeoutException ex){
Log.Error("Web Service Timeout", ex);
return "Failed to contact web services.";
}
catch(Exception ex){
Log.Error("Exception", ex);
return "An error has occurred.";
}
}
.....
}
My WebApi method are called through the use of AngularJS and HTML. When a user clicks the button related to a Web Api method, that method is run then a message is returned to the user upon success or failure of the method.
So, if I were to run the GetCountries() method using the relevant button a message would be displayed on the screen saying "Countries updated successfully" upon success or instead it would output one of the messages that are returned in the catch definitions.
My main problem is that the GetAllUpdates() method runs all of the other methods one after the other. This is fine and I return a message upon success saying "All content updated" however the setup really falls apart when an exception is hit in one of the other methods. For example, GetCountries() is run first. If an exception is raised here, no message is returned to the screen and the application simply moves onto the next method GetAreas(). This propagates through to the end where the success message is then displayed giving the user a false impression that the update went well.
My question therefore is how do I halt the GetAllUpdates() method from running subsequent methods in the chain if an exception occurs without modifying the returns in my other methods? The methods need to return a string so that the message is displayed on screen when they are run on their own however when ran as part of GetAllUpdates() the error messages being returned in the catch blocks are being treated as if the method was completely successful and the user is none the wiser.
Any help would be greatly appreciated.
N.B. After following one of the responses below I altered my WebApi method to do the following:
NEW CLASS
public class ResponseMessage
{
public bool Result { get; set; }
public string Message { get; set; }
}
RETURN ON METHODS
ResponseMessage response = new ResponseMessage();
String json = string.Empty;
response.Result = true;
response.Message = "Content update successful";
json = JsonConvert.SerializeObject(response);
return json;
My Angular code is as follows:
angular.module("umbraco")
.controller("AxumTailorMade",
function ($scope, $http, AxumTailorMade) {
$scope.getAll = function() {
$scope.load = true;
$scope.info = "Retreiving updates";
AxumTailorMade.getAll().success(function (data) {
var response = JSON.parse(data);
$scope.result = response.Result;
$scope.info = response.Message;
$scope.load = false;
});
};
});
angular.module("umbraco.services").factory("AxumTailorMade", function ($http) {
return {
getAll: function () {
return $http.get("/umbraco/api/axumtailormade/getallupdates");
},
getRegions: function () {
return $http.get("/umbraco/api/axumtailormade/getregions");
},
getCountries: function () {
return $http.get("/umbraco/api/axumtailormade/getcountries");
},
getAreas: function () {
return $http.get("/umbraco/api/axumtailormade/getareas");
},
getCities: function () {
return $http.get("/umbraco/api/axumtailormade/getcities");
},
getCategories: function () {
return $http.get("/umbraco/api/axumtailormade/getcategories");
},
getPackages: function () {
return $http.get("/umbraco/api/axumtailormade/getpackages");
},
getHotels: function () {
return $http.get("/umbraco/api/axumtailormade/gethotels");
},
getActivities: function () {
return $http.get("/umbraco/api/axumtailormade/getactivities");
}
};
})
Rather than returning a string from your methods, could you instead return a simple object containing the result and message for client?
Then when executing
GetAllUpdates()
you would check result ofGetCountries()
,GetAreas()
andGetCities()
and append any error messages.It is a little more effort and code but will also give you more control over the flow and what's returned to client. You could also optimise it quite a lot I'm sure, I just stubbed out a general approach for you...
I would suggest you actually get rid of the
GetAllUpdates()
method, and call the particularGet****()
methods separately from AngularJS.This would have the following advantages:
If you do not want/need to call the particular methods in parallel, it would still be better, in my opinion, to call them one by one, hanging the call to every subsequent one off its predecessor's promise (see "Chaining Promises" here: https://docs.angularjs.org/api/ng/service/$q)
Finally - I would not return a string from the WebAPI methods. Rather - you should return an HTTP 200 code for success (i.e. make the methods void, and simply not do anything special), or a specific HTTP code for whatever error has happened. In Angular you can then use .catch() to handle the exceptions. This way your messages will not be decided in the WebAPI code - but on the client side.
How do you return status 401 from WebAPI to AngularJS and also include a custom message?
EDIT:
If the client-side option is not possible, I would make the calls from nested try/catch blocks in the server code:
Alternatively, you could put the calls and respective error messages into lists:
and then call the methods in a for loop:
Make sense? (Sorry if the code doesn't compile, I'm not checking it in a compiler unfortunately)