Skip to content

Instantly share code, notes, and snippets.

@mythz
Created October 13, 2012 23:40
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mythz/3886615 to your computer and use it in GitHub Desktop.
Save mythz/3886615 to your computer and use it in GitHub Desktop.
Your First ASP.NET Web API Products Example vs ServiceStack
/* Tutorial example from:
* Your First ASP.NET Web API (C#):
* http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
*/
namespace HelloWebAPI.Controllers
{
public class ProductsController : ApiController
{
Product[] products = new Product[]
{
new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
};
public IEnumerable<Product> GetAllProducts()
{
return products;
}
public Product GetProductById(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return product;
}
public IEnumerable<Product> GetProductsByCategory(string category)
{
return products.Where(
(p) => string.Equals(p.Category, category,
StringComparison.OrdinalIgnoreCase));
}
}
}
/* Enhancing your services:
* - Added Get by categoryName
* - Added Find by Price
*/
namespace HelloWebAPI.Controllers
{
public class ProductsControllerV2 : ApiController
{
Product[] products = new Product[]
{
new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
};
public IEnumerable<Product> GetAllProducts()
{
return products;
}
public Product GetProductById(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return product;
}
public Product GetProductByName(string categoryName)
{
var product = products.FirstOrDefault((p) => p.Name == categoryName);
if (product == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return product;
}
//Extending existing services by adding more RPC method signatures
public IEnumerable<Product> GetProductsByCategory(string category)
{
return products.Where(
(p) => string.Equals(p.Category, category,
StringComparison.OrdinalIgnoreCase));
}
public IEnumerable<Product> GetProductsByPriceGreaterThan(decimal price)
{
return products.Where((p) => p.Price > price);
}
}
}
//Same implementation as above but using Coarse-grained, Batch-ful interfaces, less + more re-usable services:
namespace WebApi.ProductsExample
{
//Design of new services based on calling semantics and Return type, e.g. Find* filters results, whilst Get* fetches unique records:
public class FindProducts : IReturn<List<Product>>
{
public string Category { get; set; }
public decimal? PriceGreaterThan { get; set; }
}
public class GetProduct : IReturn<Product>
{
public int? Id { get; set; }
public string Name { get; set; }
}
public class ProductsService : IService
{
readonly Product[] products = new[]
{
new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
};
public object Get(FindProducts request)
{
var ret = products.AsQueryable();
if (request.Category != null)
ret = ret.Where(x => x.Category == request.Category);
if (request.PriceGreaterThan.HasValue)
ret = ret.Where(x => x.Price > request.PriceGreaterThan.Value);
return ret;
}
public object Get(GetProduct request)
{
var product = request.Id.HasValue
? products.FirstOrDefault(x => x.Id == request.Id.Value)
: products.FirstOrDefault(x => x.Name == request.Name);
if (product == null)
throw new HttpError(HttpStatusCode.NotFound, "Product does not exist");
return product;
}
}
}
// Notes:
// - No Code-Gen: Same generic service client used for all operations
// - When Custom Routes are specified it uses those, otherwise falls back to pre-defined routes
// - IRestClient interface implemented by JSON, JSV, Xml, MessagePack, ProtoBuf Service Clients
// - Service returns IEnumerable[Product] but JSON, JSV serializers happily handles List[Product] fine
private const string BaseUri = "http://localhost:1337";
IRestClient client = new JsonServiceClient(BaseUri);
"\nAll Products:".Print();
client.Get(new FindProducts()).PrintDump();
/* All Products:
[
{
Id: 1,
Name: Tomato Soup,
Category: Groceries,
Price: 1
},
{
Id: 2,
Name: Yo-yo,
Category: Toys,
Price: 3.75
},
{
Id: 3,
Name: Hammer,
Category: Hardware,
Price: 16.99
}
]
*/
List<Product> toyProducts = client.Get(new FindProducts { Category = "Toys" });
"\nToy Products:".Print();
toyProducts.PrintDump();
/* Toy Products:
[
{
Id: 2,
Name: Yo-yo,
Category: Toys,
Price: 3.75
}
]
*/
List<Product> productsOver2Bucks = client.Get(new FindProducts { PriceGreaterThan = 2 });
"\nProducts over $2:".Print();
productsOver2Bucks.PrintDump();
/* Products over $2:
[
{
Id: 2,
Name: Yo-yo,
Category: Toys,
Price: 3.75
},
{
Id: 3,
Name: Hammer,
Category: Hardware,
Price: 16.99
}
]
*/
List<Product> hardwareOver2Bucks = client.Get(new FindProducts { PriceGreaterThan = 2, Category = "Hardware" });
"\nHardware over $2:".Print();
hardwareOver2Bucks.PrintDump();
/* Hardware over $2:
[
{
Id: 3,
Name: Hammer,
Category: Hardware,
Price: 16.99
}
]
*/
Product product1 = client.Get(new GetProduct { Id = 1 });
"\nProduct with Id = 1:".Print();
product1.PrintDump();
/* Product with Id = 1:
{
Id: 1,
Name: Tomato Soup,
Category: Groceries,
Price: 1
}
*/
"\nIt's Hammer Time!".Print();
Product productHammer = client.Get(new GetProduct { Name = "Hammer" });
productHammer.PrintDump();
/* It's Hammer Time!
{
Id: 3,
Name: Hammer,
Category: Hardware,
Price: 16.99
}
*/
@tekguy
Copy link

tekguy commented Mar 8, 2013

Thank you, very useful examples

@amgdy
Copy link

amgdy commented May 22, 2013

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment