以正确的方式处理Silverlight上的ServiceStack异常

时间:2014-09-15 12:00:23

标签: silverlight servicestack

我在Silverlight方面遇到异常时遇到了一些问题...

考虑这个简单的例子

服务:

public void Any(NoResultResponseRequest request)
{
   throw new Exception("Someone give me an hug");
}

Dto:

 public class NoResultResponseRequest:IReturnVoid
 {
    public int Id { get;set; }
 }

在银光部分:

    private SS.JsonServiceClient  GetService()
    {

        Uri uri = new Uri(App.Current.Host.Source, "../api/");

        var timeout = new TimeSpan(0, 0, 45, 0, 0);// TimeSpan.Parse(ConfigurationManager.AppSettings.Get("servicestackTimeout"));
        SS.JsonServiceClient client = new SS.JsonServiceClient(uri.AbsoluteUri) { Timeout = timeout };

        client.ShareCookiesWithBrowser = true;
        client.StoreCookies = true;
        client.EmulateHttpViaPost = true;

        return client;
    }


    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var client = GetService();
        var request = new NoResultResponseRequest
        {
            Id = 9
        };

            client.PostAsync(request).ContinueWith(x =>
                {
                  //got a Not found error
                });
    }

如果我看着小提琴手的流量,我就有以下的JSon

{"responseStatus":{"errorCode":"Exception","message":"Someone give me an hug","stackTrace":"[NoResultResponseRequest: 15/09/2014 11:59:16]:\n[REQUEST: {id:9}]\nSystem.Exception: Someone give me an hug\r\n   at SilverlightException.Web.TestService.Any(NoResultResponseRequest request) in c:\\Projects\\2014\\SilverlightException\\SilverlightException.Web\\TestService.cs:line 14\r\n   at ServiceStack.Host.ServiceExec`1.<>c__DisplayClass6.<CreateExecFn>b__5(Object service, Object request)\r\n   at ServiceStack.Host.ServiceRunner`1.Execute(IRequest request, Object instance, TRequest requestDto)","errors":[]}}

提前致谢

1 个答案:

答案 0 :(得分:3)

如果将EmulateHttpViaPost设置为false,它应该按预期工作...

实际上,如果你切换到http仿真,你必须自己处理WebServiceException,也就是说,Silverlight无法读取非http状态200的http响应。

所以基本上你需要添加一个服务器端过滤器,将http状态代码更改为200

服务器端:

在您的Configure方法中添加:     GlobalResponseFilters.Add(HttpOverrideFriendExceptionFilter);

private static void HttpOverrideFriendExceptionFilter(IRequest request, IResponse httpResponse, object response)
    {
        if (request.Headers[HttpHeaders.XHttpMethodOverride] == null)
        {
            return;
        }

        Func<int, string, ResponseError> createRespErr = (statusCode, statusDesc) => new ResponseError
        {
            ErrorCode = statusCode.ToString(CultureInfo.InvariantCulture),
            FieldName = "__HTTP_EXCEPTION",
            Message = statusDesc
        };

        var httpDomainError = response as HttpError;
        if (httpDomainError != null)
        {
            httpResponse.StatusCode = 200;
            httpDomainError.ResponseStatus.Errors = new List<ResponseError>();
            httpDomainError.ResponseStatus.Errors.Add(createRespErr(httpDomainError.Status, httpDomainError.ErrorCode));
            httpDomainError.ResponseStatus.Errors.Add(new ResponseError
            {
                ErrorCode = httpDomainError.ErrorCode, Message = httpDomainError.Message
            });
            httpDomainError.StatusCode = HttpStatusCode.OK;
            httpResponse.Dto = httpDomainError;
            return;
        }

        var httpResult = response as IHttpResult;
        if (httpResult != null)
        {
            if (httpResult.StatusCode != HttpStatusCode.OK)
            {
                var errorStatus = httpResult.Status;
                var statusDesc = httpResult.StatusDescription;
                var respStatus = httpResult.Response.GetResponseStatus() ?? new ResponseStatus
                {
                    Errors = new List<ResponseError>()
                };
                var errResp = httpResult.Response as ErrorResponse ?? new ErrorResponse
                {
                    ResponseStatus = respStatus
                };

                httpResult.StatusCode = HttpStatusCode.OK;
                httpResult.Response = errResp;

                errResp.ResponseStatus.Errors.Add(createRespErr(errorStatus, statusDesc));
            }
            return;
        }

        var ex = response as Exception;
        if (ex != null)
        {
            var httpError = new HttpError(HttpStatusCode.OK, ex)
            {
                StatusCode = HttpStatusCode.OK,
                Response = new ErrorResponse
                {
                    ResponseStatus = new ResponseStatus
                    {
                        Errors = new List<ResponseError>()
                    }
                }
            };
            httpError.ResponseStatus.Errors.Add(createRespErr(500, "Unhandle Exception"));
            httpResponse.Dto = httpError;
        }
    }

在客户端级别,您需要像这样打包每个调用:

public class SilverlightClient : JsonServiceClient
{
    private const string InternalFieldError = "__HTTP_EXCEPTION";

    public SilverlightClient(string baseUri) 
        : base(baseUri)
    {

    }

    public TResponse SilverlightSend<TResponse>(object requestDto, string httpMethod)
    {
        var r = CustomMethod<HttpWebResponse>(httpMethod, requestDto);
        var text = r.ReadToEnd();

        AssertWebServiceException(text);

        return Deserialize<TResponse>(text);
    }

    public Task<TResponse> SilverlightSendAsync<TResponse>(object request, string httpMethod)
    {
        var task = CustomMethodAsync<HttpWebResponse>(httpMethod, request);
        var tsc = new TaskCompletionSource<TResponse>();

        task.ContinueWith(t =>
        {
            try
            {
                var text = t.Result.ReadToEnd();
                AssertWebServiceException(text);

                if (typeof(TResponse) == typeof(HttpWebResponse))
                {
                    tsc.SetResult((TResponse)(object)t.Result);
                    return;
                }

                tsc.SetResult(Deserialize<TResponse>(text));
            }
            catch (WebServiceException ex)
            {
                tsc.SetException(ex);
            }
            catch (Exception ex)
            {
                tsc.SetException(ex);
            }
        });

        return tsc.Task;
    }

    private void AssertWebServiceException(string text)
    {
        if (text != null && text.IndexOf(InternalFieldError, StringComparison.Ordinal) > -1)
        {
            var errResponse = Deserialize<ErrorResponse>(text);
            ThrowWebServiceException(errResponse);
        }
    }

    private static void ThrowWebServiceException(IHasResponseStatus errorResponse)
    {
        var respStatus = errorResponse.ResponseStatus;
        var serviceEx = new WebServiceException
        {
            StatusCode = 500,
            StatusDescription = respStatus.Message,
            ResponseDto = errorResponse,
        };

        var httpCode = respStatus.Errors.FirstOrDefault(e => e.FieldName == InternalFieldError);
        if (httpCode != null)
        {
            serviceEx.StatusCode = Convert.ToInt32(httpCode.ErrorCode);
            serviceEx.StatusDescription = httpCode.Message;
        }

        throw serviceEx;
    }
}

我知道这有点时髦但是你别无选择,因为Silverlight有很多限制,比如无法读取自定义http标题等等

希望有所帮助

此致