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); } }
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); } }
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); } }
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 }); } }
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(); }
public async Task <Route> GetRandomDefaultRouteAsync() { using (var db = new SubrouteContext()) return(await db.Routes .AsNoTracking() .Where(r => r.IsDefault) .OrderBy(r => Guid.NewGuid()) .FirstOrDefaultAsync()); }
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()); } }
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()); } }