Example #1
0
        /// <summary>
        /// This method resolves the appropriate transport serialzer from the incoming accept header.
        /// </summary>
        /// <param name="rs">The incoming response.</param>
        /// <param name="transport">The resolve transport serializer.</param>
        /// <returns>Returns true if the serializer can be resolved.</returns>
        protected virtual void ExtractHeaders <KT>(HttpResponseMessage rs, RepositoryHolder <KT> holder, IKeyMapper <KT> keyMapper)
        {
            string contentId = rs.Headers.Where((h) => h.Key.Equals("x-img-contentid", StringComparison.InvariantCultureIgnoreCase))
                               .SelectMany((h) => h.Value).FirstOrDefault() ?? "";
            string versionId = rs.Headers.Where((h) => h.Key.Equals("x-img-versionid", StringComparison.InvariantCultureIgnoreCase))
                               .SelectMany((h) => h.Value).FirstOrDefault() ?? "";

            holder.KeyReference = new Tuple <string, string>(contentId, versionId);

            if (!string.IsNullOrEmpty(contentId))
            {
                holder.Key = keyMapper.ToKey(contentId);
            }
        }
        /// <summary>
        /// This method marshals the RepositoryHolder and transmits it to the remote Microservice.
        /// </summary>
        /// <typeparam Name="KT">The key type.</typeparam>
        /// <typeparam Name="ET">The entity type.</typeparam>
        /// <param Name="actionType">The action type.</param>
        /// <param Name="rq">The repository holder request.</param>
        /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns>
        protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(
            string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null, IPrincipal principal = null)
        {
            try
            {
                StatisticsInternal.ActiveIncrement();

                var payload = TransmissionPayload.Create(Policy.TransmissionPayloadTraceEnabled);

                payload.SecurityPrincipal = TransmissionPayload.ConvertToClaimsPrincipal(principal ?? Thread.CurrentPrincipal);

                // Set the process correlation key to the correlation id if passed through the rq settings
                if (!string.IsNullOrEmpty(rq.Settings?.CorrelationId))
                {
                    payload.Message.ProcessCorrelationKey = rq.Settings.CorrelationId;
                }

                bool processAsync = rq.Settings?.ProcessAsync ?? false;

                payload.Message.ChannelPriority = processAsync ? 0 : 1;

                payload.Options = routing ?? RoutingDefault ?? ProcessOptions.RouteExternal;

                payload.Message.Blob = PayloadSerializer.PayloadSerialize(rq);

                payload.Message.ResponseChannelId = ResponseChannelId;

                payload.Message.ResponseChannelId   = ResponseId.Header.ChannelId;
                payload.Message.ResponseMessageType = ResponseId.Header.MessageType;
                payload.Message.ResponseActionType  = ResponseId.Header.ActionType;

                payload.Message.ResponseChannelPriority = payload.Message.ChannelPriority;

                payload.Message.ChannelId   = ChannelId;
                payload.Message.MessageType = EntityType;
                payload.Message.ActionType  = actionType;

                payload.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan;

                return(await OutgoingRequestOut(payload, ProcessResponse <KT, ET>, processAsync));
            }
            catch (Exception ex)
            {
                string key = rq != null && rq.Key != null?rq.Key.ToString() : string.Empty;

                Collector?.LogException($"Error transmitting {actionType}-{key} internally", ex);
                throw;
            }
        }
Example #3
0
        public PersistenceRepositoryHolder(RepositoryHolder <K, E> holder = null)
        {
            IsTimeout            = false;
            Retry                = 0;
            ShouldLogEventSource = true;

            if (holder != null)
            {
                Entity          = holder.Entity;
                Key             = holder.Key;
                KeyReference    = holder.KeyReference;
                Settings        = holder.Settings;
                ResponseCode    = holder.ResponseCode;
                ResponseMessage = holder.ResponseMessage;
                TraceId         = holder.TraceId;
            }

            Settings = Settings ?? new RepositorySettings();
        }
        public PersistencePayloadLogEvent(TransmissionPayload payload, RepositoryHolder request, RepositoryHolder response, LoggingLevel?level = null
                                          , Exception ex = null, DispatcherLoggerDirection?direction = null, TimeSpan?processingTime = null)
            : base(payload, level, ex, direction, processingTime)
        {
            if (request != null)
            {
                TraceId = request.TraceId;
                if (request.Settings != null)
                {
                    BatchId = request.Settings.BatchId;
                    Prefer  = request.Settings.Prefer;
                    Headers = request.Settings.Headers;
                }
            }

            if (response != null)
            {
                ResponseCode    = response.ResponseCode;
                ResponseMessage = response.ResponseMessage;
            }
        }
Example #5
0
        public virtual async Task <IHttpActionResult> Search(ODataQueryOptions <E> request)
        {
            try
            {
                //Validate that the request is correctly formed.
                request.Validate(mODataValidate);

                //Load the request with the necessary parameters.
                SearchRequest rq = new SearchRequest();
                rq.ODataPopulate(request);

                //Make the request to the persistence service.
                RepositorySettings settings = ApiUtility.BuildRepositorySettings(ActionContext);
                RepositoryHolder <SearchRequest, SearchResponse> response = await mRespository.Search(rq, settings);

                return(new OData4ServiceDocumentResponse(response, ActionContext.Request.RequestUri));
            }
            catch (Exception vex)
            {
                return(BadRequest($"Unable to process Odata request - {vex.Message}"));
            }
        }
Example #6
0
        /// <summary>
        /// This method marshals the RepositoryHolder and transmits it to the remote Microservice.
        /// </summary>
        /// <typeparam Name="KT">The key type.</typeparam>
        /// <typeparam Name="ET">The entity type.</typeparam>
        /// <param name="actionType">The action type.</param>
        /// <param name="rq">The repository holder request.</param>
        /// <param name="routing"></param>
        /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns>
        protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null, IPrincipal principal = null)
        {
            StatisticsInternal.ActiveIncrement();

            var payloadRq = TransmissionPayload.Create(mPolicy.TransmissionPayloadTraceEnabled);

            // Set the originator key to the correlation id if passed through the rq settings
            if (!string.IsNullOrEmpty(rq.Settings?.CorrelationId))
            {
                payloadRq.Message.ProcessCorrelationKey = rq.Settings.CorrelationId;
            }

            bool processAsync = rq.Settings?.ProcessAsync ?? false;

            payloadRq.Options = ProcessOptions.RouteInternal;
            var message = payloadRq.Message;

            payloadRq.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan;
            payloadRq.MessageObject     = rq;
            message.ChannelId           = ChannelId;
            message.ChannelPriority     = processAsync ? 0:-1;
            message.MessageType         = mMessageType;
            message.ActionType          = actionType;

            message.ResponseChannelId       = mResponseChannel;
            message.ResponseChannelPriority = -1; //Always internal

            message.Blob = PayloadSerializer.PayloadSerialize(rq);

            return(await OutgoingRequestOut(payloadRq, ProcessResponse <KT, ET>, processAsync : processAsync));
        }
 /// <summary>
 /// This abstract method is used to transmit the request to the appropriate party.
 /// </summary>
 /// <typeparam name="KT">The key type.</typeparam>
 /// <typeparam name="ET">The entity type.</typeparam>
 /// <param name="actionType">The request action type, i.e. Create/Read etc.</param>
 /// <param name="rq">The request.</param>
 /// <param name="routing">The routing options.</param>
 /// <returns>Returns the request response.</returns>
 protected abstract Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null, IPrincipal principal = null)
     where KT : IEquatable <KT>;
        /// <summary>
        /// This method marshals the RepositoryHolder and transmits it to the remote Microservice.
        /// </summary>
        /// <typeparam Name="KT">The key type.</typeparam>
        /// <typeparam Name="ET">The entity type.</typeparam>
        /// <param Name="actionType">The action type.</param>
        /// <param Name="rq">The repository holder request.</param>
        /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns>
        protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null)
        {
            try
            {
                StatisticsInternal.ActiveIncrement();

                var payload = TransmissionPayload.Create();

                // Set the originator key to the correlation id if passed through the rq settings
                if (rq.Settings != null && !string.IsNullOrEmpty(rq.Settings.CorrelationId))
                {
                    payload.Message.OriginatorKey = rq.Settings.CorrelationId;
                }

                bool processAsync = rq.Settings == null ? false : rq.Settings.ProcessAsync;

                payload.Message.ChannelPriority = processAsync ? 0 : 1;

                payload.Options = routing ?? RoutingDefault ?? ProcessOptions.RouteExternal;

                payload.Message.Blob = PayloadSerializer.PayloadSerialize(rq);

                payload.Message.ResponseChannelId       = ResponseChannelId;
                payload.Message.ResponseChannelPriority = payload.Message.ChannelPriority;

                payload.Message.ChannelId   = ChannelId;
                payload.Message.MessageType = EntityType;
                payload.Message.ActionType  = actionType;

                payload.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan;

                return(await TransmitAsync(payload, ProcessResponse <KT, ET>, processAsync));
            }
            catch (Exception ex)
            {
                string key = rq != null && rq.Key != null?rq.Key.ToString() : string.Empty;

                Logger.LogException(string.Format("Error transmitting {0}-{1} internally", actionType, key), ex);
                throw;
            }
        }
Example #9
0
        /// <summary>
        /// This method resolves the appropriate transport serialzer from the incoming accept header.
        /// </summary>
        /// <param name="rs">The response</param>
        /// <param name="data">The response content</param>
        /// <param name="holder">The repository holder</param>
        /// <returns>Returns true if the serializer can be resolved.</returns>
        protected virtual void EntityDeserialize(HttpResponseMessage rs, byte[] data, RepositoryHolder <K, E> holder)
        {
            string mediaType = rs.Content.Headers.ContentType.MediaType;

            if (mTransportSerializers.ContainsKey(mediaType))
            {
                var transport = mTransportSerializers[mediaType];
                holder.Entity = transport.GetObject(data);
            }
            else
            {
                throw new TransportSerializerResolutionException(mediaType);
            }
        }
Example #10
0
        /// <summary>
        /// This method calls the client using HTTP and returns the response along with the entity in the response if supplied.
        /// </summary>
        /// <typeparam name="KT">The key type.</typeparam>
        /// <typeparam name="ET">The entity type.</typeparam>
        /// <param name="uri">The request uri.</param>
        /// <param name="options">The repository settings passed from the caller.</param>
        /// <param name="content">The HttpContent to send to the API.</param>
        /// <param name="adjust">Any message adjustment.</param>
        /// <param name="mapper">Any response adjustment before returning to the caller.</param>
        /// <param name="deserializer">Deserialize the response content into the entity</param>
        /// <returns></returns>
        protected virtual async Task <RepositoryHolder <KT, ET> > CallClient <KT, ET>(
            KeyValuePair <HttpMethod, Uri> uri
            , RepositorySettings options
            , HttpContent content = null
            , Action <HttpRequestMessage> adjust = null
            , Action <HttpResponseMessage, RepositoryHolder <KT, ET> > mapper = null
            , Action <HttpResponseMessage, byte[], RepositoryHolder <KT, ET> > deserializer = null)
        {
            var response = new RepositoryHolder <KT, ET>();

            try
            {
                HttpRequestMessage httpRq = Request(uri.Key, uri.Value);

                RequestHeadersSet(httpRq);

                RequestHeadersSetTransport(httpRq);

                RequestHeadersPreferSet(httpRq, options?.Prefer);

                RequestHeadersAuth(httpRq);

                adjust?.Invoke(httpRq);

                if (content != null)
                {
                    httpRq.Content = content;
                }

                var client = new HttpClient();

                // Specify request body
                var httpRs = await client.SendAsync(httpRq);

                ResponseHeadersAuth(httpRq, httpRs);

                //OK, set the response content if set
                if (httpRs.Content != null && httpRs.Content.Headers.ContentLength > 0)
                {
                    byte[] httpRsContent = await httpRs.Content.ReadAsByteArrayAsync();

                    if (httpRs.IsSuccessStatusCode)
                    {
                        deserializer?.Invoke(httpRs, httpRsContent, response);
                    }
                    else
                    {
                        // So that we can see error messages such as schema validation fail
                        response.ResponseMessage = Encoding.UTF8.GetString(httpRsContent);
                    }
                }

                //Get any outgoing trace headers and set them in to the response.
                IEnumerable <string> trace;
                if (httpRs.Headers.TryGetValues(ApimConstants.AzureTraceHeaderLocation, out trace))
                {
                    response.Settings.Prefer.Add(ApimConstants.AzureTraceHeaderLocation, trace.First());
                }

                response.ResponseCode = (int)httpRs.StatusCode;

                mapper?.Invoke(httpRs, response);
            }
            catch (Exception ex)
            {
                response.ResponseMessage = FormatExceptionChain(ex);
                response.ResponseCode    = 503;
            }

            return(response);
        }
Example #11
0
        /// <summary>
        /// This method registers the specific persistence handler.
        /// </summary>
        /// <typeparam Name="KT">The key type.</typeparam>
        /// <typeparam Name="ET">The entity type.</typeparam>
        /// <param name="actionType">The action type identifier</param>
        /// <param name="action">The action to process the command.</param>
        /// <param name="logEventOnSuccess"></param>
        /// <param name="preaction"></param>
        /// <param name="postaction"></param>
        /// <param name="timeoutcorrect"></param>
        /// <param name="retryOnTimeout"></param>
        /// <param name="channelId"></param>
        /// <param name="entityType"></param>
        protected virtual void PersistenceCommandRegister <KT, ET>(string actionType
                                                                   , Func <PersistenceRequestHolder <KT, ET>, Task> action
                                                                   , bool logEventOnSuccess = false
                                                                   , Func <PersistenceRequestHolder <KT, ET>, Task <bool> > preaction      = null
                                                                   , Func <PersistenceRequestHolder <KT, ET>, Task> postaction             = null
                                                                   , Func <PersistenceRequestHolder <KT, ET>, Task <bool> > timeoutcorrect = null
                                                                   , int?retryOnTimeout = null
                                                                   , string channelId   = null
                                                                   , string entityType  = null
                                                                   )
        {
            Func <TransmissionPayload, List <TransmissionPayload>, Task> actionPayload = async(incoming, outgoing) =>
            {
                var profileHolder = ProfileStart <KT, ET>(incoming, outgoing);

                try
                {
                    var rsMessage = incoming.Message.ToResponse();

                    rsMessage.ChannelId       = incoming.Message.ResponseChannelId;
                    rsMessage.ChannelPriority = incoming.Message.ResponseChannelPriority;
                    rsMessage.MessageType     = incoming.Message.MessageType;
                    rsMessage.ActionType      = "";

                    var rsPayload = new TransmissionPayload(rsMessage);

                    bool hasTimedOut = false;

                    try
                    {
                        RepositoryHolder <KT, ET> rqTemp = incoming.MessageObject as RepositoryHolder <KT, ET>;

                        //Deserialize the incoming payloadRq request
                        if (rqTemp == null)
                        {
                            rqTemp = PayloadSerializer.PayloadDeserialize <RepositoryHolder <KT, ET> >(incoming);
                        }

                        profileHolder.Rq = new PersistenceRepositoryHolder <KT, ET>(rqTemp);

                        if (profileHolder.Rq.Timeout == null)
                        {
                            profileHolder.Rq.Timeout = TimeSpan.FromSeconds(10);
                        }

                        bool preactionFailed = false;

                        try
                        {
                            bool retryExceeded = false;

                            do
                            {
                                int attempt = Environment.TickCount;

                                //Create the payloadRs holder, and discard any previous version.
                                profileHolder.Rs = new PersistenceRepositoryHolder <KT, ET>();

                                if (preaction != null && !(await preaction(profileHolder)))
                                {
                                    preactionFailed = true;
                                    break;
                                }

                                //Call the specific command to process the action, i.e Create, Read, Update, Delete ... etc.
                                await action(profileHolder);

                                //Flag if the request times out at any point.
                                //This may be required later when checking whether the action was actually successful.
                                hasTimedOut |= profileHolder.Rs.IsTimeout;

                                //OK, if this is not a time out then it is successful
                                if (!profileHolder.Rs.IsTimeout && !profileHolder.Rs.ShouldRetry)
                                {
                                    break;
                                }

                                ProfileRetry(profileHolder, attempt);

                                if (profileHolder.Rs.IsTimeout)
                                {
                                    Logger.LogMessage(LoggingLevel.Warning, $"Timeout occured for {EntityType} {actionType} for request:{profileHolder.Rq} with response:{profileHolder.Rs}", "DBTimeout");
                                }

                                profileHolder.Rq.IsRetry = true;
                                //These should not be counted against the limit.
                                if (!profileHolder.Rs.ShouldRetry)
                                {
                                    profileHolder.Rq.Retry++;
                                }

                                profileHolder.Rq.IsTimeout = false;

                                retryExceeded = incoming.Cancel.IsCancellationRequested ||
                                                profileHolder.Rq.Retry > mPolicy.PersistenceRetryPolicy.GetMaximumRetries(incoming);
                            }while (!retryExceeded);

                            //Signal to the underlying comms channel that the message has been processed successfully.
                            incoming.Signal(!retryExceeded);

                            // If we have exceeded the retry limit then Log error
                            if (retryExceeded)
                            {
                                Log(actionType
                                    , profileHolder
                                    , LoggingLevel.Error
                                    , $"Retry limit has been exceeded (cancelled ({incoming.Cancel.IsCancellationRequested})) for {EntityType} {actionType} for {profileHolder.Rq} after {incoming.Message?.FabricDeliveryCount} delivery attempts"
                                    , "DBRetry");

                                profileHolder.result = ResourceRequestResult.RetryExceeded;
                            }
                        }
                        catch (Exception ex)
                        {
                            LogException(actionType, profileHolder, ex);
                            incoming.SignalFail();
                            profileHolder.result = ResourceRequestResult.Exception;
                        }

                        bool logEventSource = !preactionFailed && logEventOnSuccess && profileHolder.Rs.IsSuccess;

                        if (!profileHolder.Rs.IsSuccess && hasTimedOut && timeoutcorrect != null && profileHolder.result != ResourceRequestResult.Exception)
                        {
                            if (await timeoutcorrect(profileHolder))
                            {
                                logEventSource = true;
                                Logger.LogMessage(LoggingLevel.Info
                                                  , string.Format("Recovered timeout sucessfully for {0}-{1} for request:{2} - response:{3}", EntityType, actionType, profileHolder.Rq, profileHolder.Rs)
                                                  , "DBTimeout");
                            }
                            else
                            {
                                Logger.LogMessage(LoggingLevel.Error
                                                  , string.Format("Not recovered timeout for {0}-{1} for request:{2} - response:{3}", EntityType, actionType, profileHolder.Rq, profileHolder.Rs)
                                                  , "DBTimeout");
                            }
                        }

                        if (logEventSource && profileHolder.Rs.ShouldLogEventSource)
                        {
                            await LogEventSource(actionType, profileHolder);
                        }

                        if (!preactionFailed && postaction != null)
                        {
                            await postaction(profileHolder);
                        }

                        //Serialize the payloadRs
                        var reposHolder = profileHolder.Rs.ToRepositoryHolder();

                        rsPayload.MessageObject = reposHolder;
                        rsPayload.Message.Blob  = PayloadSerializer.PayloadSerialize(reposHolder);

                        rsPayload.Message.Status = "200";

                        if (!profileHolder.result.HasValue)
                        {
                            profileHolder.result = ResourceRequestResult.Success;
                        }
                    }
                    catch (Exception ex)
                    {
                        incoming.SignalFail();
                        rsPayload.Message.Status            = "500";
                        rsPayload.Message.StatusDescription = ex.Message;
                        Logger.LogException($"Error processing message (was cancelled({incoming.Cancel.IsCancellationRequested}))-{EntityType}-{actionType}-{profileHolder.Rq}", ex);
                        profileHolder.result = ResourceRequestResult.Exception;
                    }

                    // check whether we need to send a response message. If this is async and AsyncResponse is not set to true,
                    // then by default we do not send a response message to cut down on unnecessary traffic.
                    if (profileHolder.Rq == null || profileHolder.Rq.Settings == null || !profileHolder.Rq.Settings.ProcessAsync)
                    {
                        outgoing.Add(rsPayload);
                    }
                }
                finally
                {
                    ProfileEnd(profileHolder);
                }
            };

            if (channelId == null)
            {
                channelId = ChannelId ?? string.Empty;
            }

            if (entityType == null)
            {
                entityType = EntityType;
            }

            CommandRegister(
                channelId.ToLowerInvariant()
                , entityType.ToLowerInvariant()
                , actionType.ToLowerInvariant()
                , actionPayload);
        }
Example #12
0
        /// <summary>
        /// This method marshals the RepositoryHolder and transmits it to the remote Microservice.
        /// </summary>
        /// <typeparam Name="KT">The key type.</typeparam>
        /// <typeparam Name="ET">The entity type.</typeparam>
        /// <param name="actionType">The action type.</param>
        /// <param name="rq">The repository holder request.</param>
        /// <param name="routing"></param>
        /// <returns>Returns an async task that will be signalled when the request completes or times out.</returns>
        protected override async Task <RepositoryHolder <KT, ET> > TransmitInternal <KT, ET>(string actionType, RepositoryHolder <KT, ET> rq, ProcessOptions?routing = null)
        {
            StatisticsInternal.ActiveIncrement();

            var payloadRq = TransmissionPayload.Create();

            bool processAsync = rq.Settings?.ProcessAsync ?? false;

            payloadRq.Options = ProcessOptions.RouteInternal;
            var message = payloadRq.Message;

            payloadRq.MaxProcessingTime = rq.Settings?.WaitTime ?? mDefaultRequestTimespan;
            payloadRq.MessageObject     = rq;
            message.ChannelId           = ChannelId;
            message.ChannelPriority     = processAsync ? 0:-1;
            message.MessageType         = mMessageType;
            message.ActionType          = actionType;

            message.ResponseChannelId       = mResponseChannel;
            message.ResponseChannelPriority = -1; //Always internal

            message.Blob = PayloadSerializer.PayloadSerialize(rq);

            return(await TransmitAsync(payloadRq, ProcessResponse <KT, ET>, processAsync : processAsync));
        }
Example #13
0
 public PersistenceRepositoryHolder(RepositoryHolder <object, object> rqTemp)
 {
     this.rqTemp = rqTemp;
 }
Example #14
0
        /// <summary>
        /// This method processes the outgoing response.
        /// </summary>
        /// <typeparam name="KT">The key type.</typeparam>
        /// <typeparam name="ET">The entity type.</typeparam>
        /// <param name="responseHolder">The response message.</param>
        /// <param name="entitySerializer">The optional serializer.</param>
        /// <returns>Returns the relevant result.</returns>
        protected virtual IHttpActionResult ResponseFormat <KT, ET>(RepositoryHolder <KT, ET> responseHolder
                                                                    , TransportSerializer <ET> entitySerializer = null)
        {
            ApiResponse response = null;

            switch (responseHolder.ResponseCode)
            {
            case 200:
                response = new ApiResponse(HttpStatusCode.OK);
                break;

            case 201:
                response = new ApiResponse(HttpStatusCode.Created);
                break;

            case 202:
                response = new ApiResponse(HttpStatusCode.Accepted);
                break;

            case 204:
                response = new ApiResponse(HttpStatusCode.NoContent);
                break;

            case 400:
                return(BadRequest(responseHolder.ResponseMessage ?? string.Empty));

            case 404:
                return(StatusCode(HttpStatusCode.NotFound));

            case 405:
                return(StatusCode(HttpStatusCode.MethodNotAllowed));

            case 408:
                return(StatusCode(HttpStatusCode.RequestTimeout));

            case 409:
                return(StatusCode(HttpStatusCode.Conflict));

            case 412:
                return(StatusCode(HttpStatusCode.PreconditionFailed));

            case 417:
                return(StatusCode(HttpStatusCode.ExpectationFailed));

            case 442:
                return(StatusCode(HttpStatusCode.UnsupportedMediaType));

            case 502:
                return(StatusCode(HttpStatusCode.BadGateway));

            case 504:
                return(StatusCode(HttpStatusCode.GatewayTimeout));

            default:
                LogMessage(LoggingLevel.Error, $"Unexpected error occurred {responseHolder}");
                return(StatusCode(HttpStatusCode.InternalServerError));
            }

            if (entitySerializer != null && responseHolder.Entity != null)
            {
                response.MediaType = entitySerializer.MediaType;
                response.Data      = entitySerializer.GetData(responseHolder.Entity);
            }

            if (responseHolder.KeyReference != null)
            {
                response.ContentId = responseHolder.KeyReference.Item1;
                response.VersionId = responseHolder.KeyReference.Item2;
            }

            if (responseHolder.IsCached)
            {
                response.IsCached = true;
            }

            return(response);
        }
 public OData4ServiceDocumentResponse(RepositoryHolder <SearchRequest, SearchResponse> response, Uri requestUri)
 {
     mRequest  = requestUri;
     mResponse = response;
 }
Example #16
0
        /// <summary>
        /// This method calls the client using HTTP and returns the response along with the entity in the response if supplied.
        /// </summary>
        /// <typeparam name="KT">The key type.</typeparam>
        /// <typeparam name="ET">The entity type.</typeparam>
        /// <param name="uri">The request uri.</param>
        /// <param name="options">The repository settings passed from the caller.</param>
        /// <param name="content">The HttpContent to send to the API.</param>
        /// <param name="adjust">Any message adjustment.</param>
        /// <param name="mapper">Any response adjustment before returning to the caller.</param>
        /// <param name="deserializer">Deserialize the response content into the entity</param>
        /// <returns></returns>
        protected virtual async Task <RepositoryHolder <KT, ET> > CallClient <KT, ET>(
            KeyValuePair <HttpMethod, Uri> uri
            , RepositorySettings options
            , HttpContent content = null
            , Action <HttpRequestMessage> adjust = null
            , Action <HttpResponseMessage, RepositoryHolder <KT, ET> > mapper = null
            , Action <HttpResponseMessage, byte[], RepositoryHolder <KT, ET> > deserializer = null)
        {
            var rs = new RepositoryHolder <KT, ET>();

            try
            {
                HttpRequestMessage rq = Request(uri.Key, uri.Value);

                adjust?.Invoke(rq);

                if (content != null)
                {
                    rq.Content = content;
                }

                if (options?.Prefer != null && options.Prefer.Count > 0)
                {
                    rq.Headers.Add("Prefer", options.Prefer.Select((k) => string.Format("{0}={1}", k.Key, k.Value)));
                }

                var client = new HttpClient();

                // Specify request body
                var response = await client.SendAsync(rq);

                if (response.Content != null && response.Content.Headers.ContentLength > 0)
                {
                    byte[] rsContent = await response.Content.ReadAsByteArrayAsync();

                    if (response.IsSuccessStatusCode)
                    {
                        deserializer?.Invoke(response, rsContent, rs);
                    }
                    else
                    {
                        // So that we can see error messages such as schema validation fail
                        rs.ResponseMessage = Encoding.UTF8.GetString(rsContent);
                    }
                }

                //Get any outgoing trace headers and set them in to the response.
                IEnumerable <string> trace;
                if (response.Headers.TryGetValues(ApimConstants.AzureTraceHeaderLocation, out trace))
                {
                    rs.Settings.Prefer.Add(ApimConstants.AzureTraceHeaderLocation, trace.First());
                }

                rs.ResponseCode = (int)response.StatusCode;

                mapper?.Invoke(response, rs);
            }
            catch (Exception ex)
            {
                rs.ResponseMessage = FormatExceptionChain(ex);
                rs.ResponseCode    = 503;
            }

            return(rs);
        }