-
Notifications
You must be signed in to change notification settings - Fork 55
Services Pattern Example
rdhainaut edited this page Nov 15, 2017
·
4 revisions
Example: Northwind.Service.CustomerService.cs
*All methods from Service<TEntity>
are overridable, so that business logic can be added. Business logic should only be in Service Layer and not in the Repository Layer to address Separation of Concerns.
public interface ICustomerService : IService<Customer>
{
// Add any custom business logic (methods) here
// All methods in Service<TEntity> are ovverridable for any custom implementations
}
public class CustomerService : Service<Customer>, ICustomerService
{
public CustomerService(IRepositoryAsync<Customer> repository) : base(repository)
{
}
// Add any custom business logic (methods) here
// All methods in Service<TEntity> are ovverridable for any custom implementations
// Can ovveride any of the Repository methods to add business logic in them
// e.g.
//public override void Delete(Customer entity)
//{
// // Add business logic before or after deleting entity.
// base.Delete(entity);
//}
}
Example: Northwind.AppStart.UnitConfig.cs
container
.RegisterType<IDataContextAsync, NorthwindContext>(new PerRequestLifetimeManager())
.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
.RegisterType<IRepositoryAsync<Customer>, Repository<Customer>>()
.RegisterType<IRepositoryAsync<Product>, Repository<Product>>()
.RegisterType<IProductService, ProductService>();
Example: Northwind.WebApi.ProductController.cs
Can leverage the Northwind.Web.CodeTemplates.ODataControllerWithContext.t4 template (copy to project) Right click -> Add New Controller -> Web Api 2 OData Controller with actions, using Entity Framework (will use this T4 template)
public class ProductController : ODataController
{
private readonly IProductService _productService;
private readonly IUnitOfWorkAsync _unitOfWork;
public ProductController(
IUnitOfWorkAsync unitOfWork,
IProductService productService)
{
_unitOfWork = unitOfWork;
_productService = productService;
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Product> GetProduct()
{
return _productService.Queryable();
}
// GET odata/Product(5)
[Queryable]
public SingleResult<Product> GetProduct([FromODataUri] int key)
{
return SingleResult.Create(
_productService
.Query(product => product.ProductID == key)
.Select()
.AsQueryable());
}
// PUT odata/Product(5)
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != product.ProductID)
{
return BadRequest();
}
product.ObjectState = ObjectState.Modified;
_productService.Update(product);
try
{
await _unitOfWork.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(product);
}
// POST odata/Product
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
product.ObjectState = ObjectState.Added;
_productService.Insert(product);
await _unitOfWork.SaveChangesAsync();
return Created(product);
}
// PATCH odata/Product(5)
[AcceptVerbs("PATCH", "MERGE")]
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> patch)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var product = await _productService.FindAsync(key);
if (product == null)
{
return NotFound();
}
patch.Patch(product);
product.ObjectState = ObjectState.Modified;
_productService.Update(product);
try
{
await _unitOfWork.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(product);
}
// DELETE odata/Product(5)
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var product = await _productService.FindAsync(key);
if (product == null)
{
return NotFound();
}
product.ObjectState = ObjectState.Deleted;
_productService.Delete(product);
await _unitOfWork.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
// GET odata/Product(5)/Category
[Queryable]
public SingleResult<Category> GetCategory([FromODataUri] int key)
{
return SingleResult.Create(
_productService
.Query(m => m.ProductID == key)
.Select(m => m.Category)
.AsQueryable());
}
// GET odata/Product(5)/OrderDetails
[Queryable]
public IQueryable<OrderDetail> GetOrderDetails([FromODataUri] int key)
{
var product = _productService
.Query(m => m.ProductID == key)
.Include(m => m.OrderDetails)
.Select()
.Single();
return product.OrderDetails.AsQueryable();
}
// GET odata/Product(5)/Supplier
[Queryable]
public SingleResult<Supplier> GetSupplier([FromODataUri] int key)
{
return SingleResult.Create(
_productService
.Query(m => m.ProductID == key)
.Select(m => m.Supplier)
.AsQueryable());
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_unitOfWork.Dispose();
}
base.Dispose(disposing);
}
private bool ProductExists(int key)
{
return _productService.Query(e => e.ProductID == key).Select().Any();
}
}
The Official URF Team | Docs: goo.gl/6zh9zp | Subscribe to URF Updates: @lelong37 | Blog: blog.longle.io