|
4 | 4 | using System.Linq;
|
5 | 5 | using System.Reactive.Linq;
|
6 | 6 | using System.Threading.Tasks;
|
| 7 | +using GraphQL.Execution; |
7 | 8 | using GraphQL.Subscription;
|
8 | 9 | using GraphQL.Transport;
|
9 | 10 | using Microsoft.Extensions.Logging;
|
@@ -56,7 +57,31 @@ public void OnCompleted()
|
56 | 57 | _unsubscribe = null;
|
57 | 58 | }
|
58 | 59 |
|
59 |
| - public void OnError(Exception error) => throw new NotImplementedException(); |
| 60 | + /// <summary> |
| 61 | + /// Handles errors that are raised from the source, wrapping the error |
| 62 | + /// in an <see cref="ExecutionResult"/> instance and sending it to the client. |
| 63 | + /// </summary> |
| 64 | + public void OnError(Exception error) |
| 65 | + { |
| 66 | + _logger.LogDebug("Subscription: {subscriptionId} got error", Id); |
| 67 | + |
| 68 | + // exceptions should already be wrapped by the GraphQL engine |
| 69 | + if (error is not ExecutionError executionError) |
| 70 | + { |
| 71 | + // but in the unlikely event that an unhandled exception delegate throws an exception, |
| 72 | + // or for any other reason it is not an ExecutionError instance, wrap the error |
| 73 | + executionError = new UnhandledError($"Unhandled error of type {error?.GetType().Name}", error!); |
| 74 | + } |
| 75 | + |
| 76 | + // pass along the error as an execution result instance |
| 77 | + OnNext(new ExecutionResult { Errors = new ExecutionErrors { executionError } }); |
| 78 | + |
| 79 | + // Optionally we can disconnect the client by calling OnComplete() here |
| 80 | + // |
| 81 | + // https://docs.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern-best-practices |
| 82 | + // > Once the provider calls the OnError or IObserver<T>.OnCompleted method, there should be |
| 83 | + // > no further notifications, and the provider can unsubscribe its observers. |
| 84 | + } |
60 | 85 |
|
61 | 86 | public void OnNext(ExecutionResult value)
|
62 | 87 | {
|
|
0 commit comments