public async Task Invoke(HttpContext context, Mp3EhbContext dbContext) { var path = context.Request.Path.ToUriComponent(); var transformResult = await this.TransformPathAsync(path, dbContext, context.Items); //If is an category, change the request path to be "Content/Index/{path}" so it is handled by the content controller, index action switch (transformResult.Action) { case TransformAction.Substitute: //Let the next middleware (MVC routing) handle the request //In case the path was updated, the MVC routing will see the updated path context.Request.Path = transformResult.NewPath; break; case TransformAction.Redirect: context.Response.StatusCode = 302; context.Response.Headers.Add(LOCATION_HEADER_NAME, transformResult.NewPath); return; case TransformAction.None: break; default: throw new ArgumentOutOfRangeException(); } await this._next.Invoke(context); }
/// <summary> /// Converts hierarchical category structure to mvc route /// </summary> /// <param name="path">The route being processed</param> /// <param name="dbContext">The main app storage: <see cref="Mp3EhbContext"/></param> /// <returns></returns> private async Task <TransformResult> TransformPathAsync(string path, Mp3EhbContext dbContext, IDictionary <object, object> contextItems) { //The middleware will try to find a Category and a content in the database that matches the current path var transformResult = new TransformResult(); var trimmedPath = path.TrimTail(tail: DEFAULT_EXTENSION); var names = trimmedPath.Split(new[] { FOLDER_SEPARATOR_CHAR }, StringSplitOptions.RemoveEmptyEntries); if (names.Length == 0) { return(transformResult); //None } string bestMatchingPath = null; string correctPath = null; var contentId = default(int); var bestMatchingCategoryId = default(int); var categores = dbContext.Categories.AsNoTracking(); foreach (var name in names) { var categoryId = default(int); var currentPath = name; if (bestMatchingPath == null) //first entry { if (MenuDictionary.ContainsKey(name)) { categoryId = MenuDictionary[name]; } } else { currentPath = bestMatchingPath + "/" + name; } //let check if name is in idNumber-aliasString format var match = Regex.Match(name, @"^(\d+)-(.*)$"); Expression <Func <Category, bool> > categoryPredicate = c => c.Path == currentPath; int id = 0; if (match.Success && match.Groups.Count > 2) { id = int.Parse(match.Groups[1].Value); //name = match.Groups[2].Value; categoryPredicate = c => c.Id == id; // && c.Alias == name; } if (categoryId == default(int)) { //The midleware will try to find a Category in the database that matches the current Path categoryId = await categores .Where(categoryPredicate) .Select(c => c.Id) .FirstOrDefaultAsync(); } if (categoryId == default(int)) //name may be content name { Expression <Func <Content, bool> > contentPredicate = c => c.Alias.Contains(name); if (id != 0) { contentPredicate = c => c.Id == id; // || c.Alias.Contains(name); } //The midleware will try to find a content in the database that matches the current name var contents = dbContext.Contents.AsNoTracking(); var content = await contents .Where(contentPredicate) .Select(c => new { c.Id, c.CatId, c.Alias }) .FirstOrDefaultAsync(); if (content == null) { break; } contentId = content.Id; correctPath = await categores.GetCategoryPath(content.CatId) + "/" + content.Alias; break; } bestMatchingPath = currentPath; bestMatchingCategoryId = categoryId; } if (contentId != default(int)) { contextItems[CATEGORY_ID] = contentId; if (correctPath == path) { return(new TransformResult(HOME_CONTENT_URL + contentId, TransformAction.Substitute)); } } else if (bestMatchingCategoryId != default(int)) { contextItems[CATEGORY_ID] = bestMatchingCategoryId; correctPath = await categores.GetCategoryPath(bestMatchingCategoryId); if (correctPath == path) { return(new TransformResult(HOME_CONTENT_URL + bestMatchingCategoryId, TransformAction.Substitute)); } } else { return(transformResult); //None } return(new TransformResult(correctPath, TransformAction.Redirect)); }
/// <summary> /// Home controller constructor /// </summary> /// <param name="dbContext">The <see cref="Mp3EhbContext"/> instance, /// <seealso cref="DbContext"</param> public HomeController(Mp3EhbContext dbContext) { this.Db = dbContext; }