Ejemplo n.º 1
0
        /// <summary>
        /// Executes the request. If there are more waypoints than the batchSize value (default 25), only a MaxSolutions is set to 1, and Tolerances is set to null.
        /// </summary>
        /// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
        /// <returns>A response containing the requested data.</returns>
        public override async Task <Response> Execute(Action <int> remainingTimeCallback)
        {
            if (Waypoints.Count <= batchSize)
            {
                using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(GetRequestUrl())))
                {
                    return(ServiceHelper.DeserializeStream <Response>(responseStream));
                }
            }

            //There is more waypoints than the batchSize value (default 25), break it up into multiple requests. Only allow a single route in the response and no tolerances.
            if (RouteOptions != null)
            {
                if (RouteOptions.MaxSolutions > 1)
                {
                    RouteOptions.MaxSolutions = 1;
                }

                RouteOptions.Tolerances = null;
            }

            if (Waypoints == null)
            {
                throw new Exception("Waypoints not specified.");
            }
            else if (Waypoints.Count < 2)
            {
                throw new Exception("Not enough Waypoints specified.");
            }
            else if (Waypoints[0].IsViaPoint || Waypoints[Waypoints.Count - 1].IsViaPoint)
            {
                throw new Exception("Start and end waypoints must not be ViaWaypoints.");
            }

            int startIdx = 0;
            int endIdx   = 0;

            var requestUrls = new List <string>();

            while (endIdx < Waypoints.Count - 1)
            {
                requestUrls.Add(GetRequestUrl(startIdx, out endIdx));
                startIdx = endIdx - 1;
            }

            var      routes        = new Route[requestUrls.Count];
            Response response      = null;
            Response errorResponse = null;

            Parallel.For(0, requestUrls.Count, (i) =>
            {
                try
                {
                    //Make the call synchronously as we are in a parrallel for loop and need this to block, otherwise the for loop will exist before the async code has completed.
                    using (var responseStream = ServiceHelper.GetStreamAsync(new Uri(requestUrls[i])).GetAwaiter().GetResult())
                    {
                        var r = ServiceHelper.DeserializeStream <Response>(responseStream);

                        if (r != null)
                        {
                            if (r.ErrorDetails != null && r.ErrorDetails.Length > 0)
                            {
                                errorResponse = r;
                            }
                            else if (r.ResourceSets != null && r.ResourceSets.Length > 0 &&
                                     r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0)
                            {
                                routes[i] = r.ResourceSets[0].Resources[0] as Route;
                            }
                        }

                        if (i == 0)
                        {
                            response = r;
                        }
                    }
                }
                catch (Exception ex)
                {
                    errorResponse = new Response()
                    {
                        ErrorDetails = new string[]
                        {
                            ex.Message
                        }
                    };
                }
            });

            //If any of the responses failed to process, do not merge results, return the error info.
            if (errorResponse != null)
            {
                return(errorResponse);
            }

            response.ResourceSets[0].Resources[0] = await MergeRoutes(routes);

            return(response);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Executes the request. If there are more waypoints than the batchSize value (default 25), only a MaxSolutions is set to 1, and Tolerances is set to null.
        /// </summary>
        /// <param name="remainingTimeCallback">A callback function in which the estimated remaining time in seconds is sent.</param>
        /// <returns>A response containing the requested data.</returns>
        public override async Task <Response> Execute(Action <int> remainingTimeCallback)
        {
            Response response = null;

            if (WaypointOptimization != null && WaypointOptimization.HasValue && Waypoints.Count >= 2)
            {
                var wpHash = ServiceHelper.GetSequenceHashCode <SimpleWaypoint>(Waypoints);

                var      optionHash = Enum.GetName(typeof(TspOptimizationType), WaypointOptimization);
                var      mode       = TravelModeType.Driving;
                DateTime?depart     = null;

                if (RouteOptions != null)
                {
                    optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteOptions.TimeType);

                    if (RouteOptions.TimeType == RouteTimeType.Departure && RouteOptions.DateTime != null && RouteOptions.DateTime.HasValue)
                    {
                        depart      = RouteOptions.DateTime;
                        optionHash += "|" + RouteOptions.DateTime.ToString();
                    }

                    mode = RouteOptions.TravelMode;

                    optionHash += "|" + Enum.GetName(typeof(TravelModeType), mode);
                }
                else
                {
                    optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteTimeType.Departure);
                }

                //Check to see if the waypoints have changed since they were last optimized.
                if (waypointsHash != wpHash || string.Compare(optimizationOptionHash, optionHash) != 0)
                {
                    var tspResult = await TravellingSalesmen.Solve(Waypoints, mode, WaypointOptimization, depart, BingMapsKey);

                    Waypoints = tspResult.OptimizedWaypoints;

                    //Update the stored hashes to prevent unneeded optimizations in the future if not needed.
                    waypointsHash          = ServiceHelper.GetSequenceHashCode <SimpleWaypoint>(Waypoints);
                    optimizationOptionHash = optionHash;
                }
            }

            var requestUrl = GetRequestUrl();

            int startIdx = 0;
            int endIdx   = 0;

            if (Waypoints.Count <= batchSize)
            {
                if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
                {
                    var requestBody = GetTruckPostRequestBody(startIdx, out endIdx);

                    response = await ServiceHelper.MakeAsyncPostRequest(requestUrl, requestBody, remainingTimeCallback);
                }
                else
                {
                    remainingTimeCallback?.Invoke(1);

                    using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(requestUrl)))
                    {
                        response = ServiceHelper.DeserializeStream <Response>(responseStream);
                    }
                }
            }
            else
            {
                //There is more waypoints than the batchSize value (default 25), break it up into multiple requests. Only allow a single route in the response and no tolerances.
                if (RouteOptions != null)
                {
                    if (RouteOptions.MaxSolutions > 1)
                    {
                        RouteOptions.MaxSolutions = 1;
                    }

                    RouteOptions.Tolerances = null;
                }

                if (Waypoints == null)
                {
                    throw new Exception("Waypoints not specified.");
                }
                else if (Waypoints.Count < 2)
                {
                    throw new Exception("Not enough Waypoints specified.");
                }
                else if (Waypoints[0].IsViaPoint || Waypoints[Waypoints.Count - 1].IsViaPoint)
                {
                    throw new Exception("Start and end waypoints must not be ViaWaypoints.");
                }

                var requestUrls   = new List <string>();
                var requestBodies = new List <string>();

                while (endIdx < Waypoints.Count - 1)
                {
                    if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
                    {
                        requestUrls.Add(requestUrl);
                        requestBodies.Add(GetTruckPostRequestBody(startIdx, out endIdx));
                    }
                    else
                    {
                        requestUrls.Add(GetRequestUrl(startIdx, out endIdx));
                        requestBodies.Add(null);
                    }

                    startIdx = endIdx - 1;
                }

                if (remainingTimeCallback != null)
                {
                    int batchProcessingTime = (int)Math.Ceiling((double)requestUrls.Count / (double)ServiceManager.QpsLimit);

                    if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
                    {
                        //Use an average of 4 seconds per batch for processing truck routes as multiplier for the processing time.
                        //Other routes typically take less than a second and as such 1 second is used for those but isn't needed as a multiplier.
                        batchProcessingTime *= 4;
                    }

                    remainingTimeCallback(batchProcessingTime);
                }

                var routes     = new Route[requestUrls.Count];
                var routeTasks = new List <Task>();

                for (var i = 0; i < routes.Length; i++)
                {
                    routeTasks.Add(CalculateRoute(requestUrls[i], requestBodies[i], i, routes));
                }

                if (routeTasks.Count > 0)
                {
                    await ServiceHelper.WhenAllTaskLimiter(routeTasks);
                }

                try
                {
                    response = new Response()
                    {
                        StatusCode        = 200,
                        StatusDescription = "OK",
                        ResourceSets      = new ResourceSet[]
                        {
                            new ResourceSet()
                            {
                                Resources = new Resource[]
                                {
                                    await MergeRoutes(routes)
                                }
                            }
                        }
                    };
                }
                catch (Exception ex)
                {
                    return(new Response()
                    {
                        StatusCode = 500,
                        StatusDescription = "Error",
                        ErrorDetails = new string[]
                        {
                            ex.Message
                        }
                    });
                }
            }

            return(response);
        }
        /// <summary>
        /// Executes the request.
        /// </summary>
        /// <param name="remainingTimeCallback">A callback function in which the estimated remaining time in seconds is sent.</param>
        /// <returns>A response containing the requested data.</returns>
        public override async Task <Response> Execute(Action <int> remainingTimeCallback)
        {
            var requestUrl = GetRequestUrl();

            return(await ServiceHelper.MakeAsyncGetRequest(requestUrl, remainingTimeCallback).ConfigureAwait(false));
        }