Thursday, January 10, 2019

OData using ODataQueryOptions $count $select $expand $filter without using [EnableQuery] attribute

If you are using OData controller without using [EnableQuery] attribute, Below example help you to get all your odata query

Odata Query

/odata/GetTestData?$format=json&$filter=(Name+eq+'santosh'+AND+Age+eq+30)&$select=Name,Address&$top=50&$count=true

Step 1:

declare temp variable and load data from your repository like below:

IQueryable tempQuery = repo.GetTestData();
IQueryable result = tempQuery;

Step 2:

Add below lines of code to apply your query.
for $count- get count() from temp result variable so that you will get all data count

if (opts.Filter != null){
tempQuery = opts.Filter.ApplyTo(tempQuery, new ODataQuerySettings()) as Queryable;
}
if (opts.Top != null){
tempQuery = opts.Top.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
if (opts.Skip != null){
tempQuery = opts.Skip.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
if (opts.OrderBy != null){
tempQuery = opts.OrderBy.ApplyTo(tempQuery, new ODataQuerySettings()) as Queryable;
}
if (opts.SelectExpand != null){
Request.ODataProperties().SelectExpandClause = opts.SelectExpand.SelectExpandClause;
}
 if (opts.Count != null)
{
Request.ODataProperties().TotalCount = result.Count();
}

Step 3:
Final full Odata Controller code

//Web API Odata Controller

 [HttpGet]
 [ODataRoute("GetTestData")]
public IQueryable GetTestData(ODataQueryOptions opts)
        {
            
            var repo = unitOfWork.TestRepository;

            IQueryable tempQuery = repo.GetTestData();
            IQueryable result = tempQuery;

            if (opts.Filter != null){
                tempQuery = opts.Filter.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
            if (opts.Top != null){
                tempQuery = opts.Top.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
            if (opts.Skip != null){
                tempQuery = opts.Skip.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
            if (opts.OrderBy != null){
                tempQuery = opts.OrderBy.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable;
}
            if (opts.SelectExpand != null){
                Request.ODataProperties().SelectExpandClause = opts.SelectExpand.SelectExpandClause;
}
            if (opts.Count != null)
            {
                Request.ODataProperties().TotalCount = result.Count();
            }

            result = tempQuery.ToList().AsQueryable();

            return result;
        }

Happy coding👍

Friday, January 4, 2019

OData $expand and $select

How to implement OData $expand and $select in Web API

You can download the full code from my GitHub repository 

And follow my YouTube channel for detailed description
Step 1:

Create a new Web API project in visual studio and add below nuget packages to enable odata
"Microsoft.AspNet.OData"

Step 2:

Create below model class Product, Supplier, Category and ProductList
-----------------------------------------------------------------------------
using System.ComponentModel.DataAnnotations.Schema;

namespace ODataExpandAndSelect.Models
{
    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }

        [ForeignKey("Category")]
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }

        [ForeignKey("Supplier")]
        public string SupplierId { get; set; }
        public virtual Supplier Supplier { get; set; }
    }
}
----------------------------------------------------------------------------------------
using System.ComponentModel.DataAnnotations;

namespace ODataExpandAndSelect.Models
{
    public class Supplier
    {
        [Key]
        public string Key { get; set; }
        public string Name { get; set; }
    }

}
----------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;

namespace ODataExpandAndSelect.Models
{
    public class Category
    {
        public Category()
        {
            Products = new HashSet();
        }
        public int ID { get; set; }
        public string Name { get; set; }
        public virtual ICollection Products { get; set; }
    }
------------------------------------------------------------------------------------------
    public class ProductList
    {
        public IQueryable getProducts()
        {
            List products = new List();

            Category c1 = new Category() { ID = 1, Name = "Category1", Products = products };
            Category c2 = new Category() { ID = 2, Name = "Category2", Products = products };
            Supplier s1 = new Supplier() { Key = "s1", Name = "Supplier1" };
            Supplier s2 = new Supplier() { Key = "s2", Name = "Supplier2" };

            Product p1 = new Product() { ID = 1, Category = c1, CategoryId = 1, Name = "product1", Price = 100.50M , Supplier = s1, SupplierId = "SupplierS1" };
            Product p2 = new Product() { ID = 2, Category = c2, CategoryId = 2, Name = "product2", Price = 200.50M , Supplier = s2, SupplierId = "SupplierS2" };

            products.Add(p1);
            products.Add(p2);
           
            return products.AsQueryable();
        }
    }
}
------------------------------------------------------------------------------------

Since I am not using any database in this example, So I have created ProductList class and returning some dummy data, You may use any database or entity framework as per your requirement.

Step 3:  
In WebApi.Config Please add below changes

using System.Linq;
using System.Web.Http;
using Microsoft.AspNet.OData.Batch;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.OData.Edm;
using ODataExpandAndSelect.Models;

namespace ODataExpandAndSelect
{
    public static class WebApiConfig
    {
        private static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.Namespace = "WebAPITest";
            builder.ContainerName = "DefaultContainer";
            builder.EntitySet("Product");
            builder.EntitySet("Category");
            builder.EntitySet("Supplier");
            var edmModel = builder.GetEdmModel();
            return edmModel;
        }
        public static void Register(HttpConfiguration config)
        {
            config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); 
            config.MapODataServiceRoute("odata", null, GetEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
            config.EnsureInitialized();
        }
    }

}

Step 4:
Create a ProductController in controller folder like below

using System.Linq;
using Microsoft.AspNet.OData;
using ODataExpandAndSelect.Models;

namespace ODataExpandAndSelect.Controllers
{
    public class ProductController : ODataController
    {
        [EnableQuery]
        public IQueryable Get()
        {
            ProductList list = new ProductList();
            var data = list.getProducts();
            return data;
        }
    }
}

Step 5:
In Global.asax.cs add below changes

using System.Web.Http;

namespace ODataExpandAndSelect
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);
        }
    }
}

Step 6:
Run your application on IIS express and use query like below

http://localhost:5197/Product?$expand=Category





You can expand to next level through comma separated like below query
http://localhost:5197/Product?$expand=Category,Supplier


For $select you can you below query
http://localhost:5197/Product?$select=Price





Thank you
Happy coding