Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added UnitOfWork and Ninject

  • Loading branch information...
commit 80a8a8d6e66f7078c77ebbec29480b25cf661352 1 parent f672c64
Nicholas Murray authored
Showing with 56,065 additions and 0 deletions.
  1. +63 −0 CodeCamper.Data.Contracts/CodeCamper.Data.Contracts.csproj
  2. +13 −0 CodeCamper.Data.Contracts/IAttendanceRepository.cs
  3. +21 −0 CodeCamper.Data.Contracts/ICodeCamperUow.cs
  4. +19 −0 CodeCamper.Data.Contracts/IPersonsRepository.cs
  5. +14 −0 CodeCamper.Data.Contracts/IRepository.cs
  6. +35 −0 CodeCamper.Data.Contracts/ISessionsRepository.cs
  7. +36 −0 CodeCamper.Data.Contracts/Properties/AssemblyInfo.cs
  8. +46 −0 CodeCamper.Data/AttendanceRepository.cs
  9. +13 −0 CodeCamper.Data/CodeCamper.Data.csproj
  10. +105 −0 CodeCamper.Data/CodeCamperUow.cs
  11. +83 −0 CodeCamper.Data/EFRepository.cs
  12. +60 −0 CodeCamper.Data/Helpers/IRepositoryProvider.cs
  13. +33 −0 CodeCamper.Data/Helpers/PredicateBuilder.cs
  14. +119 −0 CodeCamper.Data/Helpers/RepositoryFactories.cs
  15. +128 −0 CodeCamper.Data/Helpers/RepositoryProvider.cs
  16. +35 −0 CodeCamper.Data/PersonsRepository.cs
  17. +77 −0 CodeCamper.Data/SessionsRepository.cs
  18. +6 −0 CodeCamper.Web.sln
  19. +26 −0 CodeCamper.Web/App_Start/GlobalConfig.cs
  20. +27 −0 CodeCamper.Web/App_Start/IocConfig.cs
  21. +21 −0 CodeCamper.Web/App_Start/NinjectDependencyResolver.cs
  22. +46 −0 CodeCamper.Web/App_Start/NinjectDependencyScope.cs
  23. +31 −0 CodeCamper.Web/App_Start/ValidationActionFilter.cs
  24. +12 −0 CodeCamper.Web/CodeCamper.Web.csproj
  25. +6 −0 CodeCamper.Web/Global.asax.cs
  26. +1 −0  CodeCamper.Web/packages.config
  27. BIN  packages/Ninject.3.0.1.10/Ninject.3.0.1.10.nupkg
  28. BIN  packages/Ninject.3.0.1.10/lib/net35/Ninject.dll
  29. +6,209 −0 packages/Ninject.3.0.1.10/lib/net35/Ninject.xml
  30. BIN  packages/Ninject.3.0.1.10/lib/net40/Ninject.dll
  31. +6,157 −0 packages/Ninject.3.0.1.10/lib/net40/Ninject.xml
  32. BIN  packages/Ninject.3.0.1.10/lib/net45-full/Ninject.dll
  33. +6,157 −0 packages/Ninject.3.0.1.10/lib/net45-full/Ninject.xml
  34. BIN  packages/Ninject.3.0.1.10/lib/sl2/Ninject.dll
  35. +6,120 −0 packages/Ninject.3.0.1.10/lib/sl2/Ninject.xml
  36. BIN  packages/Ninject.3.0.1.10/lib/sl3-wp/Ninject.dll
  37. +6,071 −0 packages/Ninject.3.0.1.10/lib/sl3-wp/Ninject.xml
  38. BIN  packages/Ninject.3.0.1.10/lib/sl3/Ninject.dll
  39. +6,120 −0 packages/Ninject.3.0.1.10/lib/sl3/Ninject.xml
  40. BIN  packages/Ninject.3.0.1.10/lib/sl4-windowsphone71/Ninject.dll
  41. +6,019 −0 packages/Ninject.3.0.1.10/lib/sl4-windowsphone71/Ninject.xml
  42. BIN  packages/Ninject.3.0.1.10/lib/sl4/Ninject.dll
  43. +6,068 −0 packages/Ninject.3.0.1.10/lib/sl4/Ninject.xml
  44. BIN  packages/Ninject.3.0.1.10/lib/sl5/Ninject.dll
  45. +6,068 −0 packages/Ninject.3.0.1.10/lib/sl5/Ninject.xml
63 CodeCamper.Data.Contracts/CodeCamper.Data.Contracts.csproj
View
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{95635373-151D-4F6C-87CB-65BA24C6E2C1}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CodeCamper.Data.Contracts</RootNamespace>
+ <AssemblyName>CodeCamper.Data.Contracts</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="IAttendanceRepository.cs" />
+ <Compile Include="ICodeCamperUow.cs" />
+ <Compile Include="IPersonsRepository.cs" />
+ <Compile Include="IRepository.cs" />
+ <Compile Include="ISessionsRepository.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\CodeCamper.Model\CodeCamper.Model.csproj">
+ <Project>{353810b1-c8cb-4a8b-86bc-f74929a1bf57}</Project>
+ <Name>CodeCamper.Model</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
13 CodeCamper.Data.Contracts/IAttendanceRepository.cs
View
@@ -0,0 +1,13 @@
+using System.Linq;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data.Contracts
+{
+ public interface IAttendanceRepository : IRepository<Attendance>
+ {
+ IQueryable<Attendance> GetByPersonId(int id);
+ IQueryable<Attendance> GetBySessionId(int id);
+ Attendance GetByIds(int personId, int sessionId);
+ void Delete(int personId, int sessionId);
+ }
+}
21 CodeCamper.Data.Contracts/ICodeCamperUow.cs
View
@@ -0,0 +1,21 @@
+using CodeCamper.Model;
+
+namespace CodeCamper.Data.Contracts
+{
+ /// <summary>
+ /// Interface for the Code Camper "Unit of Work"
+ /// </summary>
+ public interface ICodeCamperUow
+ {
+ // Save pending changes to the data store.
+ void Commit();
+
+ // Repositories
+ IPersonsRepository Persons { get; }
+ IRepository<Room> Rooms { get; }
+ ISessionsRepository Sessions { get; }
+ IRepository<TimeSlot> TimeSlots { get; }
+ IRepository<Track> Tracks { get; }
+ IAttendanceRepository Attendance { get; }
+ }
+}
19 CodeCamper.Data.Contracts/IPersonsRepository.cs
View
@@ -0,0 +1,19 @@
+using System.Linq;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data.Contracts
+{
+ public interface IPersonsRepository : IRepository<Person>
+ {
+ /// <summary>
+ /// Get <see cref="Speaker"/>s at sessions.
+ /// </summary>
+ /// <remarks>
+ /// <see cref="Speaker"/> is a subset of
+ /// <see cref="Person"/> properties suitable for
+ /// quick client-side filtering and presentation.
+ /// </remarks>
+ IQueryable<Speaker> GetSpeakers();
+
+ }
+}
14 CodeCamper.Data.Contracts/IRepository.cs
View
@@ -0,0 +1,14 @@
+using System.Linq;
+
+namespace CodeCamper.Data.Contracts
+{
+ public interface IRepository<T> where T : class
+ {
+ IQueryable<T> GetAll();
+ T GetById(int id);
+ void Add(T entity);
+ void Update(T entity);
+ void Delete(T entity);
+ void Delete(int id);
+ }
+}
35 CodeCamper.Data.Contracts/ISessionsRepository.cs
View
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Linq;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data.Contracts
+{
+ public interface ISessionsRepository : IRepository<Session>
+ {
+ /// <summary>
+ /// Get <see cref="SessionBrief"/>s,
+ /// a cutdown version of <see cref="Session"/> entities.
+ /// </summary>
+ /// <remarks>
+ /// <see cref="SessionBrief"/> is a subset of
+ /// <see cref="Session"/> properties suitable for
+ /// quick client-side filtering and presentation.
+ /// </remarks>
+ IQueryable<SessionBrief> GetSessionBriefs();
+
+ /// <summary>
+ /// Get the unique tags from all of the sessions
+ /// as a list of <see cref="TagGroup"/>.
+ /// </summary>
+ /// <remarks>
+ /// Each session has a "Tags" property with its tags in a
+ /// delimited string such as "WP7|MVVM|Mobile".
+ /// This TagGroups method creates a list of unique tags and
+ /// the ids of the sessions that have each tag.
+ /// e.g., {WP7, [1,4,5]}, {MVVM, [1,28]}, ...
+ /// Each item in the list is a <see cref="TagGroup"/> consisting
+ /// of a tag and an array of ids of sessions with that tag.
+ /// </remarks>
+ IEnumerable<TagGroup> GetTagGroups();
+ }
+}
36 CodeCamper.Data.Contracts/Properties/AssemblyInfo.cs
View
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CodeCamper.Data.Contracts")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CodeCamper.Data.Contracts")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("fd854710-71b8-43b2-befc-5e244871d636")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
46 CodeCamper.Data/AttendanceRepository.cs
View
@@ -0,0 +1,46 @@
+using System;
+using System.Data.Entity;
+using System.Linq;
+using CodeCamper.Data.Contracts;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data
+{
+ public class AttendanceRepository : EFRepository<Attendance>, IAttendanceRepository
+ {
+ public AttendanceRepository(DbContext context) : base(context) { }
+
+ public override Attendance GetById(int id)
+ {
+ throw new InvalidOperationException("Cannot return a single Attendance object by single id value.");
+ }
+
+ public Attendance GetByIds(int personId, int sessionId)
+ {
+ return DbSet.FirstOrDefault(ps => ps.PersonId == personId && ps.SessionId == sessionId);
+ }
+
+ public IQueryable<Attendance> GetByPersonId(int id)
+ {
+ return DbSet.Where(ps => ps.PersonId == id);
+ }
+
+ public IQueryable<Attendance> GetBySessionId(int id)
+ {
+ return DbSet.Where(ps => ps.SessionId == id);
+ }
+
+ public override void Delete(int id)
+ {
+ throw new InvalidOperationException("Cannot delete an Attendance object by a single id value.");
+ }
+
+ public void Delete(int personId, int sessionId)
+ {
+ // EF needs an attendance entity to delete (can't delete with the id)
+ // Don't need the REAL entity though. A placeholder with the ids in it will do.
+ var attendance = new Attendance {PersonId = personId, SessionId = sessionId};
+ Delete(attendance);
+ }
+ }
+}
13 CodeCamper.Data/CodeCamper.Data.csproj
View
@@ -47,9 +47,17 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="AttendanceRepository.cs" />
<Compile Include="CodeCamperDbContext.cs" />
+ <Compile Include="CodeCamperUow.cs" />
<Compile Include="Configuration\AttendanceConfiguration.cs" />
<Compile Include="Configuration\SessionConfiguration.cs" />
+ <Compile Include="EFRepository.cs" />
+ <Compile Include="Helpers\IRepositoryProvider.cs" />
+ <Compile Include="Helpers\PredicateBuilder.cs" />
+ <Compile Include="Helpers\RepositoryFactories.cs" />
+ <Compile Include="Helpers\RepositoryProvider.cs" />
+ <Compile Include="PersonsRepository.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SampleData\CodeCamperDatabaseInitializer.cs" />
<Compile Include="SampleData\PeopleNames.cs" />
@@ -58,8 +66,13 @@
<Compile Include="SampleData\SampleTrack.cs" />
<Compile Include="SampleData\TagsGenerator.cs" />
<Compile Include="SampleData\TheChosen.cs" />
+ <Compile Include="SessionsRepository.cs" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\CodeCamper.Data.Contracts\CodeCamper.Data.Contracts.csproj">
+ <Project>{95635373-151d-4f6c-87cb-65ba24c6e2c1}</Project>
+ <Name>CodeCamper.Data.Contracts</Name>
+ </ProjectReference>
<ProjectReference Include="..\CodeCamper.Model\CodeCamper.Model.csproj">
<Project>{353810b1-c8cb-4a8b-86bc-f74929a1bf57}</Project>
<Name>CodeCamper.Model</Name>
105 CodeCamper.Data/CodeCamperUow.cs
View
@@ -0,0 +1,105 @@
+using System;
+using CodeCamper.Data.Contracts;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data
+{
+ /// <summary>
+ /// The Code Camper "Unit of Work"
+ /// 1) decouples the repos from the controllers
+ /// 2) decouples the DbContext and EF from the controllers
+ /// 3) manages the UoW
+ /// </summary>
+ /// <remarks>
+ /// This class implements the "Unit of Work" pattern in which
+ /// the "UoW" serves as a facade for querying and saving to the database.
+ /// Querying is delegated to "repositories".
+ /// Each repository serves as a container dedicated to a particular
+ /// root entity type such as a <see cref="Person"/>.
+ /// A repository typically exposes "Get" methods for querying and
+ /// will offer add, update, and delete methods if those features are supported.
+ /// The repositories rely on their parent UoW to provide the interface to the
+ /// data layer (which is the EF DbContext in Code Camper).
+ /// </remarks>
+ public class CodeCamperUow : ICodeCamperUow, IDisposable
+ {
+ public CodeCamperUow(IRepositoryProvider repositoryProvider)
+ {
+ CreateDbContext();
+
+ repositoryProvider.DbContext = DbContext;
+ RepositoryProvider = repositoryProvider;
+ }
+
+ // Code Camper repositories
+
+ public IRepository<Room> Rooms { get { return GetStandardRepo<Room>(); } }
+ public IRepository<TimeSlot> TimeSlots { get { return GetStandardRepo<TimeSlot>(); } }
+ public IRepository<Track> Tracks { get { return GetStandardRepo<Track>(); } }
+ public ISessionsRepository Sessions { get { return GetRepo<ISessionsRepository>(); } }
+ public IPersonsRepository Persons { get { return GetRepo<IPersonsRepository>(); } }
+ public IAttendanceRepository Attendance { get { return GetRepo<IAttendanceRepository>(); } }
+
+ /// <summary>
+ /// Save pending changes to the database
+ /// </summary>
+ public void Commit()
+ {
+ //System.Diagnostics.Debug.WriteLine("Committed");
+ DbContext.SaveChanges();
+ }
+
+ protected void CreateDbContext()
+ {
+ DbContext = new CodeCamperDbContext();
+
+ // Do NOT enable proxied entities, else serialization fails
+ DbContext.Configuration.ProxyCreationEnabled = false;
+
+ // Load navigation properties explicitly (avoid serialization trouble)
+ DbContext.Configuration.LazyLoadingEnabled = false;
+
+ // Because Web API will perform validation, we don't need/want EF to do so
+ DbContext.Configuration.ValidateOnSaveEnabled = false;
+
+ //DbContext.Configuration.AutoDetectChangesEnabled = false;
+ // We won't use this performance tweak because we don't need
+ // the extra performance and, when autodetect is false,
+ // we'd have to be careful. We're not being that careful.
+ }
+
+ protected IRepositoryProvider RepositoryProvider { get; set; }
+
+ private IRepository<T> GetStandardRepo<T>() where T : class
+ {
+ return RepositoryProvider.GetRepositoryForEntityType<T>();
+ }
+ private T GetRepo<T>() where T : class
+ {
+ return RepositoryProvider.GetRepository<T>();
+ }
+
+ private CodeCamperDbContext DbContext { get; set; }
+
+ #region IDisposable
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (DbContext != null)
+ {
+ DbContext.Dispose();
+ }
+ }
+ }
+
+ #endregion
+ }
+}
83 CodeCamper.Data/EFRepository.cs
View
@@ -0,0 +1,83 @@
+using System;
+using System.Data;
+using System.Data.Entity;
+using System.Data.Entity.Infrastructure;
+using System.Linq;
+using CodeCamper.Data.Contracts;
+
+namespace CodeCamper.Data
+{
+ /// <summary>
+ /// The EF-dependent, generic repository for data access
+ /// </summary>
+ /// <typeparam name="T">Type of entity for this Repository.</typeparam>
+ public class EFRepository<T> : IRepository<T> where T : class
+ {
+ public EFRepository(DbContext dbContext)
+ {
+ if (dbContext == null)
+ throw new ArgumentNullException("dbContext");
+ DbContext = dbContext;
+ DbSet = DbContext.Set<T>();
+ }
+
+ protected DbContext DbContext { get; set; }
+
+ protected DbSet<T> DbSet { get; set; }
+
+ public virtual IQueryable<T> GetAll()
+ {
+ return DbSet;
+ }
+
+ public virtual T GetById(int id)
+ {
+ //return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
+ return DbSet.Find(id);
+ }
+
+ public virtual void Add(T entity)
+ {
+ DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
+ if (dbEntityEntry.State != EntityState.Detached)
+ {
+ dbEntityEntry.State = EntityState.Added;
+ }
+ else
+ {
+ DbSet.Add(entity);
+ }
+ }
+
+ public virtual void Update(T entity)
+ {
+ DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
+ if (dbEntityEntry.State == EntityState.Detached)
+ {
+ DbSet.Attach(entity);
+ }
+ dbEntityEntry.State = EntityState.Modified;
+ }
+
+ public virtual void Delete(T entity)
+ {
+ DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
+ if (dbEntityEntry.State != EntityState.Deleted)
+ {
+ dbEntityEntry.State = EntityState.Deleted;
+ }
+ else
+ {
+ DbSet.Attach(entity);
+ DbSet.Remove(entity);
+ }
+ }
+
+ public virtual void Delete(int id)
+ {
+ var entity = GetById(id);
+ if (entity == null) return; // not found; assume already deleted.
+ Delete(entity);
+ }
+ }
+}
60 CodeCamper.Data/Helpers/IRepositoryProvider.cs
View
@@ -0,0 +1,60 @@
+using System;
+using System.Data.Entity;
+using CodeCamper.Data.Contracts;
+
+namespace CodeCamper.Data
+{
+ /// <summary>
+ /// Interface for a class that can provide repositories by type.
+ /// The class may create the repositories dynamically if it is unable
+ /// to find one in its cache of repositories.
+ /// </summary>
+ /// <remarks>
+ /// Repositories created by this provider tend to require a <see cref="DbContext"/>
+ /// to retrieve data.
+ /// </remarks>
+ public interface IRepositoryProvider
+ {
+ /// <summary>
+ /// Get and set the <see cref="DbContext"/> with which to initialize a repository
+ /// if one must be created.
+ /// </summary>
+ DbContext DbContext { get; set; }
+
+ /// <summary>
+ /// Get an <see cref="IRepository{T}"/> for entity type, T.
+ /// </summary>
+ /// <typeparam name="T">
+ /// Root entity type of the <see cref="IRepository{T}"/>.
+ /// </typeparam>
+ IRepository<T> GetRepositoryForEntityType<T>() where T : class;
+
+ /// <summary>
+ /// Get a repository of type T.
+ /// </summary>
+ /// <typeparam name="T">
+ /// Type of the repository, typically a custom repository interface.
+ /// </typeparam>
+ /// <param name="factory">
+ /// An optional repository creation function that takes a <see cref="DbContext"/>
+ /// and returns a repository of T. Used if the repository must be created.
+ /// </param>
+ /// <remarks>
+ /// Looks for the requested repository in its cache, returning if found.
+ /// If not found, tries to make one with the factory, fallingback to
+ /// a default factory if the factory parameter is null.
+ /// </remarks>
+ T GetRepository<T>(Func<DbContext, object> factory = null) where T : class;
+
+
+ /// <summary>
+ /// Set the repository to return from this provider.
+ /// </summary>
+ /// <remarks>
+ /// Set a repository if you don't want this provider to create one.
+ /// Useful in testing and when developing without a backend
+ /// implementation of the object returned by a repository of type T.
+ /// </remarks>
+ void SetRepository<T>(T repository);
+ }
+}
33 CodeCamper.Data/Helpers/PredicateBuilder.cs
View
@@ -0,0 +1,33 @@
+using System;
+using System.Linq.Expressions;
+
+namespace CodeCamper.Data
+{
+ public static class PredicateBuilder
+ {
+ /// <summary>
+ /// Produces a predicate for IQueryable LINQ "Where" clause that queries by id for specific value,
+ /// </summary>
+ /// <typeparam name="T">The type to query which must have an int property named "Id".</typeparam>
+ /// <param name="id">The int value of the id of the desired entity.</param>
+ /// <returns>An predicate expression suitable for a LINQ "Where" or "First" clause.</returns>
+ /// <remarks>
+ /// See <see cref="Model.IRepository{T}.GetById"/> for usage.
+ /// </remarks>
+ /// <Example>
+ /// If T is a Foo and Foo.Id is of type int, then
+ /// var predicate = GetByIdPredicate{T}(42) returns the equivalent of
+ /// "f => f.Id == 42" and can be used to get the Foo with Id==42 by writing
+ /// aFooDbSet.FirstOrDefault(predicate)".
+ /// </Example>
+ public static Expression<Func<T, bool>> GetByIdPredicate<T>(int id)
+ {
+ var itemParam = Expression.Parameter(typeof(T), "item");
+ var itemPropertyExpr = Expression.Property(itemParam, "Id");
+ var idParam = Expression.Constant(id);
+ var newBody = Expression.MakeBinary(ExpressionType.Equal, itemPropertyExpr, idParam);
+ var newLambda = Expression.Lambda(newBody, itemParam);
+ return newLambda as Expression<Func<T, bool>>;
+ }
+ }
+}
119 CodeCamper.Data/Helpers/RepositoryFactories.cs
View
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using CodeCamper.Data.Contracts;
+
+namespace CodeCamper.Data
+{
+ /// <summary>
+ /// A maker of Code Camper Repositories.
+ /// </summary>
+ /// <remarks>
+ /// An instance of this class contains repository factory functions for different types.
+ /// Each factory function takes an EF <see cref="DbContext"/> and returns
+ /// a repository bound to that DbContext.
+ /// <para>
+ /// Designed to be a "Singleton", configured at web application start with
+ /// all of the factory functions needed to create any type of repository.
+ /// Should be thread-safe to use because it is configured at app start,
+ /// before any request for a factory, and should be immutable thereafter.
+ /// </para>
+ /// </remarks>
+ public class RepositoryFactories
+ {
+ /// <summary>
+ /// Return the runtime Code Camper repository factory functions,
+ /// each one is a factory for a repository of a particular type.
+ /// </summary>
+ /// <remarks>
+ /// MODIFY THIS METHOD TO ADD CUSTOM CODE CAMPER FACTORY FUNCTIONS
+ /// </remarks>
+ private IDictionary<Type, Func<DbContext, object>> GetCodeCamperFactories()
+ {
+ return new Dictionary<Type, Func<DbContext, object>>
+ {
+ {typeof(IAttendanceRepository), dbContext => new AttendanceRepository(dbContext)},
+ {typeof(IPersonsRepository), dbContext => new PersonsRepository(dbContext)},
+ {typeof(ISessionsRepository), dbContext => new SessionsRepository(dbContext)},
+ };
+ }
+
+ /// <summary>
+ /// Constructor that initializes with runtime Code Camper repository factories
+ /// </summary>
+ public RepositoryFactories()
+ {
+ _repositoryFactories = GetCodeCamperFactories();
+ }
+
+ /// <summary>
+ /// Constructor that initializes with an arbitrary collection of factories
+ /// </summary>
+ /// <param name="factories">
+ /// The repository factory functions for this instance.
+ /// </param>
+ /// <remarks>
+ /// This ctor is primarily useful for testing this class
+ /// </remarks>
+ public RepositoryFactories(IDictionary<Type, Func<DbContext, object>> factories )
+ {
+ _repositoryFactories = factories;
+ }
+
+ /// <summary>
+ /// Get the repository factory function for the type.
+ /// </summary>
+ /// <typeparam name="T">Type serving as the repository factory lookup key.</typeparam>
+ /// <returns>The repository function if found, else null.</returns>
+ /// <remarks>
+ /// The type parameter, T, is typically the repository type
+ /// but could be any type (e.g., an entity type)
+ /// </remarks>
+ public Func<DbContext, object> GetRepositoryFactory<T>()
+ {
+
+ Func<DbContext, object> factory;
+ _repositoryFactories.TryGetValue(typeof(T), out factory);
+ return factory;
+ }
+
+ /// <summary>
+ /// Get the factory for <see cref="IRepository{T}"/> where T is an entity type.
+ /// </summary>
+ /// <typeparam name="T">The root type of the repository, typically an entity type.</typeparam>
+ /// <returns>
+ /// A factory that creates the <see cref="IRepository{T}"/>, given an EF <see cref="DbContext"/>.
+ /// </returns>
+ /// <remarks>
+ /// Looks first for a custom factory in <see cref="_repositoryFactories"/>.
+ /// If not, falls back to the <see cref="DefaultEntityRepositoryFactory{T}"/>.
+ /// You can substitute an alternative factory for the default one by adding
+ /// a repository factory for type "T" to <see cref="_repositoryFactories"/>.
+ /// </remarks>
+ public Func<DbContext, object> GetRepositoryFactoryForEntityType<T>() where T : class
+ {
+ return GetRepositoryFactory<T>() ?? DefaultEntityRepositoryFactory<T>();
+ }
+
+ /// <summary>
+ /// Default factory for a <see cref="IRepository{T}"/> where T is an entity.
+ /// </summary>
+ /// <typeparam name="T">Type of the repository's root entity</typeparam>
+ protected virtual Func<DbContext, object> DefaultEntityRepositoryFactory<T>() where T : class
+ {
+ return dbContext => new EFRepository<T>(dbContext);
+ }
+
+ /// <summary>
+ /// Get the dictionary of repository factory functions.
+ /// </summary>
+ /// <remarks>
+ /// A dictionary key is a System.Type, typically a repository type.
+ /// A value is a repository factory function
+ /// that takes a <see cref="DbContext"/> argument and returns
+ /// a repository object. Caller must know how to cast it.
+ /// </remarks>
+ private readonly IDictionary<Type, Func<DbContext, object>> _repositoryFactories;
+
+ }
+}
128 CodeCamper.Data/Helpers/RepositoryProvider.cs
View
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using CodeCamper.Data.Contracts;
+
+namespace CodeCamper.Data
+{
+ /// <summary>
+ /// Provides an <see cref="IRepository{T}"/> for a client request.
+ /// </summary>
+ /// <remarks>
+ /// Caches repositories of a given type so that repositories are only created once per provider.
+ /// Code Camper creates a new provider per client request.
+ /// </remarks>
+ public class RepositoryProvider : IRepositoryProvider
+ {
+ public RepositoryProvider(RepositoryFactories repositoryFactories)
+ {
+ _repositoryFactories = repositoryFactories;
+ Repositories = new Dictionary<Type, object>();
+ }
+
+ /// <summary>
+ /// Get and set the <see cref="DbContext"/> with which to initialize a repository
+ /// if one must be created.
+ /// </summary>
+ public DbContext DbContext { get; set; }
+
+ /// <summary>
+ /// Get or create-and-cache the default <see cref="IRepository{T}"/> for an entity of type T.
+ /// </summary>
+ /// <typeparam name="T">
+ /// Root entity type of the <see cref="IRepository{T}"/>.
+ /// </typeparam>
+ /// <remarks>
+ /// If can't find repository in cache, use a factory to create one.
+ /// </remarks>
+ public IRepository<T> GetRepositoryForEntityType<T>() where T : class
+ {
+ return GetRepository<IRepository<T>>(
+ _repositoryFactories.GetRepositoryFactoryForEntityType<T>());
+ }
+
+ /// <summary>
+ /// Get or create-and-cache a repository of type T.
+ /// </summary>
+ /// <typeparam name="T">
+ /// Type of the repository, typically a custom repository interface.
+ /// </typeparam>
+ /// <param name="factory">
+ /// An optional repository creation function that takes a DbContext argument
+ /// and returns a repository of T. Used if the repository must be created and
+ /// caller wants to specify the specific factory to use rather than one
+ /// of the injected <see cref="RepositoryFactories"/>.
+ /// </param>
+ /// <remarks>
+ /// Looks for the requested repository in its cache, returning if found.
+ /// If not found, tries to make one using <see cref="MakeRepository{T}"/>.
+ /// </remarks>
+ public virtual T GetRepository<T>(Func<DbContext, object> factory = null) where T : class
+ {
+ // Look for T dictionary cache under typeof(T).
+ object repoObj;
+ Repositories.TryGetValue(typeof(T), out repoObj);
+ if (repoObj != null)
+ {
+ return (T)repoObj;
+ }
+
+ // Not found or null; make one, add to dictionary cache, and return it.
+ return MakeRepository<T>(factory, DbContext);
+ }
+
+ /// <summary>
+ /// Get the dictionary of repository objects, keyed by repository type.
+ /// </summary>
+ /// <remarks>
+ /// Caller must know how to cast the repository object to a useful type.
+ /// <p>This is an extension point. You can register fully made repositories here
+ /// and they will be used instead of the ones this provider would otherwise create.</p>
+ /// </remarks>
+ protected Dictionary<Type, object> Repositories { get; private set; }
+
+ /// <summary>Make a repository of type T.</summary>
+ /// <typeparam name="T">Type of repository to make.</typeparam>
+ /// <param name="dbContext">
+ /// The <see cref="DbContext"/> with which to initialize the repository.
+ /// </param>
+ /// <param name="factory">
+ /// Factory with <see cref="DbContext"/> argument. Used to make the repository.
+ /// If null, gets factory from <see cref="_repositoryFactories"/>.
+ /// </param>
+ /// <returns></returns>
+ protected virtual T MakeRepository<T>(Func<DbContext, object> factory, DbContext dbContext)
+ {
+ var f = factory ?? _repositoryFactories.GetRepositoryFactory<T>();
+ if (f == null)
+ {
+ throw new NotImplementedException("No factory for repository type, " + typeof(T).FullName);
+ }
+ var repo = (T)f(dbContext);
+ Repositories[typeof(T)] = repo;
+ return repo;
+ }
+
+ /// <summary>
+ /// Set the repository for type T that this provider should return.
+ /// </summary>
+ /// <remarks>
+ /// Plug in a custom repository if you don't want this provider to create one.
+ /// Useful in testing and when developing without a backend
+ /// implementation of the object returned by a repository of type T.
+ /// </remarks>
+ public void SetRepository<T>(T repository)
+ {
+ Repositories[typeof(T)] = repository;
+ }
+
+ /// <summary>
+ /// The <see cref="RepositoryFactories"/> with which to create a new repository.
+ /// </summary>
+ /// <remarks>
+ /// Should be initialized by constructor injection
+ /// </remarks>
+ private RepositoryFactories _repositoryFactories;
+
+ }
+}
35 CodeCamper.Data/PersonsRepository.cs
View
@@ -0,0 +1,35 @@
+using System.Data.Entity;
+using System.Linq;
+using CodeCamper.Data.Contracts;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data
+{
+ public class PersonsRepository : EFRepository<Person>, IPersonsRepository
+ {
+ public PersonsRepository(DbContext context) : base(context) { }
+
+ /// <summary>
+ /// Get <see cref="Speaker"/>s at sessions.
+ /// </summary>
+ ///<remarks>
+ ///See <see cref="IPersonsRepository.GetSpeakers"/> for details.
+ ///</remarks>
+
+ public IQueryable<Speaker> GetSpeakers()
+ {
+ return DbContext
+ .Set<Session>()
+ .Select(session => session.Speaker)
+ .Distinct().Select(s =>
+ new Speaker
+ {
+ Id = s.Id,
+ FirstName = s.FirstName,
+ LastName = s.LastName,
+ ImageSource = s.ImageSource,
+ });
+
+ }
+ }
+}
77 CodeCamper.Data/SessionsRepository.cs
View
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Linq;
+using CodeCamper.Data.Contracts;
+using CodeCamper.Model;
+
+namespace CodeCamper.Data
+{
+ public class SessionsRepository : EFRepository<Session>, ISessionsRepository
+ {
+ public SessionsRepository(DbContext context) : base(context) { }
+
+ /// <summary>
+ /// Get <see cref="SessionBrief"/>s,
+ /// a cutdown version of <see cref="Session"/> entities.
+ /// </summary>
+ ///<remarks>
+ ///See <see cref="ISessionsRepository.GetSessionBriefs"/> for details.
+ ///</remarks>
+ public IQueryable<SessionBrief> GetSessionBriefs()
+ {
+ return DbSet.Select(s => new SessionBrief
+ {
+ Id = s.Id,
+ Title = s.Title,
+ Code = s.Code,
+ SpeakerId = s.SpeakerId,
+ TrackId = s.TrackId,
+ TimeSlotId = s.TimeSlotId,
+ RoomId = s.RoomId,
+ Level = s.Level,
+ Tags = s.Tags,
+ });
+ }
+
+ /// <summary>
+ /// Get the unique tags from all of the sessions
+ /// as a list of <see cref="TagGroup"/>.
+ /// </summary>
+ /// <remarks>
+ ///See <see cref="ISessionsRepository.GetTagGroups"/> for details.
+ /// </remarks>
+ public IEnumerable<TagGroup> GetTagGroups()
+ {
+
+ var tagGroups =
+ // extract the delimited tags string and session id from all sessions
+ DbSet.Select(s => new { s.Tags, s.Id })
+ .ToArray() // we'll process them in memory.
+
+ // split the "Tags" string into individual tags
+ // and flatten into {tag, id} pairs
+ .SelectMany(
+ s =>
+ s.Tags.Split(_tagDelimiter, StringSplitOptions.RemoveEmptyEntries)
+ .Select(t => new { Tag = t, s.Id })
+ )
+
+ // group {tag, id} by tag into unique {tag, [session-id-array]}
+ .GroupBy(g => g.Tag, data => data.Id)
+
+ // project the group into TagGroup instances
+ // ensuring that ids array in each array are unique
+ .Select(tg => new TagGroup
+ {
+ Tag = tg.Key,
+ Ids = tg.Distinct().ToArray(),
+ })
+ .OrderBy(tg => tg.Tag);
+
+ return tagGroups;
+ }
+
+ private readonly char[] _tagDelimiter = new[] { '|' };
+ }
+}
6 CodeCamper.Web.sln
View
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCamper.Model", "CodeCam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCamper.Data", "CodeCamper.Data\CodeCamper.Data.csproj", "{CFB5CCDB-8F5F-4F67-8F7F-E571523ED384}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCamper.Data.Contracts", "CodeCamper.Data.Contracts\CodeCamper.Data.Contracts.csproj", "{95635373-151D-4F6C-87CB-65BA24C6E2C1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,6 +19,10 @@ Global
{353810B1-C8CB-4A8B-86BC-F74929A1BF57}.Debug|Any CPU.Build.0 = Debug|Any CPU
{353810B1-C8CB-4A8B-86BC-F74929A1BF57}.Release|Any CPU.ActiveCfg = Release|Any CPU
{353810B1-C8CB-4A8B-86BC-F74929A1BF57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {95635373-151D-4F6C-87CB-65BA24C6E2C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {95635373-151D-4F6C-87CB-65BA24C6E2C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95635373-151D-4F6C-87CB-65BA24C6E2C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {95635373-151D-4F6C-87CB-65BA24C6E2C1}.Release|Any CPU.Build.0 = Release|Any CPU
{96511E6F-DD27-44A8-AD7E-002699F5AE87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96511E6F-DD27-44A8-AD7E-002699F5AE87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96511E6F-DD27-44A8-AD7E-002699F5AE87}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 CodeCamper.Web/App_Start/GlobalConfig.cs
View
@@ -0,0 +1,26 @@
+using System.Web.Http;
+using Newtonsoft.Json.Serialization;
+
+namespace CodeCamper.Web
+{
+ public static class GlobalConfig
+ {
+ public static void CustomizeConfig(HttpConfiguration config)
+ {
+ // Remove Xml formatters. This means when we visit an endpoint from a browser,
+ // Instead of returning Xml, it will return Json.
+ // More information from Dave Ward: http://jpapa.me/P4vdx6
+ config.Formatters.Remove(config.Formatters.XmlFormatter);
+
+ // Configure json camelCasing per the following post: http://jpapa.me/NqC2HH
+ // Here we configure it to write JSON property names with camel casing
+ // without changing our server-side data model:
+ var json = config.Formatters.JsonFormatter;
+ json.SerializerSettings.ContractResolver =
+ new CamelCasePropertyNamesContractResolver();
+
+ // Add model validation, globally
+ config.Filters.Add(new ValidationActionFilter());
+ }
+ }
+}
27 CodeCamper.Web/App_Start/IocConfig.cs
View
@@ -0,0 +1,27 @@
+using System.Web.Http;
+using CodeCamper.Data;
+using CodeCamper.Data.Contracts;
+using Ninject;
+
+namespace CodeCamper.Web
+{
+ public class IocConfig
+ {
+ public static void RegisterIoc(HttpConfiguration config)
+ {
+ var kernel = new StandardKernel(); // Ninject IoC
+
+ // These registrations are "per instance request".
+ // See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/
+
+ kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()
+ .InSingletonScope();
+
+ kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
+ kernel.Bind<ICodeCamperUow>().To<CodeCamperUow>();
+
+ // Tell WebApi how to use our Ninject IoC
+ config.DependencyResolver = new NinjectDependencyResolver(kernel);
+ }
+ }
+}
21 CodeCamper.Web/App_Start/NinjectDependencyResolver.cs
View
@@ -0,0 +1,21 @@
+using System.Web.Http.Dependencies;
+using Ninject;
+
+namespace CodeCamper.Web
+{
+ public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
+ {
+ private IKernel kernel;
+
+ public NinjectDependencyResolver(IKernel kernel)
+ : base(kernel)
+ {
+ this.kernel = kernel;
+ }
+
+ public IDependencyScope BeginScope()
+ {
+ return new NinjectDependencyScope(kernel.BeginBlock());
+ }
+ }
+}
46 CodeCamper.Web/App_Start/NinjectDependencyScope.cs
View
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Web.Http.Dependencies;
+using Ninject;
+using Ninject.Syntax;
+
+namespace CodeCamper.Web
+{
+ public class NinjectDependencyScope : IDependencyScope
+ {
+ private IResolutionRoot resolver;
+
+ internal NinjectDependencyScope(IResolutionRoot resolver)
+ {
+ Contract.Assert(resolver != null);
+
+ this.resolver = resolver;
+ }
+
+ public void Dispose()
+ {
+ var disposable = resolver as IDisposable;
+ if (disposable != null)
+ disposable.Dispose();
+
+ resolver = null;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ if (resolver == null)
+ throw new ObjectDisposedException("this", "This scope has already been disposed");
+
+ return resolver.TryGet(serviceType);
+ }
+
+ public IEnumerable<object> GetServices(Type serviceType)
+ {
+ if (resolver == null)
+ throw new ObjectDisposedException("this", "This scope has already been disposed");
+
+ return resolver.GetAll(serviceType);
+ }
+ }
+}
31 CodeCamper.Web/App_Start/ValidationActionFilter.cs
View
@@ -0,0 +1,31 @@
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Web.Http.Controllers;
+using System.Web.Http.Filters;
+using Newtonsoft.Json.Linq;
+
+namespace CodeCamper.Web
+{
+ public class ValidationActionFilter : ActionFilterAttribute
+ {
+ public override void OnActionExecuting(HttpActionContext context)
+ {
+ var modelState = context.ModelState;
+ if (!modelState.IsValid)
+ {
+ var errors = new JObject();
+ foreach (var key in modelState.Keys)
+ {
+ var state = modelState[key];
+ if (state.Errors.Any())
+ {
+ errors[key] = state.Errors.First().ErrorMessage;
+ }
+ }
+
+ context.Response = context.Request.CreateResponse<JObject>(HttpStatusCode.BadRequest, errors);
+ }
+ }
+ }
+}
12 CodeCamper.Web/CodeCamper.Web.csproj
View
@@ -40,6 +40,9 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
+ <Reference Include="Ninject">
+ <HintPath>..\packages\Ninject.3.0.1.10\lib\net45-full\Ninject.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Data.Entity" />
@@ -124,7 +127,12 @@
<ItemGroup>
<Compile Include="App_Start\BundleConfig.cs" />
<Compile Include="App_Start\FilterConfig.cs" />
+ <Compile Include="App_Start\GlobalConfig.cs" />
+ <Compile Include="App_Start\IocConfig.cs" />
+ <Compile Include="App_Start\NinjectDependencyResolver.cs" />
+ <Compile Include="App_Start\NinjectDependencyScope.cs" />
<Compile Include="App_Start\RouteConfig.cs" />
+ <Compile Include="App_Start\ValidationActionFilter.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\ValuesController.cs" />
<Compile Include="Global.asax.cs">
@@ -233,6 +241,10 @@
<Content Include="packages.config" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\CodeCamper.Data.Contracts\CodeCamper.Data.Contracts.csproj">
+ <Project>{95635373-151d-4f6c-87cb-65ba24c6e2c1}</Project>
+ <Name>CodeCamper.Data.Contracts</Name>
+ </ProjectReference>
<ProjectReference Include="..\CodeCamper.Data\CodeCamper.Data.csproj">
<Project>{cfb5ccdb-8f5f-4f67-8f7f-e571523ed384}</Project>
<Name>CodeCamper.Data</Name>
6 CodeCamper.Web/Global.asax.cs
View
@@ -21,9 +21,15 @@ protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
+ // Tell WebApi to use our custom Ioc (Ninject)
+ IocConfig.RegisterIoc(GlobalConfiguration.Configuration);
+
+ // Web API template created these 3
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
+
+ GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
}
}
}
1  CodeCamper.Web/packages.config
View
@@ -21,6 +21,7 @@
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Modernizr" version="2.0.6" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.1" targetFramework="net45" />
+ <package id="Ninject" version="3.0.1.10" targetFramework="net45" />
<package id="toastr" version="1.0.2" targetFramework="net45" />
<package id="WebGrease" version="1.0.0" targetFramework="net45" />
</packages>
BIN  packages/Ninject.3.0.1.10/Ninject.3.0.1.10.nupkg
View
Binary file not shown
BIN  packages/Ninject.3.0.1.10/lib/net35/Ninject.dll
View
Binary file not shown
6,209 packages/Ninject.3.0.1.10/lib/net35/Ninject.xml
View
6,209 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/net40/Ninject.dll
View
Binary file not shown
6,157 packages/Ninject.3.0.1.10/lib/net40/Ninject.xml
View
6,157 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/net45-full/Ninject.dll
View
Binary file not shown
6,157 packages/Ninject.3.0.1.10/lib/net45-full/Ninject.xml
View
6,157 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl2/Ninject.dll
View
Binary file not shown
6,120 packages/Ninject.3.0.1.10/lib/sl2/Ninject.xml
View
6,120 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl3-wp/Ninject.dll
View
Binary file not shown
6,071 packages/Ninject.3.0.1.10/lib/sl3-wp/Ninject.xml
View
6,071 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl3/Ninject.dll
View
Binary file not shown
6,120 packages/Ninject.3.0.1.10/lib/sl3/Ninject.xml
View
6,120 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl4-windowsphone71/Ninject.dll
View
Binary file not shown
6,019 packages/Ninject.3.0.1.10/lib/sl4-windowsphone71/Ninject.xml
View
6,019 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl4/Ninject.dll
View
Binary file not shown
6,068 packages/Ninject.3.0.1.10/lib/sl4/Ninject.xml
View
6,068 additions, 0 deletions not shown
BIN  packages/Ninject.3.0.1.10/lib/sl5/Ninject.dll
View
Binary file not shown
6,068 packages/Ninject.3.0.1.10/lib/sl5/Ninject.xml
View
6,068 additions, 0 deletions not shown
Please sign in to comment.
Something went wrong with that request. Please try again.