In my experience, the best way to handle this seamlessly is to set up your web api so that it is not responsible for handling unanticipated errors. This keeps the web api code very clean and simple, like this:
public DataCollection GetSomeData()
{
var data = GetData();
return data;
}
If you'd like to throw a custom exception for whatever reason - maybe you have a specific message to display if the data is null - you can throw the exception normally:
public DataCollection GetSomeData()
{
var data = GetData();
if( data == null ){
throw new Exception("Data is null");
//or... throw new MyCustomException("Data is null");
}
}
Now, so far this approach is not acceptable, because it can potentially expose sensitive server information to the client. In order to handle this cleanly, create a custom action filter that handles the exceptions. Something like this:
/// <summary>
/// Represents an attribute that will automatically process any unhandled exceptions
/// that occur during during the execution of a web api action
/// </summary>
public class HandleExceptionAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
//log the error (make sure LogError doesn't throw any exceptions)
LogError(actionExecutedContext);
//set up a default message that is safe to send to the client
// (doesn't expose any sensitive exception information)
var message = "An error has occured please try your request again later";
//if the exception is, or inherits from MyCustomException, then
// go ahead and forward the message on the client
if (actionExecutedContext.Exception is MyCustomException)
{
message = actionExecutedContext.Exception.Message;
}
actionExecutedContext.Response =
actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, message);
}
}
Be sure to apply this action filter globally, so that it applies to all web api methods without any developer intervention. That way you can be confident that no unhandled exceptions are throwing raw exception messages back to the client.
Now that you have the error coming back from the server properly, you can display the message to your users in a number of ways. The cleanest thing to do is to simply display the message immediately and not try to add it to the view model. You can display a message to the user using toast.js or some other notification mechanism (even window.alert() until you get further down the road).
Here's another question on Stack Overflow that may help with this decision: knockout js best practices ajax error handling