Example #1
0
        public async Task <Route> UpdateRouteAsync(Route route, string userId = null)
        {
            using (var db = new SubrouteContext())
            {
                // Do not allow adding a new entry. Entry must already exist.
                if (route.Id == 0)
                {
                    throw new NotFoundException("Route cannot be updated because it hasn't yet been created.");
                }

                // Ensure route belongs to user.
                if (userId != null && route.UserId != userId)
                {
                    throw new NotFoundException("Route does not belong to specified user, and cannot be modified.");
                }

                db.Routes.Attach(route);
                db.Entry(route).State = EntityState.Modified;

                route.UpdatedOn = DateTimeOffset.Now;
                route.UpdatedBy = Thread.CurrentPrincipal.GetUserId();

                await db.SaveChangesAsync();

                return(route);
            }
        }
        /// <summary>
        /// Update an existing route package record using the specified <see cref="RoutePackage"/> instance.
        /// </summary>
        /// <param name="package">Instance of <see cref="RoutePackage"/> used to update database record.</param>
        /// <returns>The updated <see cref="RoutePackage"/> record.</returns>
        public async Task <RoutePackage> UpdateRoutePackageAsync(RoutePackage package)
        {
            using (var db = new SubrouteContext())
            {
                // Try to get the user ID for auditing purposes.
                var userId = Thread.CurrentPrincipal.GetUserId();

                var existingPackage = await db.RoutePackages.FirstOrDefaultAsync(rs => rs.Id == package.Id);

                if (existingPackage == null)
                {
                    throw new NotFoundException($"No route package exists with ID '{package.Id}'.");
                }

                existingPackage.Version       = package.Version;
                existingPackage.UserSpecified = package.UserSpecified;
                existingPackage.UpdatedOn     = DateTimeOffset.Now;
                existingPackage.UpdatedBy     = userId;

                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(existingPackage).State = EntityState.Detached;

                return(existingPackage);
            }
        }
        /// <summary>
        /// Update an existing route setting record using the specified <see cref="RouteSetting"/> instance.
        /// </summary>
        /// <param name="setting">Instance of <see cref="RouteSetting"/> used to update database record.</param>
        /// <returns>The updated <see cref="RouteSetting"/> that includes the generated route setting ID.</returns>
        public async Task <RouteSetting> UpdateRouteSettingAsync(RouteSetting setting)
        {
            using (var db = new SubrouteContext())
            {
                // Try to get the user ID for auditing purposes.
                var userId = Thread.CurrentPrincipal.GetUserId();

                var existingSetting = await db.RouteSettings.FirstOrDefaultAsync(rs => rs.Name == setting.Name);

                if (existingSetting == null)
                {
                    throw new NotFoundException($"No route setting exists with name '{setting.Name}'.");
                }

                existingSetting.Value     = setting.Value;
                existingSetting.UpdatedOn = DateTimeOffset.Now;
                existingSetting.UpdatedBy = userId;

                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(existingSetting).State = EntityState.Detached;

                return(existingSetting);
            }
        }
Example #4
0
        public async Task <Route> GetRouteByIdentifierAsync(RouteIdentifier identifier, string userId = null)
        {
            using (var db = new SubrouteContext())
            {
                var query = db.Routes
                            .Include(r => r.RouteSettings)
                            .Include(r => r.RoutePackages)
                            .AsNoTracking()
                            .AsQueryable();

                if (userId != null)
                {
                    query = query.Where(q => q.UserId == userId);
                }

                // We'll load the route from an untracked collection since we don't want outside changes causing unwanted updates.
                var route = identifier.Type == RouteIdentifierType.Id ?
                            await query.AsNoTracking().FirstOrDefaultAsync(r => r.Id == identifier.Id) :
                            await query.AsNoTracking().FirstOrDefaultAsync(r => r.Uri == identifier.Uri);

                if (route == null)
                {
                    throw new NotFoundException($"No route with identifier '{identifier}' was found.");
                }

                return(route);
            }
        }
        public async Task <Request> UpdateRequestAsync(Request request)
        {
            using (var db = new SubrouteContext())
            {
                // Do not allow adding a new entry. Entry must already exist.
                if (request.Id == 0)
                {
                    throw new NotFoundException($"Request cannot be updated because it hasn't yet been created.");
                }

                // Calculate and store the response length if a response payload is available.
                if (request.ResponsePayload != null)
                {
                    request.ResponseLength = request.ResponsePayload.LongLength;
                }

                db.Requests.Attach(request);
                db.Entry(request).State = EntityState.Modified;

                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(request).State = EntityState.Detached;

                return(request);
            }
        }
Example #6
0
        public async Task <Route> CreateRouteAsync(Route route, string userId = null)
        {
            using (var db = new SubrouteContext())
            {
                // Ensure we are only creating a route for specified user.
                if (route.UserId != userId)
                {
                    throw new NotFoundException("Route does not belong to specified user, and cannot be created.");
                }

                // Set auto property values.
                route.CreatedOn = DateTimeOffset.Now;
                route.CreatedBy = "SYSTEM"; // Todo: Use Authenticated Username.
                route.UpdatedOn = route.CreatedOn;
                route.UpdatedBy = "SYSTEM"; // Todo: Use Authenticated Username.

                db.Routes.Add(route);
                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(route).State = EntityState.Detached;

                return(route);
            }
        }
Example #7
0
        public PagedCollection <Route> GetAllPublicRoutes(int skip, int take, string search)
        {
            using (var db = new SubrouteContext())
            {
                var query = db.Routes
                            .Include(r => r.RouteSettings)
                            .Include(r => r.RoutePackages)
                            .AsNoTracking()
                            .AsQueryable();

                if (!string.IsNullOrEmpty(search))
                {
                    query = query
                            .Where(q => !q.IsPrivate && q.Title.Contains(search));
                }
                else
                {
                    query = query
                            .Where(q => !q.IsPrivate && q.Title != null);
                }

                var count = query.Count();

                query = query.Take(take)
                        .Skip(skip)
                        .OrderBy(x => x.StarredCount)
                        .ThenBy(x => x.ClonedCount)
                        .ThenBy(x => x.UpdatedOn);

                return(new PagedCollection <Route>()
                {
                    TotalCount = count, Results = query.ToArray(), Skip = skip, Take = take
                });
            }
        }
Example #8
0
        static void Main(string[] args)
        {
            // Wire tracing sub-system into console output.
            Trace.Listeners.Add(new ConsoleTraceListener());

            // Register all dependencies once during app setup. This will ensure dependency registration happens
            // well before the first request is received. Previously I was registering dependencies in the
            // ExecutionMethods class, but that instance doesn't get created until the first request.
            TraceUtility.TraceTime("Register Dependencies", () =>
            {
                var assembly = Assembly.GetExecutingAssembly();
                var builder  = Bootstrapper.GetContainerBuilder(assembly);

                Container = builder.Build();
            });

            // We'll also get an instance of the RequestRepository. Since the RequestRepository is thread-safe
            // we'll register a single instance of it here to reduce the amount of operations we perform during
            // the execution of an individual request.
            RequestRepository = Container.Resolve <IRequestRepository>();

            // Force the database to initialize Entity Framework metadata.
            // It turns out Entity Framework lazy-loads all its metadata
            // and this make the first request take many seconds to run.
            // The initialization performs a no-op query which warms EF up.
            TraceUtility.TraceTime("Initialize Entity Framework", () =>
            {
                // Assign a custom DatabaseInitializer to configure certain aspects of our database.
                Database.SetInitializer(new DatabaseInitializer());

                SubrouteContext.InitializeMetadata();
            });

            // Override the nuget package directory with one related to the current execution directory.
            Settings.NugetPackageDirectory = Path.Combine(Environment.CurrentDirectory, "packages-container");

            var jobHostConfig = new JobHostConfiguration
            {
                NameResolver = new ConfigNameResolver(),
                DashboardConnectionString = Settings.StorageConnectionString,
                StorageConnectionString   = Settings.StorageConnectionString
            };

            var serviceBusConfig = new ServiceBusConfiguration
            {
                ConnectionString = Settings.ServiceBusConnectionString,
                MessageOptions   = new OnMessageOptions
                {
                    MaxConcurrentCalls = Settings.ServiceBusMaxConcurrentExecutions
                }
            };

            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Tcp;

            jobHostConfig.UseServiceBus(serviceBusConfig);

            using (var jobHost = new JobHost(jobHostConfig))
                jobHost.RunAndBlock();
        }
Example #9
0
 public async Task <Route> GetRandomDefaultRouteAsync()
 {
     using (var db = new SubrouteContext())
         return(await db.Routes
                .AsNoTracking()
                .Where(r => r.IsDefault)
                .OrderBy(r => Guid.NewGuid())
                .FirstOrDefaultAsync());
 }
Example #10
0
 public static void Register()
 {
     // This method will perform a no-op query against the database and will force
     // Entity Framework to initialize its metadata, which is usually done on the
     // first database request. The initialization can take over 6 seconds to run
     // which means that if we don't pre-warm-up Entity Framework, the first user
     // will have to wait for this call.
     SubrouteContext.InitializeMetadata();
 }
        /// <summary>
        /// Delete the route setting record using the passed instance.
        /// </summary>
        /// <param name="setting">Instance of <see cref="RouteSetting"/> that represents the record to delete.</param>
        /// <returns>Returns a Task, essentially void when using async syntax.</returns>
        public async Task DeleteRouteSettingAsync(RouteSetting setting)
        {
            using (var db = new SubrouteContext())
            {
                // Mark route for deletion so the context knowns to delete it.
                db.Entry(setting).State = EntityState.Deleted;

                await db.SaveChangesAsync();
            }
        }
        /// <summary>
        /// Delete the route setting record with the specified identifier.
        /// </summary>
        /// <param name="identifier"><see cref="RouteIdentifier"/> for the requested route.</param>
        /// <param name="name">String that identifies the route setting record to delete.</param>
        /// <returns>Returns a Task, essentially void when using async syntax.</returns>
        public async Task DeleteRouteSettingAsync(RouteIdentifier identifier, string name)
        {
            using (var db = new SubrouteContext())
            {
                var route = await GetRouteSettingByNameAsync(identifier, name);

                // Mark route for deletion so the context knowns to delete it.
                db.Entry(route).State = EntityState.Deleted;

                await db.SaveChangesAsync();
            }
        }
        public Route[] GetAllRoutes(string userId = null)
        {
            // We'll load the route from an untracked collection since we don't want outside changes causing unwanted updates.
            using (var db = new SubrouteContext())
            {
                var query = db.Routes.Include(r => r.RouteSettings).AsNoTracking().AsQueryable();

                if (userId != null)
                {
                    query = query.Where(q => q.UserId == userId);
                }

                return(query.ToArray());
            }
        }
        public async Task <long> GetRequestExecutionCountByRouteIdentifierAsync(RouteIdentifier identifier)
        {
            using (var db = new SubrouteContext())
            {
                // Build base query to return all requests.
                var query = db.Requests.AsNoTracking().AsQueryable();

                // Ensure we are only returning requests for the specified route.
                query = identifier.Type == RouteIdentifierType.Id
                    ? query.Where(r => r.RouteId == identifier.Id)
                    : query.Where(r => r.Route.Uri == identifier.Uri);

                // Execute query and get total count.
                return(await query.LongCountAsync());
            }
        }
Example #15
0
        public async Task DeleteRouteByIdentifierAsync(RouteIdentifier identifier, string userId = null)
        {
            using (var db = new SubrouteContext())
            {
                var route = await GetRouteByIdentifierAsync(identifier);

                // Ensure route belongs to specified user.
                if (userId != null && route.UserId != userId)
                {
                    throw new NotFoundException("Route does not belong to specified user, and cannot be deleted.");
                }

                // Mark route for deletion so the context knowns to delete it.
                db.Entry(route).State = EntityState.Deleted;

                await db.SaveChangesAsync();
            }
        }
        /// <summary>
        /// Load a single route setting by its name.
        /// </summary>
        /// <param name="identifier"><see cref="RouteIdentifier"/> for the requested route.</param>
        /// <param name="name">String representing the specified route setting name.</param>
        /// <returns>Returns a single <see cref="RouteSetting"/> with the matching route setting identifier.</returns>
        public async Task <RouteSetting> GetRouteSettingByNameAsync(RouteIdentifier identifier, string name)
        {
            using (var db = new SubrouteContext())
            {
                var query = db.RouteSettings
                            .AsNoTracking()
                            .Where(rs => rs.Name == name);

                // Ensure we are only returning settings for the specified route
                // Use the correct identifier type to query the database.
                query = identifier.Type == RouteIdentifierType.Id
                    ? query.Where(r => r.RouteId == identifier.Id)
                    : query.Where(r => r.Route.Uri == identifier.Uri);

                // Return the first match.
                return(await query.FirstOrDefaultAsync());
            }
        }
        public async Task <Request> GetRequestByIdAsync(int id)
        {
            using (var db = new SubrouteContext())
            {
                var request = await db.Requests
                              .Include(r => r.Route)
                              .Include(r => r.Route.RouteSettings)
                              .AsNoTracking()
                              .FirstOrDefaultAsync(r => r.Id == id);

                if (request == null)
                {
                    throw new NotFoundException($"No request with ID '{id}' was found.");
                }

                return(request);
            }
        }
        public async Task <PagedCollection <Models.Requests.Request> > GetRequestsByDateRangeAsync(RouteIdentifier id, int skip, int take, DateTimeOffset?from, DateTimeOffset?to)
        {
            using (var db = new SubrouteContext())
            {
                // Limit the request results by date range if one was provided.
                var query = db.Requests.AsNoTracking()
                            .Where(r => from.HasValue && r.OccurredOn >= from)
                            .Where(r => to.HasValue && r.OccurredOn <= to);

                // Ensure we are only returning requests for the specified route.
                query = id.Type == RouteIdentifierType.Id
                    ? query.Where(r => r.RouteId == id.Id)
                    : query.Where(r => r.Route.Uri == id.Uri);

                // Apply an order to the query to reverse chronological.
                query = query.OrderByDescending(r => r.OccurredOn);

                // Project and page query results into our wire format and materialize.
                // We project the results so we don't pull back the entire payload contents.
                var pagedResults = await query
                                   .Skip(skip)
                                   .Take(take)
                                   .Select(Models.Requests.Request.Map)
                                   .ToArrayAsync();

                // Get total count and final projected results.
                var total = await query.CountAsync();

                // Iterate the results and deserialize the headers for each request.
                foreach (var request in pagedResults)
                {
                    request.RequestHeaders  = HeaderUtility.DeserializeHeaders(request.SerializedRequestHeaders);
                    request.ResponseHeaders = HeaderUtility.DeserializeHeaders(request.SerializedResponseHeaders);
                }

                return(new PagedCollection <Models.Requests.Request>
                {
                    Skip = skip,
                    Take = take,
                    TotalCount = total,
                    Results = pagedResults
                });
            }
        }
        /// <summary>
        /// Load all the route settings for the specified <see cref="RouteIdentifier"/>.
        /// </summary>
        /// <param name="identifier"><see cref="RouteIdentifier"/> for the requested route.</param>
        /// <returns>Returns an array of <see cref="RouteSetting"/> objects for the specified route.</returns>
        public async Task <RouteSetting[]> GetRouteSettingsAsync(RouteIdentifier identifier)
        {
            using (var db = new SubrouteContext())
            {
                // Get an untracked base queryable.
                var query = db.RouteSettings
                            .AsNoTracking()
                            .AsQueryable();

                // Ensure we are only returning settings for the specified route
                // Use the correct identifier type to query the database.
                query = identifier.Type == RouteIdentifierType.Id
                    ? query.Where(r => r.RouteId == identifier.Id)
                    : query.Where(r => r.Route.Uri == identifier.Uri);

                // Materialize the results into memory.
                return(await query.ToArrayAsync());
            }
        }
        public async Task <Request> CreateRequestAsync(Request request)
        {
            using (var db = new SubrouteContext())
            {
                request.OccurredOn = DateTimeOffset.UtcNow;

                // Calculate and store the request length if a request payload is available.
                if (request.RequestPayload != null)
                {
                    request.RequestLength = request.RequestPayload.LongLength;
                }

                db.Requests.Add(request);
                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(request).State = EntityState.Detached;

                return(request);
            }
        }
        /// <summary>
        /// Uses the specified <see cref="RouteSetting"/> instance to create a new route setting record in the database.
        /// </summary>
        /// <param name="setting">Instance of <see cref="RouteSetting"/> used to create the database record.</param>
        /// <returns>Returns instance of <see cref="RouteSetting"/>.</returns>
        public async Task <RouteSetting> CreateRouteSettingAsync(RouteSetting setting)
        {
            using (var db = new SubrouteContext())
            {
                // Try to get the user ID for auditing purposes.
                var userId = Thread.CurrentPrincipal.GetUserId();

                // Set auto property values.
                setting.CreatedOn = DateTimeOffset.Now;
                setting.CreatedBy = userId;
                setting.UpdatedOn = setting.CreatedOn;
                setting.UpdatedBy = userId;

                db.RouteSettings.Add(setting);
                await db.SaveChangesAsync();

                // Detach entry so its changes won't be tracked.
                db.Entry(setting).State = EntityState.Detached;

                return(setting);
            }
        }
        /// <summary>
        /// Load all the route packages for the specified <see cref="RouteIdentifier"/>.
        /// </summary>
        /// <param name="identifier"><see cref="RouteIdentifier"/> for the requested route.</param>
        /// <param name="specified">Indicates if the results should only include user specified packages.</param>
        /// <returns>Returns an array of <see cref="RoutePackage"/> objects for the specified route.</returns>
        public async Task <RoutePackage[]> GetRoutePackagesAsync(RouteIdentifier identifier, bool specified = false)
        {
            using (var db = new SubrouteContext())
            {
                // Get an untracked base queryable.
                var query = db.RoutePackages
                            .AsNoTracking()
                            .AsQueryable();

                // Ensure we are only returning packages for the specified route
                // Use the correct identifier type to query the database.
                query = identifier.Type == RouteIdentifierType.Id
                    ? query.Where(r => r.RouteId == identifier.Id)
                    : query.Where(r => r.Route.Uri == identifier.Uri);

                // Determine if we are including all results or just user specified.
                query = specified ? query.Where(q => q.UserSpecified) : query;

                // Materialize the results into memory.
                return(await query.ToArrayAsync());
            }
        }