예제 #1
0
        /// <summary>
        /// Proxies the specified request to the actual Store REST API.
        /// </summary>
        /// <param name="pathAndQuery">
        /// The UriAbsolutePath and Query properties.  Simply, this is the entire Uri except for
        /// the protocol and domain information.
        /// </param>
        /// <param name="method">The <see cref="HttpMethod"/> of the REST API.</param>
        /// <param name="onBehalfOf">
        /// The <see cref="IPrincipal"/> of the user that we're performing the API request on behalf of.
        /// </param>
        /// <param name="body">The body content of the REST request (if needed).</param>
        /// <param name="tenantId">
        /// [Optional] The tenantId that should be used for the request if the proxy supports
        /// multiple tenants.  Mutually exclusive with <paramref name="tenantName"/> since
        /// <paramref name="tenantName"/> is a "friendly" version of this value.  If neither this
        /// nor <paramref name="tenantName"/> are provided, the default TenantId will be used for
        /// this request.
        /// </param>
        /// <param name="tenantName">
        /// [Optional] The friendly name of the <paramref name="tenantId"/> that should be used for
        /// the request if the proxy supports multiple tenants.  Mutually exclusive with
        /// <paramref name="tenantId"/> since this is a friendly name version of that value.
        /// If neither this nor <paramref name="tenantId"/> are provided, the default TenantId will
        /// be used for this request.
        /// </param>
        /// <param name="endpointType">The type of endpoint that should be used for the request.</param>
        /// <param name="correlationId">
        /// An ID that a client may have set in the header (which we must proxy) to track a string of related requests.
        /// </param>
        /// <param name="clientRequestId">
        /// An ID that a client may have set in the header (which we must proxy) to track an individual request.
        /// </param>
        /// <returns>The <see cref="HttpResponseMessage"/> to be sent to the user.</returns>
        public static async Task <HttpResponseMessage> PerformRequestAsync(
            string pathAndQuery,
            HttpMethod method,
            IPrincipal onBehalfOf,
            string body               = null,
            string tenantId           = null,
            string tenantName         = null,
            EndpointType endpointType = EndpointType.Prod,
            string correlationId      = null,
            string clientRequestId    = null)
        {
            // We'll track how long this takes, for telemetry purposes.
            Stopwatch stopwatch = Stopwatch.StartNew();

            // Assume ok unless we find out otherwise.
            HttpStatusCode statusCode = HttpStatusCode.OK;

            // We want to record the request header for every request in case we need to look up failures later.
            string requestId = string.Empty;

            // We also want to store the ClientId so that it's easier to see distribution of requests across Clients.
            string clientId = string.Empty;

            try
            {
                Endpoint            endpoint = null;
                HttpResponseMessage response;
                if (ProxyManager.TryGetEndpoint(tenantId, tenantName, endpointType, out endpoint, out response))
                {
                    clientId = endpoint.ClientId;
                    response = await endpoint.PerformRequestAsync(pathAndQuery, method, onBehalfOf, body, correlationId, clientRequestId);
                }

                // We'll capture the status code for use in the finally block.
                statusCode = response.StatusCode;

                // Get any of the request ID headers that can be used for post-mortem diagnostics.  We'll use them in the finally block.
                IEnumerable <string> headerValues;
                if (response.Headers.TryGetValues(ProxyManager.MSCorrelationIdHeader, out headerValues))
                {
                    // If the client supplied a correlationId, the value we're getting back from the API should be identical.
                    correlationId = headerValues.FirstOrDefault();
                }

                if (response.Headers.TryGetValues(ProxyManager.MSRequestIdHeader, out headerValues))
                {
                    requestId = headerValues.FirstOrDefault();
                }

                if (response.Headers.TryGetValues(ProxyManager.MSClientRequestIdHeader, out headerValues))
                {
                    // If the client supplied a clientRequestId, the value we're getting back from the API should be identical.
                    clientRequestId = headerValues.FirstOrDefault();
                }

                return(response);
            }
            finally
            {
                stopwatch.Stop();
                ProxyManager.LogTelemetryEvent(
                    onBehalfOf.Identity.Name,
                    pathAndQuery,
                    method,
                    tenantId,
                    tenantName,
                    clientId,
                    endpointType,
                    statusCode,
                    correlationId,
                    requestId,
                    clientRequestId,
                    stopwatch.Elapsed.TotalSeconds);
            }
        }