Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save DiracSpace/0a1b4f95fb4b0d3e2b7cad13c3f4e702 to your computer and use it in GitHub Desktop.

Select an option

Save DiracSpace/0a1b4f95fb4b0d3e2b7cad13c3f4e702 to your computer and use it in GitHub Desktop.

Revisions

  1. @mikeblakeuk mikeblakeuk renamed this gist Jul 5, 2017. 1 changed file with 0 additions and 0 deletions.
  2. @mikeblakeuk mikeblakeuk created this gist Jul 5, 2017.
    128 changes: 128 additions & 0 deletions PowerBIHttpOperationExceptionHandler
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,128 @@
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Rest;
    using Microsoft.Rest.Serialization;
    using Newtonsoft.Json;

    namespace PowerBI
    {
    // Samples:
    // {"error":{"code":"InvalidRequest", "message":"datasetId is null or empty"}}
    // {"error":{"code":"GeneralException", "message":"Failed to process dataset PostDataset","target":"PostDataset","details":[{"message":"SQL operation failed: The Database operation reached a timeout of '00:01:30'"}]}}
    // {"error":{"code":"DM_GWPipeline_UnknownError","pbi.error":{"code":"DM_GWPipeline_UnknownError","parameters":{},"details":[]}}}
    // {"error":{"code":"FeatureNotAvailableError","pbi.error":{"code":"FeatureNotAvailableError","parameters":{},"details":[]}}}
    // {"error":{"code":"UnknownError", "pbi.error":{"code":"UnknownError","parameters":{},"details":[],"exceptionCulprit":1}}}

    public class PowerBIHttpOperationExceptionHandler : DelegatingHandler
    {
    const string XPowerBIErrorDetailsHeaderKey = "X-PowerBI-Error-Details";
    const string RequestIdHeaderKey = "RequestId";

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
    var response = await base.SendAsync(request, cancellationToken);

    if (response.IsSuccessStatusCode)
    {
    return response;
    }

    var errorBody = ErrorInHeader(response);
    var content = response.Content?.ReadAsStringAsync().Result ?? string.Empty;
    errorBody = errorBody ?? content;
    var errorTypeSafe = IsPowerBIErrorJson(errorBody);

    if (errorTypeSafe == null)
    {
    return response;
    }

    var message = $"Power BI operation returned an error code '{errorTypeSafe.Code}'";
    var exception =
    new PowerBIErrorException(message)
    {
    Body = errorBody,
    Code = errorTypeSafe.Code,
    ErrorMessage = errorTypeSafe.Message,
    Details = errorTypeSafe.Details?.FirstOrDefault()?.Message,
    Request = new HttpRequestMessageWrapper(request, request.Content?.ReadAsStringAsync().Result), //If the user was uploading a 10meg pbix, we have just read it twice
    Response = new HttpResponseMessageWrapper(response, content)
    };

    if (response.Headers.Contains(RequestIdHeaderKey))
    {
    exception.RequestId = response.Headers.GetValues(RequestIdHeaderKey).FirstOrDefault();
    }
    var shouldTrace = ServiceClientTracing.IsEnabled;
    if (shouldTrace)
    {
    //var invocationId = (ServiceClientTracing.NextInvocationId - 1).ToString(); //need to use the same id from the call.
    //ServiceClientTracing.Error(invocationId, exception);
    }
    request.Dispose();
    response.Dispose();
    throw exception;
    }

    static string ErrorInHeader(HttpResponseMessage response)
    {
    IEnumerable<string> errorHeaderValues = null;
    if (response.Headers?.TryGetValues(XPowerBIErrorDetailsHeaderKey, out errorHeaderValues) == true)
    {
    var xHeaderErrorDetails = errorHeaderValues?.SingleOrDefault();
    if (xHeaderErrorDetails != null)
    {
    return xHeaderErrorDetails;
    }
    }
    return null;
    }

    static PowerBIError IsPowerBIErrorJson(string body)
    {
    if (string.IsNullOrEmpty(body))
    {
    return null;
    }
    try
    {
    var json = SafeJsonConvert.DeserializeObject<PowerBIErrorBody>(body);
    return json?.Error;
    }
    catch (JsonException)
    {
    }
    return null;
    }

    public class PowerBIErrorBody
    {
    [JsonProperty(PropertyName = "error")]
    public PowerBIError Error { get; set; }
    }

    public class PowerBIError
    {
    [JsonProperty(PropertyName = "code")]
    public string Code { get; set; }

    [JsonProperty(PropertyName = "details")]
    public IEnumerable<PowerBIExceptionDetails> Details { get; set; }

    [JsonProperty(PropertyName = "message")]
    public string Message { get; set; }

    [JsonProperty(PropertyName = "target")]
    public string Target { get; set; }
    }

    public class PowerBIExceptionDetails
    {
    [JsonProperty(PropertyName = "message")]
    public string Message { get; set; }
    }
    }
    }