Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Chapter 7

  • Loading branch information...
commit 36a5616a6c9ca55c007817c6dcb7443ad985ac2c 1 parent 3d9de3a
@jchadwick jchadwick authored
View
24 Ebuy.Common/DataAccess/IRepository.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Ebuy.DataAccess
+{
+ public interface IRepository : IDisposable
+ {
+ void Add<TModel>(TModel instance) where TModel : class, IEntity;
+ void Add<TModel>(IEnumerable<TModel> instances) where TModel : class, IEntity;
+
+ IQueryable<TModel> All<TModel>(params string[] includePaths) where TModel : class, IEntity;
+
+ void Delete<TModel>(object key) where TModel : class, IEntity;
+ void Delete<TModel>(TModel instance) where TModel : class, IEntity;
+ void Delete<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class, IEntity;
+
+ TModel Single<TModel>(object key) where TModel : class, IEntity;
+ TModel Single<TModel>(Expression<Func<TModel, bool>> predicate, params string[] includePaths) where TModel : class, IEntity;
+
+ IQueryable<TModel> Query<TModel>(Expression<Func<TModel, bool>> predicate, params string[] includePaths) where TModel : class, IEntity;
+ }
+}
View
139 Ebuy.Common/DataAccess/Repository.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Data.Entity.Infrastructure;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Ebuy.DataAccess
+{
+ public class Repository : IRepository
+ {
+ private readonly DbContext _context;
+ private readonly bool _isSharedContext;
+
+ public Repository(DbContext context, bool isSharedContext = true)
+ {
+ Contract.Requires(context != null);
+
+ _context = context;
+ _isSharedContext = isSharedContext;
+ }
+
+
+ public void Add<TModel>(TModel instance)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(instance != null);
+
+ _context.Set<TModel>().Add(instance);
+
+ if (_isSharedContext == false)
+ _context.SaveChanges();
+ }
+
+ public void Add<TModel>(IEnumerable<TModel> instances)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(instances != null);
+
+ foreach (var instance in instances)
+ {
+ Add(instance);
+ }
+ }
+
+
+ public IQueryable<TModel> All<TModel>(params string[] includePaths)
+ where TModel : class, IEntity
+ {
+ return Query<TModel>(x => true, includePaths);
+ }
+
+
+ public void Dispose()
+ {
+ // If this is a shared (or null) context then
+ // we're not responsible for disposing it
+ if (_isSharedContext || _context == null)
+ return;
+
+ _context.Dispose();
+ }
+
+
+ public void Delete<TModel>(object id)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(id != null);
+
+ var instance = Single<TModel>(id);
+ Delete(instance);
+ }
+
+ public void Delete<TModel>(TModel instance)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(instance != null);
+
+ if (instance != null)
+ _context.Set<TModel>().Remove(instance);
+ }
+
+ public void Delete<TModel>(Expression<Func<TModel, bool>> predicate)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(predicate != null);
+
+ TModel entity = Single(predicate);
+ Delete(entity);
+ }
+
+
+ public TModel Single<TModel>(object id)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(id != null);
+
+ var instance = _context.Set<TModel>().Find(id);
+ return instance;
+ }
+
+ public TModel Single<TModel>(Expression<Func<TModel, bool>> predicate, params string[] includePaths)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(predicate != null);
+
+ var instance = GetSetWithIncludedPaths<TModel>(includePaths).SingleOrDefault(predicate);
+ return instance;
+ }
+
+
+ public IQueryable<TModel> Query<TModel>(Expression<Func<TModel, bool>> predicate, params string[] includePaths)
+ where TModel : class, IEntity
+ {
+ Contract.Requires(predicate != null);
+
+ var items = GetSetWithIncludedPaths<TModel>(includePaths);
+
+ if (predicate != null)
+ return items.Where(predicate);
+
+ return items;
+ }
+
+
+ private DbQuery<TModel> GetSetWithIncludedPaths<TModel>(IEnumerable<string> includedPaths) where TModel : class, IEntity
+ {
+ DbQuery<TModel> items = _context.Set<TModel>();
+
+ foreach (var path in includedPaths ?? Enumerable.Empty<string>())
+ {
+ items = items.Include(path);
+ }
+
+ return items;
+ }
+ }
+}
View
3  Ebuy.Common/Ebuy.Common.csproj
@@ -48,8 +48,11 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="DataAccess\IRepository.cs" />
+ <Compile Include="DataAccess\Repository.cs" />
<Compile Include="Entities\Auction.cs" />
<Compile Include="DataAccess\EbuyDataContext.cs" />
+ <Compile Include="Entities\Entity.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
View
2  Ebuy.Common/Entities/Auction.cs
@@ -3,7 +3,7 @@
namespace Ebuy
{
- public class Auction
+ public class Auction : IEntity
{
public long Id { get; set; }
View
60 Ebuy.Common/Entities/Entity.cs
@@ -0,0 +1,60 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Ebuy
+{
+ public interface IEntity
+ {
+ }
+
+ public abstract class Entity<TId> : IEntity, IEquatable<Entity<TId>>
+ where TId : struct
+ {
+ [Key]
+ public virtual TId Id
+ {
+ get
+ {
+ if (_id == null && typeof(TId) == typeof(Guid))
+ _id = Guid.NewGuid();
+
+ return _id == null ? default(TId) : (TId)_id;
+ }
+ protected set { _id = value; }
+ }
+ private object _id;
+
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != typeof(Entity<TId>)) return false;
+ return Equals((Entity<TId>)obj);
+ }
+
+ public bool Equals(Entity<TId> other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ if (other.GetType() != GetType()) return false;
+
+ return other.Id.Equals(Id);
+ }
+
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
+ }
+
+ public static bool operator ==(Entity<TId> left, Entity<TId> right)
+ {
+ return Equals(left, right);
+ }
+
+ public static bool operator !=(Entity<TId> left, Entity<TId> right)
+ {
+ return !Equals(left, right);
+ }
+ }
+}
View
79 Ebuy.Website/Api/AuctionCsvFormatter.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http.Formatting;
+using System.Net.Http.Headers;
+
+namespace Ebuy.Website.Api
+{
+ public class AuctionCsvFormatter : BufferedMediaTypeFormatter
+ {
+ public AuctionCsvFormatter()
+ {
+ SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
+ }
+
+ public override bool CanWriteType(Type type)
+ {
+ if (type == typeof(Auction))
+ {
+ return true;
+ }
+ else
+ {
+ Type enumerableType = typeof(IEnumerable<Auction>);
+ return enumerableType.IsAssignableFrom(type);
+ }
+ }
+
+ public override bool CanReadType(Type type)
+ {
+ return false;
+ }
+
+ public override void WriteToStream(Type type, object value, Stream stream, System.Net.Http.HttpContent content)
+ {
+ var source = value as IEnumerable<Auction>;
+ if (source != null)
+ {
+ foreach (var item in source)
+ {
+ WriteItem(item, stream);
+ }
+ }
+ else
+ {
+ var item = value as Auction;
+ if (item != null)
+ {
+ WriteItem(item, stream);
+ }
+ }
+ }
+
+ private void WriteItem(Auction item, Stream stream)
+ {
+ var writer = new StreamWriter(stream);
+ writer.WriteLine("{0},{1},{2}",
+ Encode(item.Title),
+ Encode(item.Description),
+ Encode(item.CurrentPrice));
+ writer.Flush();
+ }
+
+ static readonly char[] _specialChars = new char[] { ',', '\n', '\r', '"' };
+ private string Encode(object o)
+ {
+ string result = "";
+ if (o != null)
+ {
+ string data = o.ToString();
+ if (data.IndexOfAny(_specialChars) != -1)
+ {
+ result = String.Format("\"{0}\"", data.Replace("\"", "\"\""));
+ }
+ }
+ return result;
+ }
+ }
+}
View
54 Ebuy.Website/Api/AuctionsDataController.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Linq;
+using System.Web.Http;
+using AutoMapper;
+using Ebuy.DataAccess;
+
+namespace Ebuy.Website.Api
+{
+ public class AuctionsDataController : ApiController
+ {
+ private readonly IRepository _repository;
+
+ public AuctionsDataController(IRepository repository)
+ {
+ _repository = repository;
+ }
+
+ public IQueryable<Auction> Get()
+ {
+ return _repository.All<Auction>().AsQueryable();
+ }
+
+ [CustomExceptionFilter]
+ public Auction Get(string id)
+ {
+ var result = _repository.Single<Auction>(id);
+
+ if (result == null)
+ {
+ throw new Exception("Item not Found!");
+ }
+
+ return result;
+ }
+ public void Post(Auction auction)
+ {
+ _repository.Add<Auction>(auction);
+ }
+
+ public void Put(string id, Auction auction)
+ {
+ var currentAuction = _repository.Single<Auction>(id);
+ if (currentAuction != null)
+ {
+ Mapper.DynamicMap(auction, currentAuction);
+ }
+ }
+
+ public void Delete(string id)
+ {
+ _repository.Delete<Auction>(id);
+ }
+ }
+}
View
20 Ebuy.Website/Api/CustomExceptionFilter.cs
@@ -0,0 +1,20 @@
+using System.Net;
+using System.Net.Http;
+using System.Web.Http.Filters;
+
+namespace Ebuy.Website.Api
+{
+ public class CustomExceptionFilter : ExceptionFilterAttribute
+ {
+ public override void OnException(HttpActionExecutedContext context)
+ {
+ if (context.Response == null)
+ {
+ context.Response = new HttpResponseMessage();
+ }
+
+ context.Response.StatusCode = HttpStatusCode.NotImplemented;
+ context.Response.Content = new StringContent("Custom Message");
+ }
+ }
+}
View
8 Ebuy.Website/App_Start/WebApiConfig.cs
@@ -1,7 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web.Http;
+using System.Web.Http;
+using Ebuy.Website.Api;
namespace Ebuy.Website
{
@@ -9,6 +7,8 @@ public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
+ config.Formatters.Add(new AuctionCsvFormatter());
+
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
View
6 Ebuy.Website/Ebuy.Website.csproj
@@ -39,6 +39,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="AutoMapper">
+ <HintPath>..\packages\AutoMapper.2.2.0\lib\net40\AutoMapper.dll</HintPath>
+ </Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Ninject">
<HintPath>..\packages\Ninject.3.0.1.10\lib\net45-full\Ninject.dll</HintPath>
@@ -168,6 +171,9 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="Api\AuctionCsvFormatter.cs" />
+ <Compile Include="Api\AuctionsDataController.cs" />
+ <Compile Include="Api\CustomExceptionFilter.cs" />
<Compile Include="App_Start\AuthConfig.cs" />
<Compile Include="App_Start\BundleConfig.cs" />
<Compile Include="App_Start\FilterConfig.cs" />
View
1  Ebuy.Website/packages.config
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="AutoMapper" version="2.2.0" targetFramework="net45" />
<package id="DotNetOpenAuth.AspNet" version="4.0.3.12153" targetFramework="net45" />
<package id="DotNetOpenAuth.Core" version="4.0.3.12153" targetFramework="net45" />
<package id="DotNetOpenAuth.OAuth.Consumer" version="4.0.3.12153" targetFramework="net45" />
Please sign in to comment.
Something went wrong with that request. Please try again.