public void CheckErrors_WhenAckCodeIsSuccess_ShouldReturnEmpty(AckCodeType ackCode)
        {
            var abstractResponseType = new AbstractResponseType {
                Ack = ackCode
            };
            var result = _subject.CheckErrors(abstractResponseType);

            Assert.Equal(string.Empty, result);
        }
Example #2
0
        private void AssertCheckoutResponse(AckCodeType codeType, List <ErrorType> errorTypes)
        {
            if (codeType.Equals(AckCodeType.FAILURE) || (errorTypes != null && errorTypes.Count > 0))
            {
                var errMsg = string.Join(",", errorTypes.Select(e => e.ShortMessage + ":" + e.ErrorCode));

                throw new PayPalDGException(string.Format("An error occurred while processing payment to PayPal. (Error Details: {0})", errMsg));
            }
        }
 /// <summary>
 /// Determines whether [is valid response] [the specified ack code type].
 /// </summary>
 /// <param name="ackCodeType">Type of the ack code.</param>
 /// <returns>
 /// 	<c>true</c> if [is valid response] [the specified ack code type]; otherwise, <c>false</c>.
 /// </returns>
 private bool IsValidResponse(AckCodeType ackCodeType)
 {
     return ackCodeType != AckCodeType.Success && ackCodeType != AckCodeType.SuccessWithWarning;
 }
        public void CheckErrors_WhenAckCodeIsNotSuccessAndResponseHasNoErrors_ShouldReturnCorrectly(AckCodeType ackCode)
        {
            var abstractResponseType = new AbstractResponseType {
                Ack = ackCode
            };
            var result = _subject.CheckErrors(abstractResponseType);

            Assert.True(!string.IsNullOrEmpty(result));
        }
        public void CheckErrors_WhenAckCodeIsNotSuccessAndResponseHasErrors_ShouldReturnCorrectly(AckCodeType ackCode)
        {
            var errorCode            = "E0001";
            var message              = "ThisIsVeryLongMessage";
            var abstractResponseType = new AbstractResponseType {
                Ack = ackCode
            };

            abstractResponseType.Errors.Add(new ErrorType {
                SeverityCode = SeverityCodeType.ERROR, ErrorCode = errorCode, LongMessage = message
            });
            var result = _subject.CheckErrors(abstractResponseType);

            Assert.Contains(SeverityCodeType.ERROR.ToString(), result);
            Assert.Contains(errorCode, result);
            Assert.Contains(message, result);
        }
        /// <summary>
        /// Writes to response.
        /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers.
        /// </summary>
        /// <param name="response">The response.</param>
        /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
        /// <param name="defaultAction">The default action.</param>
        /// <param name="serializerCtx">The serialization context.</param>
        /// <param name="bodyPrefix">Add prefix to response body if any</param>
        /// <param name="bodySuffix">Add suffix to response body if any</param>
        /// <returns></returns>
        public static bool WriteToResponse(this IHttpResponse response, IHttpRequest request, object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, byte[] bodyPrefix, byte[] bodySuffix)
        {
            var defaultContentType = serializerCtx.ResponseContentType;
            AckCodeType ack = AckCodeType.Success;
            bool completed = true;
            try
            {
                if (result == null)
                {
                    response.EndRequestWithNoContent();
                    return true;
                }

                ApplyGlobalResponseHeaders(response);

                /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */
                var responseOptions = result as IHasOptions;
                if (responseOptions != null)
                {
                    //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction)
                    const string reservedOptions = ".";

                    foreach (var responseHeaders in responseOptions.Options)
                    {
                        if (responseHeaders.Key.Contains(reservedOptions)) continue;

                        Log.Debug(string.Format("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value),
                            new Dictionary<string, string>() 
                            {
                                {"ErrorCode", "FXD300061"}
                            });
                        response.AddHeader(responseHeaders.Key, responseHeaders.Value);
                    }
                }

                var disposableResult = result as IDisposable;

                //ContentType='text/html' is the default for a HttpResponse
                //Do not override if another has been set
                if (response.ContentType == null || response.ContentType == ContentType.Html)
                {
                    response.ContentType = defaultContentType;
                }
                if (bodyPrefix != null && response.ContentType.IndexOf(ContentType.Json, StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    response.ContentType = ContentType.JavaScript;
                }

                if (EndpointHost.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType))
                {
                    response.ContentType += ContentType.Utf8Suffix;
                }

                var responseText = result as string;
                if (responseText != null)
                {
                    if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length);
                    WriteTextToResponse(response, responseText, defaultContentType);
                    if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length);
                    return true;
                }

                var commonResponseDto = result as IHasResponseStatus;
                if (commonResponseDto != null)
                {
                    // defensive programming
                    if (commonResponseDto.ResponseStatus == null)
                    {
                        commonResponseDto.ResponseStatus = new ResponseStatusType();
                    }
                    commonResponseDto.ResponseStatus.Timestamp = DateTime.Now;
                    // TODO add version

                    // post ack check, in case developer forget to set ack according to error status 
                    bool hasError = false;
                    if (commonResponseDto.ResponseStatus.Ack == AckCodeType.Success && commonResponseDto.ResponseStatus.Errors.Count > 0)
                    {
                        foreach (ErrorDataType error in commonResponseDto.ResponseStatus.Errors)
                        {
                            if (error.SeverityCode == SeverityCodeType.Error)
                            {
                                hasError = true;
                                break;
                            }
                        }
                        if (hasError)
                        {
                            commonResponseDto.ResponseStatus.Ack = AckCodeType.Failure;
                        }
                    }

                    ack = commonResponseDto.ResponseStatus.Ack;

                    AddRequestInfoToResponseStatus(serializerCtx.Get<IHttpRequest>(), commonResponseDto);
                }

                // Defensive programming, in normal case, we should not see GenericErrorResponseType here
                // In case any exception, we set http status code to trigger SOA C# client side WebServiceException
                var genericErrorResponseDto = result as GenericErrorResponseType;
                if (genericErrorResponseDto != null)
                {
                    response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    ack = AckCodeType.Failure;
                }

                if (defaultAction == null)
                {
                    throw new ArgumentNullException("defaultAction", String.Format(
                    "As result '{0}' is not a supported responseType, a defaultAction must be supplied",
                    (result != null ? result.GetType().Name : "")));
                }

                if (EndpointHost.Config.ServiceManager.MetadataMap[request.ServicePath].UseChunkedTransferEncoding)
                {
                    response.AddHeader(ServiceUtils.ResponseStatusHttpHeaderKey, ack.ToString());
                    response.UseChunkedTransferEncoding();
                }

                if (bodyPrefix != null) response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length);
                if (result != null)
                {
                    try
                    {
                        defaultAction(serializerCtx, result, response);
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                    finally
                    {
                       //response.SerializationTimeInMillis = serializeTransaction.Transaction.DurationInMillis;
                    }
                }
                if (bodySuffix != null) response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length);
                
                // Record response size
                response.ExecutionResult.ResponseSize = response.OutputStream.Length;

                if (disposableResult != null) disposableResult.Dispose();

                return false;
            }
            catch (Exception originalEx)
            {
                ack = AckCodeType.Failure;

                bool usedChunkedTransferEncoding = response.UsedChunkedTransferEncoding();
                var errorMessage = string.Format("Error occured while {0}: [{1}] {2}",
                    usedChunkedTransferEncoding ? "using chunked transfer encoding" : "processing request", originalEx.GetType().Name, originalEx.Message);
                Log.Error(errorMessage, originalEx, new Dictionary<string, string>(){ { "ErrorCode", "FXD300010" } });

                //TM: It would be good to handle 'remote end dropped connection' problems here. Arguably they should at least be suppressible via configuration

                //DB: Using standard ServiceStack configuration method

                if (!EndpointHost.Config.WriteErrorsToResponse)
                {
                    completed = false;
                    throw;
                }

                if (response.IsClosed)
                    return true;
                
                if (usedChunkedTransferEncoding)
                    return true;

                try
                {
                    response.WriteErrorToResponse(serializerCtx.Get<IHttpRequest>(), defaultContentType, originalEx);
                    return true;
                }
                catch (Exception writeErrorEx)
                {
                    //Exception in writing to response should not hide the original exception
                    Log.Error("Failed to write error to response: " + writeErrorEx.Message, writeErrorEx, new Dictionary<string, string>(){ { "ErrorCode", "FXD300010" } });
                    completed = false;
                    throw originalEx;
                }
            }
            finally
            {
                if (!response.UsedChunkedTransferEncoding())
                    response.AddHeader(ServiceUtils.ResponseStatusHttpHeaderKey, ack.ToString());

                if (completed)
                    response.LogRequest(request);

                response.EndRequest(true);
            }
        }