/// <summary> /// Creates the multi modal nancy module. /// </summary> public MultimodalModule() { JsonSettings.MaxJsonLength = Int32.MaxValue; Get["{instance}/multimodal"] = _ => { this.EnableCors(); // get request id. ulong requestId = MultimodalModule.GetRequestId(); // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } // check transit support. if (!ApiBootstrapper.Get(instance).TransitSupport) { // not found, this is not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } var startTicks = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal request #{1} from {0}.", this.Request.UserHostAddress, requestId)); try { // bind the query if any. var query = this.Bind <RoutingQuery>(); // parse location. if (string.IsNullOrWhiteSpace(query.loc)) { // no loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("loc parameter not found or request invalid.")); } var locs = query.loc.Split(','); if (locs.Length < 2) { // less than two loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("only one loc parameter found or request invalid.")); } var coordinates = new GeoCoordinate[locs.Length / 2]; for (int idx = 0; idx < coordinates.Length; idx++) { double lat, lon; if (double.TryParse(locs[idx * 2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lat) && double.TryParse(locs[idx * 2 + 1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lon)) { // parsing was successful. coordinates[idx] = new GeoCoordinate(lat, lon); } else { // invalid formatting. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("location coordinates are invalid.")); } } // get vehicle. string vehicleName = "car"; // assume car is the default. if (!string.IsNullOrWhiteSpace(query.vehicle)) { // a vehicle was defined. vehicleName = query.vehicle; } var vehicles = new List <Vehicle>(); var vehicleNames = vehicleName.Split('|'); for (int idx = 0; idx < vehicleNames.Length; idx++) { var vehicle = Vehicle.GetByUniqueName(vehicleNames[idx]); if (vehicle == null) { // vehicle not found or not registered. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel(string.Format("vehicle with name '{0}' not found.", vehicleName))); } vehicles.Add(vehicle); } // get operators. HashSet <string> operators = null; if (query.operators != null) { // a vehicle was defined. operators = new HashSet <string>(); var operatorNames = query.operators.Split('|'); for (int idx = 0; idx < operatorNames.Length; idx++) { operators.Add(operatorNames[idx]); } } bool instructions = false; if (!string.IsNullOrWhiteSpace(query.instructions)) { // there is an instruction flag. instructions = query.instructions == "true"; } bool complete = false; if (!string.IsNullOrWhiteSpace(query.complete)) { // there is a complete flag. complete = query.complete == "true"; } bool fullFormat = false; if (!string.IsNullOrWhiteSpace(query.format)) { // there is a format field. fullFormat = query.format == "osmsharp"; } bool departure = false; if (!string.IsNullOrWhiteSpace(query.departure)) { // there is a format field. departure = query.departure == "true"; } // check conflicting parameters. if (!complete && instructions) { // user wants an incomplete route but instructions, this is impossible. complete = true; } // parse time. if (string.IsNullOrWhiteSpace(query.time)) { // there is a format field. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("No valid time parameter found.")); } DateTime dt; string pattern = "yyyyMMddHHmm"; if (!DateTime.TryParseExact(query.time, pattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt)) { // could not parse date. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel( string.Format("No valid time parameter found, could not parse date: {0}. Expected to be in format yyyyMMddHHmm."))); } var aggregationType = RouteAggregationType.All; if (!string.IsNullOrWhiteSpace(query.aggregate)) { // there is an aggregation field. switch (query.aggregate.ToLowerInvariant()) { case "instructions": aggregationType = RouteAggregationType.Instructions; break; case "modal": aggregationType = RouteAggregationType.Modal; break; } } bool otm = false; if (!string.IsNullOrWhiteSpace(query.type)) { // custom type of routing request. if (query.type == "otm") { otm = true; } } if (!otm) { // calculate route. var route = ApiBootstrapper.Get(instance).GetTransitRoute(dt, vehicles, coordinates, operators, complete); var endTicks = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("MultimodalModal", OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal request #{1} from {0} finished in {2}ms.", this.Request.UserHostAddress, requestId, (new TimeSpan(endTicks - startTicks)).TotalMilliseconds.ToInvariantString())); if (route == null) { // route could not be calculated. return(null); } if (route != null && instructions) { // also calculate instructions. var instruction = ApiBootstrapper.Get(instance).GetInstructions(route); if (fullFormat) { return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(new CompleteRoute() { Route = route, Instructions = instruction })); } else { // return a GeoJSON object. var featureCollection = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } if (fullFormat) { // return a complete route but no instructions. return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(route)); } else { // return a GeoJSON object. var featureCollection = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } else { // calculate route. var routes = ApiBootstrapper.Get(instance).GetTransitOneToMany(dt, vehicles, coordinates, operators, complete); if (routes == null) { // route could not be calculated. return(null); } if (routes != null && instructions) { // also calculate instructions. if (fullFormat) { throw new NotSupportedException(); } else { // return a GeoJSON object. var featureCollection = new FeatureCollection(); foreach (var route in routes) { if (route != null) { var routeFeatures = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); if (routeFeatures != null) { foreach (var feature in routeFeatures) { featureCollection.Add(feature); } } } } return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } if (fullFormat) { return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(routes)); } else { // return a GeoJSON object. var featureCollection = new FeatureCollection(); foreach (var route in routes) { if (route != null) { var routeFeatures = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); if (routeFeatures != null) { foreach (var feature in routeFeatures) { featureCollection.Add(feature); } } } } return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } } catch (Exception) { // an unhandled exception! OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal request #{1} from {0} failed.", this.Request.UserHostAddress, requestId)); return(Negotiate.WithStatusCode(HttpStatusCode.InternalServerError)); } }; Options["{instance}/multimodal/range"] = _ => { this.EnableCors(); // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } return(Negotiate.WithStatusCode(HttpStatusCode.OK)); }; Get["{instance}/multimodal/range"] = _ => { this.EnableCors(); // get request id. ulong requestId = MultimodalModule.GetRequestId(); // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } long requestStart = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal range request #{1} from {0}.", this.Request.UserHostAddress, requestId)); try { // bind the query if any. var query = this.Bind <RangeQuery>(); // parse location. if (string.IsNullOrWhiteSpace(query.loc)) { // no loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("loc parameter not found or request invalid.")); } var locs = query.loc.Split(','); if (locs.Length < 2) { // less than two loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("only one loc parameter found or request invalid.")); } var coordinates = new GeoCoordinate[locs.Length / 2]; for (int idx = 0; idx < coordinates.Length; idx++) { double lat, lon; if (double.TryParse(locs[idx * 2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lat) && double.TryParse(locs[idx * 2 + 1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lon)) { // parsing was successful. coordinates[idx] = new GeoCoordinate(lat, lon); } else { // invalid formatting. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("location coordinates are invalid.")); } } // get vehicle. string vehicleName = "car"; // assume car is the default. if (!string.IsNullOrWhiteSpace(query.vehicle)) { // a vehicle was defined. vehicleName = query.vehicle; } var vehicles = new List <Vehicle>(); var vehicleNames = vehicleName.Split('|'); for (int idx = 0; idx < vehicleNames.Length; idx++) { var vehicle = Vehicle.GetByUniqueName(vehicleNames[idx]); if (vehicle == null) { // vehicle not found or not registered. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel(string.Format("vehicle with name '{0}' not found.", vehicleName))); } vehicles.Add(vehicle); } // parse time. if (string.IsNullOrWhiteSpace(query.time)) { // there is a format field. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("No valid time parameter found.")); } DateTime dt; string pattern = "yyyyMMddHHmm"; if (!DateTime.TryParseExact(query.time, pattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt)) { // could not parse date. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel( string.Format("No valid time parameter found, could not parse date: {0}. Expected to be in format yyyyMMddHHmm."))); } // calculate route. int max; if (!int.TryParse(query.max, out max)) {// could not parse date. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel( string.Format("No valid max time parameter found, could not parse: {0}.", query.max))); } int zoom; if (!int.TryParse(query.zoom, out zoom)) {// could not parse date. zoom = 16; } var range = ApiBootstrapper.Get(instance).GetWithinRange(dt, vehicles, coordinates[0], max, zoom); long afterRequest = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal range request #{1} from {0} finished after {2}ms.", this.Request.UserHostAddress, requestId, (new TimeSpan(afterRequest - requestStart)).TotalMilliseconds)); // output all vertex and times. var vertexAndTimes = new List <VertexAndTime>(); foreach (var rangeEntry in range) { double time = max - rangeEntry.Item3; if (time > 0) { time = (int)((time / max) * 100) + 25; vertexAndTimes.Add(new VertexAndTime() { lat = rangeEntry.Item1.Latitude, lon = rangeEntry.Item1.Longitude, value = time, id = rangeEntry.Item2 }); } } return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(new OsmSharp.Service.Routing.Multimodal.Domain.Queries.Range() { max = 125, data = vertexAndTimes.ToArray() })); } catch (Exception) { // an unhandled exception! OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal range request #{1} from {0} failed.", this.Request.UserHostAddress, requestId)); return(Negotiate.WithStatusCode(HttpStatusCode.InternalServerError)); } }; Get["{instance}/alongjustone"] = _ => { this.EnableCors(); // get request id. var requestId = MultimodalModule.GetRequestId(); // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Along just one request #{1} from {0}.", this.Request.UserHostAddress, requestId)); try { // bind the query if any. var query = this.Bind <RoutingQuery>(); // parse location. if (string.IsNullOrWhiteSpace(query.loc)) { // no loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("loc parameter not found or request invalid.")); } var locs = query.loc.Split(','); if (locs.Length < 6) { // less than two loc parameters. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("only two loc parameter found or request invalid.")); } var coordinates = new GeoCoordinate[locs.Length / 2]; for (int idx = 0; idx < coordinates.Length; idx++) { double lat, lon; if (double.TryParse(locs[idx * 2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lat) && double.TryParse(locs[idx * 2 + 1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out lon)) { // parsing was successful. coordinates[idx] = new GeoCoordinate(lat, lon); } else { // invalid formatting. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("location coordinates are invalid.")); } } // get vehicle. string vehicleName = "car"; // assume car is the default. if (!string.IsNullOrWhiteSpace(query.vehicle)) { // a vehicle was defined. vehicleName = query.vehicle; } var vehicles = new List <Vehicle>(); var vehicleNames = vehicleName.Split('|'); for (int idx = 0; idx < vehicleNames.Length; idx++) { var vehicle = Vehicle.GetByUniqueName(vehicleNames[idx]); if (vehicle == null) { // vehicle not found or not registered. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel(string.Format("vehicle with name '{0}' not found.", vehicleName))); } vehicles.Add(vehicle); } if (vehicles.Count > 2) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("More than two vehicle profiles found.")); } bool instructions = false; if (!string.IsNullOrWhiteSpace(query.instructions)) { // there is an instruction flag. instructions = query.instructions == "true"; } bool complete = false; if (!string.IsNullOrWhiteSpace(query.complete)) { // there is a complete flag. complete = query.complete == "true"; } bool fullFormat = false; if (!string.IsNullOrWhiteSpace(query.format)) { // there is a format field. fullFormat = query.format == "osmsharp"; } bool departure = false; if (!string.IsNullOrWhiteSpace(query.departure)) { // there is a format field. departure = query.departure == "true"; } // check conflicting parameters. if (!complete && instructions) { // user wants an incomplete route but instructions, this is impossible. complete = true; } var aggregationType = RouteAggregationType.All; if (!string.IsNullOrWhiteSpace(query.aggregate)) { // there is an aggregation field. switch (query.aggregate.ToLowerInvariant()) { case "instructions": aggregationType = RouteAggregationType.Instructions; break; case "modal": aggregationType = RouteAggregationType.Modal; break; } } // calculate route. var route = ApiBootstrapper.Get(instance).GetRouteAlongOne(vehicles, coordinates); OsmSharp.Logging.Log.TraceEvent("MultimodalModal", OsmSharp.Logging.TraceEventType.Information, string.Format("Along one request #{1} from {0} finished.", this.Request.UserHostAddress, requestId)); if (route == null) { // route could not be calculated. return(null); } if (route != null && instructions) { // also calculate instructions. if (fullFormat) { var instruction = ApiBootstrapper.Get(instance).GetInstructions(route); return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(new CompleteRoute() { Route = route, Instructions = instruction })); } else {// return a GeoJSON object. var featureCollection = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } if (fullFormat) { // return a complete route but no instructions. return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(route)); } else { // return a GeoJSON object. var featureCollection = ApiBootstrapper.Get(instance).GetFeatures(route, aggregationType); return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(featureCollection)); } } catch (Exception) { // an unhandled exception! OsmSharp.Logging.Log.TraceEvent(string.Format("MultimodalModal.{0}", instance), OsmSharp.Logging.TraceEventType.Information, string.Format("Multimodal request #{1} from {0} failed.", this.Request.UserHostAddress, requestId)); return(Negotiate.WithStatusCode(HttpStatusCode.InternalServerError)); } }; Get["{instance}/multimodal/status"] = _ => { // get instance and check if active. string instance = _.instance; if (ApiBootstrapper.IsActive(instance)) { return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(new Status() { Available = true, Info = "Initialized." })); } return(Negotiate.WithStatusCode(HttpStatusCode.OK).WithModel(new Status() { Available = false, Info = "Not initialized." })); }; Get["{instance}/multimodal/network"] = _ => { // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } try { this.EnableCors(); // get request id. ulong requestId = MultimodalModule.GetRequestId(); // bind the query if any. var query = this.Bind <BoxQuery>(); double left, right, top, bottom; if (string.IsNullOrWhiteSpace(query.left) || !double.TryParse(query.left, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out left)) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("box coordinates are invalid.")); } if (string.IsNullOrWhiteSpace(query.right) || !double.TryParse(query.right, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out right)) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("box coordinates are invalid.")); } if (string.IsNullOrWhiteSpace(query.top) || !double.TryParse(query.top, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out top)) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("box coordinates are invalid.")); } if (string.IsNullOrWhiteSpace(query.bottom) || !double.TryParse(query.bottom, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out bottom)) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel("box coordinates are invalid.")); } var features = ApiBootstrapper.Get(instance).GetNeworkFeatures(new GeoCoordinateBox(new GeoCoordinate(top, left), new GeoCoordinate(bottom, right))); return(OsmSharp.Geo.Streams.GeoJson.GeoJsonConverter.ToGeoJson(features)); } catch (Exception) { // an unhandled exception! return(Negotiate.WithStatusCode(HttpStatusCode.InternalServerError)); } }; }
/// <summary> /// Called on PUT '/{instance}/matrix'. /// </summary> /// <param name="_"></param> /// <returns></returns> private dynamic PutInstanceMatrix(dynamic _) { this.EnableCors(); // get instance and check if active. string instance = _.instance; if (!ApiBootstrapper.IsActive(instance)) { // oeps, instance not active! return(Negotiate.WithStatusCode(HttpStatusCode.NotFound)); } var api = ApiBootstrapper.Get(instance); // bind the request if any. var request = this.Bind <Domain.Request>(); // check request. if (request == null) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable)); } if (request.locations == null && request.sources == null) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable)); } if (request.locations == null && (request.sources == null || request.targets == null)) { return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable)); } if (request.output != null) { // check output contents. foreach (var output in request.output) { if (!(output.Equals(Domain.Request.DistanceOutputOption) || output.Equals(Domain.Request.TimesOutputOption) || output.Equals(Domain.Request.WeightsOutputOption))) { // this output-option does not equal one of the options. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel( string.Format("Invalid output option: {0}", output))); } } } // set defaults if needed. if (request.profile == null) { // set default profile. request.profile = new Domain.Profile() { vehicle = "car" }; } if (request.output == null || request.output.Length == 0) { // set default output. request.output = new string[] { "times" }; } // build sources and targets arrays. GeoCoordinate[] sources; GeoCoordinate[] targets; if (request.locations != null) { // NxN matrix, source and targets are identical. sources = new GeoCoordinate[request.locations.Length]; for (var i = 0; i < request.locations.Length; i++) { sources[i] = new GeoCoordinate(request.locations[i][1], request.locations[i][0]); } targets = sources; } else { // NxM matrix, sources and targets are different. sources = new GeoCoordinate[request.sources.Length]; for (var i = 0; i < request.sources.Length; i++) { sources[i] = new GeoCoordinate(request.sources[i][1], request.sources[i][0]); } targets = new GeoCoordinate[request.targets.Length]; for (var i = 0; i < request.targets.Length; i++) { targets[i] = new GeoCoordinate(request.targets[i][1], request.targets[i][0]); } } // build profile. var vehicle = OsmSharp.Routing.Vehicles.Vehicle.GetByUniqueName(request.profile.vehicle); if (!ApiBootstrapper.Get(instance).SupportsVehicle(vehicle)) { // vehicle is not supported. return(Negotiate.WithStatusCode(HttpStatusCode.NotAcceptable).WithModel( string.Format("Vehicle with name '{0}' cannot be use with this routing instance.", vehicle.UniqueName))); } // calculate matrices. Tuple <string, int, string>[] errors; var matrices = api.GetMatrix(vehicle, sources, targets, request.output, out errors); // remove target errors and adapt source errors when only a locations array was in the request. if (request.locations != null) { var errorsList = new List <Tuple <string, int, string> >(); foreach (var error in errors) { if (error.Item1 == "source") { errorsList.Add(new Tuple <string, int, string>(null, error.Item2, error.Item3)); } } errors = errorsList.ToArray(); } // build response. var response = new Matrix.Domain.Response(); foreach (var matrix in matrices) { if (matrix.Item1 == Matrix.Domain.Request.DistanceOutputOption) { response.distances = matrix.Item2; } else if (matrix.Item1 == Matrix.Domain.Request.TimesOutputOption) { response.times = matrix.Item2; } else if (matrix.Item1 == Matrix.Domain.Request.WeightsOutputOption) { response.weights = matrix.Item2; } } if (errors != null && errors.Length > 0) { response.errors = new Domain.Error[errors.Length]; for (var i = 0; i < errors.Length; i++) { response.errors[i] = new Domain.Error() { type = errors[i].Item1, index = errors[i].Item2, message = errors[i].Item3 }; } } return(response); }