/*IActionResult defines a contract that represents the result of an action method. */ /*ActionResult<T> explicity define the return type of the method, the other pieces * of code can infer the actions expected return type. That allows them to integrate * better of our actions. This isn't the benefit that is immediately obvious. It only * becomes obvious when implementing something like Swashbuckle for documenting the API, * which relies on getting information on how our API behaves. Next to that, both <T> * and ActionResult can be implicitly cast to an ActionResult of T, and that too simplifies * syntax. In other words, when you can use ActionResult of T, use it.*/ /* We are now implementing a filter on mainCategory when getting authors. * The first thing to do is to allow the consumer of the API to pass in the value for the * mainCategory to the query string. This does not match any parameter name from the * route template so, thanks to the ApiController attribute, this will be bound by the * query string. [FromQuery] attribute is optional but this will make the code more * readable. In case the action parameter name is different from the key in the query string, * you can use the Name property FromQuery attribute [FromQuery(Name = "differentMainCategory")]. * We will leave the default value as null. "string" is a reference type so null is the default. * By default, we don't want to apply "mainCategory" filters to our authors collection. */ /* We will now add searching functionality for our Authors collection. We will accept a search query * and will return all authors for which one of the string fields contains the search query. First * we need to ensure that the search query can be passed in. That means adding a search query * string to our action parameter list for the GetAuthors action. We do need to combine it * with the filtering. The consumer might do a filter or search or combine both. */ public ActionResult <IEnumerable <AuthorDto> > GetAuthors(AuthorsResourceParameter authorsResourceParameter) { var authorsFromRepo = _courseLibraryRepository.GetAuthors(authorsResourceParameter); // We are now commenting this codes since we will now use AutoMapper //var authors = new List<AuthorDto>(); //foreach (var author in authorsFromRepo) //{ // authors.Add(new AuthorDto() // { // Id = author.Id, // Name = $"{author.FirstName} {author.LastName}", // MainCategory = author.MainCategory, // Age = author.DateOfBirth.GetCurrentAge() // }); ; //} //return Ok(authors); /* We want to map the authorsFromRepo variable. We pass to the type we want * to get back. */ return(Ok(_mapper.Map <IEnumerable <AuthorDto> >(authorsFromRepo))); }
private IEnumerable <LinkDto> CreateLinksForAuthors( AuthorsResourceParameter authorsResourceParameter, bool hasNext, bool hasPrevious) { var links = new List <LinkDto>(); links.Add( new LinkDto(CreateAuthorsResourceUri(authorsResourceParameter, ResourceUriType.Current), "self", "GET" )); if (hasNext) { links.Add( new LinkDto(CreateAuthorsResourceUri(authorsResourceParameter, ResourceUriType.NextPage), "nextPage", "GET" )); } if (hasPrevious) { links.Add( new LinkDto(CreateAuthorsResourceUri(authorsResourceParameter, ResourceUriType.PreviousPage), "previousPage", "GET" )); } return(links); }
public async Task <PagedList <Author> > GetAuthors(AuthorsResourceParameter authorsResourceParameter) { var collectionBeforePaging = _context.Authors.ApplySort(authorsResourceParameter.OrderBy, _propertyMappingService.GetPropertyMapping <AuthorDto, Author>()); if (!string.IsNullOrEmpty(authorsResourceParameter.Genre)) { // trim and to lower case var genreForwhereClause = authorsResourceParameter.Genre.Trim().ToLower(); collectionBeforePaging = collectionBeforePaging .Where(a => a.Genre.ToLower() == genreForwhereClause); } if (!string.IsNullOrEmpty(authorsResourceParameter.SearchQuery)) { // trim and to lower case var searhForwhereClause = authorsResourceParameter.SearchQuery.Trim().ToLower(); collectionBeforePaging = collectionBeforePaging .Where(a => a.Genre.ToLower().Contains(searhForwhereClause) || a.FirstName.ToLower().Contains(searhForwhereClause) || a.LastName.ToLower().Contains(searhForwhereClause)); } return(await PagedList <Author> .Create(collectionBeforePaging, authorsResourceParameter.PageNumber, authorsResourceParameter.PageSize)); }
public IEnumerable <Author> GetAuthors(AuthorsResourceParameter authorsResourceParameter) { if (authorsResourceParameter == null) { throw new ArgumentNullException(nameof(authorsResourceParameter)); } if (string.IsNullOrWhiteSpace(authorsResourceParameter.MainCategory) && string.IsNullOrWhiteSpace(authorsResourceParameter.SearchQuery)) { return(GetAuthors()); } var collection = _context.Authors as IQueryable <Author>; if (!string.IsNullOrWhiteSpace(authorsResourceParameter.MainCategory)) { var mainCategory = authorsResourceParameter.MainCategory.Trim(); collection = collection.Where(a => a.MainCategory == mainCategory); } if (!string.IsNullOrWhiteSpace(authorsResourceParameter.SearchQuery)) { var searchQuery = authorsResourceParameter.SearchQuery.Trim(); collection = collection.Where(a => a.MainCategory.Contains(searchQuery) || a.FirstName.Contains(searchQuery) || a.LastName.Contains(searchQuery)); } return(collection.ToList()); }
public ActionResult <IEnumerable <AuthorDto> > GetAuthors([FromQuery] AuthorsResourceParameter authorsResourceParameter) { var authors = _courseLibraryRepository.GetAuthors(authorsResourceParameter); var result = _mapper.Map <IEnumerable <AuthorDto> >(authors); return(Ok(result)); }
public IEnumerable <Author> GetAuthors(AuthorsResourceParameter authorsResourceParameter) { if (string.IsNullOrWhiteSpace(authorsResourceParameter.MainCategory) && string.IsNullOrWhiteSpace(authorsResourceParameter.SearchQuery)) { return(GetAuthors()); } //mainCategory = mainCategory.Trim(); //return _context.Authors.Where(a => a.MainCategory == mainCategory).ToList(); /* It could be that we only want to apply the filter, only want to apply the * search query or both. We want to cover all of these cases, so the first thing * we will do is cast the Author DbSet to an IQueryable of author. The Author DbSet * is Authors on the context. By doing this, we can work on this collection, adding * where clauses for filtering when needed and for searching. There is a good reason * to write code like this and it has something to do with deferred execution. * * DEFERRED EXECUTION * Whe working with Entity-Framework Core, we use Linq to build our queries. With deferred * execution, the query variable itself never holds the query results and only stores * the query commands. Execution of the query is deferred until the query variable is * iterated over. So, deferred execution means that query execution occurs sometime after * the query is constructed. We can get this behavior by working with IQueryable * implementing collections. A query variable stores query commands and not results. * IQueryable of T allows us to execute the query against the specific datasource, * and while building upon it, it creates an expression tree. But, the query itself * is not sent to the datasource until the iteration happens and the iteration can happen * in different ways: (1) using the IQueryable in a loop, (2) calling ToList(), ToArray(), * ToDictionary() because this means that converting the expression tree to an actual * list of items, (3) calling Singleton queries like Average, Count, First, */ var collection = _context.Authors as IQueryable <Author>; if (!string.IsNullOrWhiteSpace(authorsResourceParameter.MainCategory)) { authorsResourceParameter.MainCategory = authorsResourceParameter.MainCategory.Trim(); collection = collection.Where(a => a.MainCategory == authorsResourceParameter.MainCategory); } if (!string.IsNullOrWhiteSpace(authorsResourceParameter.SearchQuery)) { authorsResourceParameter.SearchQuery = authorsResourceParameter.SearchQuery.Trim(); collection = collection.Where(a => a.MainCategory.Contains(authorsResourceParameter.SearchQuery) || a.LastName.Contains(authorsResourceParameter.SearchQuery) || a.FirstName.Contains(authorsResourceParameter.SearchQuery)); } return(collection.ToList()); }
/* Creates a links for pagination */ private string CreateAuthorsResourceUri( AuthorsResourceParameter authorsResourceParameter, ResourceUriType type) { switch (type) { case ResourceUriType.PreviousPage: return(urlHelper.Link("GetAuthors", new { fields = authorsResourceParameter.Fields, orderBy = authorsResourceParameter.OrderBy, searchQuery = authorsResourceParameter.SearchQuery, genre = authorsResourceParameter.Genre, pageNumber = authorsResourceParameter.PageNumber - 1, pageSize = authorsResourceParameter.PageSize }));; case ResourceUriType.NextPage: return(urlHelper.Link("GetAuthors", new { fields = authorsResourceParameter.Fields, orderBy = authorsResourceParameter.OrderBy, searchQuery = authorsResourceParameter.SearchQuery, genre = authorsResourceParameter.Genre, pageNumber = authorsResourceParameter.PageNumber + 1, pageSize = authorsResourceParameter.PageSize })); case ResourceUriType.Current: default: return(urlHelper.Link("GetAuthors", new { fields = authorsResourceParameter.Fields, orderBy = authorsResourceParameter.OrderBy, searchQuery = authorsResourceParameter.SearchQuery, genre = authorsResourceParameter.Genre, pageNumber = authorsResourceParameter.PageNumber, pageSize = authorsResourceParameter.PageSize })); } }
public IEnumerable <Author> GetAuthors(AuthorsResourceParameter authorsResourceParameter) { var result = _context.Authors as IQueryable <Author>; if (!string.IsNullOrEmpty(authorsResourceParameter.MainCategory)) { result = result.Where(it => it.MainCategory == authorsResourceParameter.MainCategory); } if (!string.IsNullOrEmpty(authorsResourceParameter.SearchQuery)) { result = result.Where(it => it.MainCategory.Contains(authorsResourceParameter.SearchQuery) || it.FirstName.Contains(authorsResourceParameter.SearchQuery) || it.LastName.Contains(authorsResourceParameter.SearchQuery) ); } return(result); }
public async Task <IActionResult> GetAuthors([FromQuery] AuthorsResourceParameter authorsResourceParameter, [FromHeader(Name = "Accept")] string mediaType) // accept header for getting the media type { if (!propertyMappingService.ValidMappingExistsFor <AuthorDto, Author>(authorsResourceParameter.OrderBy)) { return(BadRequest()); } if (!typeHelperService.TypeHasProperties <AuthorDto>(authorsResourceParameter.Fields)) { return(BadRequest()); } var authorsFromRepo = await libraryRepository.GetAuthors(authorsResourceParameter); var authors = Mapper.Map <IEnumerable <AuthorDto> >(authorsFromRepo); if (mediaType == "application/vnd.marvin.hateoas+json") { var paginationMetaData = new { totalCount = authorsFromRepo.TotalCount, pageSize = authorsFromRepo.PageSize, currentPage = authorsFromRepo.CurrentPage, totalPages = authorsFromRepo.TotalPages }; Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetaData)); // Links for each author for DELETE, POST, GET var links = CreateLinksForAuthors(authorsResourceParameter, authorsFromRepo.HasNext, authorsFromRepo.HasPrevious); var shapedAuthors = authors.ShapeData(authorsResourceParameter.Fields); // Links for each author for DELETE, POST, GET var shapedAuthorsWithLinks = shapedAuthors.Select(author => { var authorAsDictionary = author as IDictionary <string, object>; var authorLinks = CreateLinksForAuthor( (Guid)authorAsDictionary["Id"], authorsResourceParameter.Fields); authorAsDictionary.Add("links", authorLinks); return(authorAsDictionary); }); var linkedCollectionResource = new { value = shapedAuthorsWithLinks, links }; return(Ok(linkedCollectionResource)); } else { var previousPageLink = authorsFromRepo.HasPrevious ? CreateAuthorsResourceUri(authorsResourceParameter, ResourceUriType.PreviousPage) : null; var nextPageLink = authorsFromRepo.HasNext ? CreateAuthorsResourceUri(authorsResourceParameter, ResourceUriType.NextPage) : null; var paginationMetaData = new { previousPageLink, nextPageLink, totalCount = authorsFromRepo.TotalCount, pageSize = authorsFromRepo.PageSize, currentPage = authorsFromRepo.CurrentPage, totalPages = authorsFromRepo.TotalPages }; Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetaData)); return(Ok(authors.ShapeData(authorsResourceParameter.Fields))); } }