Basic working & complete tests

This commit is contained in:
Biarity 2018-01-27 15:20:57 +10:00
parent 37a6f9f70d
commit 0f7ecfb36c
21 changed files with 509 additions and 141 deletions

View File

@ -5,7 +5,7 @@ using System.Text;
namespace Sieve.Attributes namespace Sieve.Attributes
{ {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class SieveAttribute : Attribute public class SieveAttribute : Attribute
{ {
/// <summary> /// <summary>
/// Override name used /// Override name used

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Sieve.Extensions
{
public static partial class LinqExtentions
{
public static IQueryable<TEntity> OrderByDynamic<TEntity>(this IQueryable<TEntity> source, string orderByProperty,
bool desc, bool useThenBy)
{
string command = desc ?
( useThenBy ? "ThenByDescending" : "OrderByDescending") :
( useThenBy ? "ThenBy" : "OrderBy");
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return source.Provider.CreateQuery<TEntity>(resultExpression);
}
}
}

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Sieve.Extensions
{
public static class LinqExtensions
{
public static IOrderedEnumerable<TSource> OrderByWithDirection<TSource, TKey>
(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
public static IOrderedQueryable<TSource> OrderByWithDirection<TSource, TKey>
(this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> keySelector,
bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
}
}

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text; using System.Text;
@ -8,13 +7,40 @@ namespace Sieve.Models
{ {
public class FilterTerm public class FilterTerm
{ {
public string Name { get; set; } private string _filter;
public string Operator { get; set; } public FilterTerm(string filter)
{
_filter = filter;
}
public string Name
{
get
{
return _filter.Split(' ')[0];
}
}
public string Operator
{
get
{
return _filter.Split(' ')[1];
}
}
public string Value {
get
{
return _filter.Split(' ')[2];
}
}
[BindNever]
public FilterOperator OperatorParsed { public FilterOperator OperatorParsed {
get { get
{
switch (Operator.Trim().ToLower()) switch (Operator.Trim().ToLower())
{ {
case "equals": case "equals":
@ -51,8 +77,5 @@ namespace Sieve.Models
} }
} }
public string Value { get; set; }
public bool Descending { get; set; } = false;
} }
} }

View File

@ -7,14 +7,55 @@ namespace Sieve.Models
{ {
public class SieveModel public class SieveModel
{ {
public IEnumerable<FilterTerm> Filter { get; set; } public string Filters { get; set; }
public IEnumerable<SortTerm> Sort { get; set; } public string Sorts { get; set; }
[Range(1, Double.MaxValue)] [Range(1, Double.MaxValue)]
public int Page { get; set; } = 1; public int? Page { get; set; }
[Range(1, Double.MaxValue)] [Range(1, Double.MaxValue)]
public int PageSize { get; set; } = 10; public int? PageSize { get; set; }
public List<FilterTerm> FilterParsed
{
get
{
if (Filters != null)
{
var value = new List<FilterTerm>();
foreach (var filter in Filters.Split(','))
{
value.Add(new FilterTerm(filter));
}
return value;
}
else
{
return null;
}
}
}
public List<SortTerm> SortParsed
{
get
{
if (Sorts != null)
{
var value = new List<SortTerm>();
foreach (var sort in Sorts.Split(','))
{
value.Add(new SortTerm(sort));
}
return value;
}
else
{
return null;
}
}
}
} }
} }

View File

@ -7,8 +7,41 @@ namespace Sieve.Models
{ {
public class SortTerm public class SortTerm
{ {
public string Name { get; set; } private string _sort;
public bool Descending { get; set; } = false; public SortTerm(string sort)
{
_sort = sort;
}
public string Name
{
get
{
if (_sort.StartsWith('-'))
{
return _sort.Substring(1);
}
else
{
return _sort;
}
}
}
public bool Descending
{
get
{
if (_sort.StartsWith('-'))
{
return true;
}
else
{
return false;
}
}
}
} }
} }

View File

@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using Sieve.Models;
namespace Sieve.Services
{
//public interface ISieveProcessor : ISieveProcessor<object> { }
public interface ISieveProcessor<TEntity> where TEntity : class
{
IQueryable<TEntity> ApplyAll(SieveModel model, IQueryable<TEntity> source);
IQueryable<TEntity> ApplySorting(SieveModel model, IQueryable<TEntity> result);
IQueryable<TEntity> ApplyFiltering(SieveModel model, IQueryable<TEntity> result);
IQueryable<TEntity> ApplyPagination(SieveModel model, IQueryable<TEntity> result);
}
}

View File

@ -5,19 +5,34 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Data.Entity;
using System.Reflection; using System.Reflection;
using Sieve.Attributes; using Sieve.Attributes;
using Sieve.Extensions; using Sieve.Extensions;
using System.ComponentModel;
using System.Collections;
using System.Linq.Expressions;
namespace Sieve.Services namespace Sieve.Services
{ {
public class SieveProcessor<TEntity> //public class SieveProcessor : SieveProcessor<object>, ISieveProcessor
//{
// public SieveProcessor(IOptions<SieveOptions> options, ISieveCustomSortMethods<object> customSortMethods, ISieveCustomFilterMethods<object> customFilterMethods) : base(options, customSortMethods, customFilterMethods)
// {
// }
//
// public SieveProcessor(IOptions<SieveOptions> options) : base(options)
// {
// }
//
//}
public class SieveProcessor<TEntity> : ISieveProcessor<TEntity>
where TEntity: class where TEntity: class
{ {
private IOptions<SieveOptions> _options; private IOptions<SieveOptions> _options;
private ISieveCustomSortMethods<TEntity> _customSortMethods; private ISieveCustomSortMethods<TEntity> _customSortMethods;
private ISieveCustomFilterMethods<TEntity> _customFilterMethods; private ISieveCustomFilterMethods<TEntity> _customFilterMethods;
public SieveProcessor(IOptions<SieveOptions> options, public SieveProcessor(IOptions<SieveOptions> options,
ISieveCustomSortMethods<TEntity> customSortMethods, ISieveCustomSortMethods<TEntity> customSortMethods,
@ -28,15 +43,23 @@ namespace Sieve.Services
_customFilterMethods = customFilterMethods; _customFilterMethods = customFilterMethods;
} }
public IEnumerable<TEntity> ApplyAll(SieveModel model, IQueryable<TEntity> source) public SieveProcessor(IOptions<SieveOptions> options)
{ {
var result = source.AsNoTracking(); _options = options;
}
public IQueryable<TEntity> ApplyAll(SieveModel model, IQueryable<TEntity> source)
{
var result = source;
if (model == null)
return result;
// Sort // Sort
result = ApplySort(model, result); result = ApplySorting(model, result);
// Filter // Filter
result = ApplyFilter(model, result); result = ApplyFiltering(model, result);
// Paginate // Paginate
result = ApplyPagination(model, result); result = ApplyPagination(model, result);
@ -44,84 +67,95 @@ namespace Sieve.Services
return result; return result;
} }
public IQueryable<TEntity> ApplySort(SieveModel model, IQueryable<TEntity> result) public IQueryable<TEntity> ApplySorting(SieveModel model, IQueryable<TEntity> result)
{ {
foreach (var sortTerm in model.Sort) if (model?.SortParsed == null)
return result;
var useThenBy = false;
foreach (var sortTerm in model.SortParsed)
{ {
var property = GetSieveProperty(true, false, sortTerm.Name); var property = GetSieveProperty(true, false, sortTerm.Name);
if (property != null) if (property != null)
{ {
result = result.OrderByWithDirection( result = result.OrderByDynamic(property.Name, sortTerm.Descending, useThenBy);
e => property.GetValue(e),
sortTerm.Descending);
} }
else else
{ {
var customMethod = _customSortMethods.GetType() result = ApplyCustomMethod(result, sortTerm.Name, _customSortMethods,
.GetMethod(sortTerm.Name); includeUseThenBy: true,
useThenBy: useThenBy);
if (customMethod != null)
{
result = result.OrderByWithDirection(
e => customMethod.Invoke(_customSortMethods, new object[] { e }),
sortTerm.Descending);
}
} }
useThenBy = true;
} }
return result; return result;
} }
public IQueryable<TEntity> ApplyFilter(SieveModel model, IQueryable<TEntity> result) public IQueryable<TEntity> ApplyFiltering(SieveModel model, IQueryable<TEntity> result)
{ {
foreach (var filterTerm in model.Filter) if (model?.FilterParsed == null)
return result;
foreach (var filterTerm in model.FilterParsed)
{ {
var property = GetSieveProperty(false, true, filterTerm.Name); var property = GetSieveProperty(false, true, filterTerm.Name);
if (property != null) if (property != null)
{ {
var filterValue = Convert.ChangeType(filterTerm.Value, property.GetType()); var converter = TypeDescriptor.GetConverter(property.PropertyType);
var parameter = Expression.Parameter(typeof(TEntity), "e");
var filterValue = Expression.Constant(
converter.CanConvertFrom(typeof(string)) ?
converter.ConvertFrom(filterTerm.Value) :
Convert.ChangeType(filterTerm.Value, property.PropertyType));
var propertyValue = Expression.PropertyOrField(parameter, property.Name);
Expression comparison;
switch (filterTerm.OperatorParsed) switch (filterTerm.OperatorParsed)
{ {
case FilterOperator.Equals: case FilterOperator.Equals:
result = result.Where(e => ((IComparable)property.GetValue(e)).Equals(filterValue)); comparison = Expression.Equal(propertyValue, filterValue);
break; break;
case FilterOperator.GreaterThan: case FilterOperator.GreaterThan:
result = result.Where(e => ((IComparable)property.GetValue(e)).CompareTo(filterValue) > 0); comparison = Expression.GreaterThan(propertyValue, filterValue);
break; break;
case FilterOperator.LessThan: case FilterOperator.LessThan:
result = result.Where(e => ((IComparable)property.GetValue(e)).CompareTo(filterValue) < 0); comparison = Expression.LessThan(propertyValue, filterValue);
break; break;
case FilterOperator.GreaterThanOrEqualTo: case FilterOperator.GreaterThanOrEqualTo:
result = result.Where(e => ((IComparable)property.GetValue(e)).CompareTo(filterValue) >= 0); comparison = Expression.GreaterThanOrEqual(propertyValue, filterValue);
break; break;
case FilterOperator.LessThanOrEqualTo: case FilterOperator.LessThanOrEqualTo:
result = result.Where(e => ((IComparable)property.GetValue(e)).CompareTo(filterValue) <= 0); comparison = Expression.LessThanOrEqual(propertyValue, filterValue);
break; break;
case FilterOperator.Contains: case FilterOperator.Contains:
result = result.Where(e => ((string)property.GetValue(e)).Contains((string)filterValue)); comparison = Expression.Call(propertyValue,
typeof(string).GetMethods()
.First(m => m.Name == "Contains" && m.GetParameters().Length == 1),
filterValue);
break; break;
case FilterOperator.StartsWith: case FilterOperator.StartsWith:
result = result.Where(e => ((string)property.GetValue(e)).StartsWith((string)filterValue)); comparison = Expression.Call(propertyValue,
break; typeof(string).GetMethods()
.First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1),
filterValue); break;
default: default:
result = result.Where(e => ((IComparable)property.GetValue(e)).Equals(filterValue)); comparison = Expression.Equal(propertyValue, filterValue);
break; break;
} }
result = result.Where(Expression.Lambda<Func<TEntity, bool>>(
comparison,
parameter));
} }
else else
{ {
var customMethod = _customFilterMethods.GetType() result = ApplyCustomMethod(result, filterTerm.Name, _customFilterMethods);
.GetMethod(filterTerm.Name);
if (customMethod != null)
{
result = result.Where(
e => (bool)customMethod.Invoke(_customFilterMethods, new object[] { e }));
}
} }
} }
@ -130,8 +164,11 @@ namespace Sieve.Services
public IQueryable<TEntity> ApplyPagination(SieveModel model, IQueryable<TEntity> result) public IQueryable<TEntity> ApplyPagination(SieveModel model, IQueryable<TEntity> result)
{ {
result = result.Skip((model.Page - 1) * model.PageSize) if (model?.Page == null || model?.PageSize == null)
.Take(model.PageSize); return result;
result = result.Skip((model.Page.Value - 1) * model.PageSize.Value)
.Take(model.PageSize.Value);
return result; return result;
} }
@ -147,5 +184,21 @@ namespace Sieve.Services
return false; return false;
}); });
} }
private IQueryable<TEntity> ApplyCustomMethod(IQueryable<TEntity> result, string name, object parent,
bool includeUseThenBy = false, bool useThenBy = false)
{
var customMethod = parent?.GetType()
.GetMethod(name);
if (customMethod != null)
{
var parameters = includeUseThenBy ? new object[] { result, useThenBy } : new object[] { result };
result = customMethod.Invoke(parent, parameters)
as IQueryable<TEntity>;
}
return result;
}
} }
} }

View File

@ -5,8 +5,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EntityFramework" Version="6.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Sieve.Models;
using Sieve.Services;
using SieveTests.Entities;
namespace SieveTests.Controllers
{
[Route("api/[controller]/[action]")]
public class TestController : Controller
{
private ISieveProcessor<Post> _sieveProcessor;
private ApplicationDbContext _dbContext;
public TestController(ISieveProcessor<Post> sieveProcessor,
ApplicationDbContext dbContext)
{
_sieveProcessor = sieveProcessor;
_dbContext = dbContext;
}
[HttpGet]
public JsonResult GetAllWithSieve(SieveModel sieveModel)
{
var result = _dbContext.Posts.AsNoTracking();
result = _sieveProcessor.ApplyAll(sieveModel, result);
return Json(result.ToList());
}
[HttpGet]
public JsonResult Create(int number = 10)
{
for (int i = 0; i < number; i++)
{
_dbContext.Posts.Add(new Post());
}
_dbContext.SaveChanges();
return Json(_dbContext.Posts.ToList());
}
[HttpGet]
public JsonResult GetAll()
{
return Json(_dbContext.Posts.ToList());
}
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace SieveTests.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}

View File

@ -0,0 +1,20 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SieveTests.Entities
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Sieve.Attributes;
namespace SieveTests.Entities
{
public class Post
{
public int Id { get; set; }
[Sieve(CanFilter = true, CanSort = true)]
public string Title { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 8);
[Sieve(CanFilter = true, CanSort = true)]
public int LikeCount { get; set; } = new Random().Next(0, 1000);
[Sieve(CanFilter = true, CanSort = true)]
public int CommentCount { get; set; } = new Random().Next(0, 1000);
[Sieve(CanFilter = true, CanSort = true)]
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.UtcNow;
}
}

View File

@ -0,0 +1,44 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using SieveTests.Entities;
using System;
namespace SieveTests.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20180127005347_Init")]
partial class Init
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("SieveTests.Entities.Post", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("CommentCount");
b.Property<DateTimeOffset>("DateCreated");
b.Property<int>("LikeCount");
b.Property<string>("Title");
b.HasKey("Id");
b.ToTable("Posts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace SieveTests.Migrations
{
public partial class Init : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Posts",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
CommentCount = table.Column<int>(nullable: false),
DateCreated = table.Column<DateTimeOffset>(nullable: false),
LikeCount = table.Column<int>(nullable: false),
Title = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Posts", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Posts");
}
}
}

View File

@ -0,0 +1,43 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using SieveTests.Entities;
using System;
namespace SieveTests.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("SieveTests.Entities.Post", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("CommentCount");
b.Property<DateTimeOffset>("DateCreated");
b.Property<int>("LikeCount");
b.Property<string>("Title");
b.HasKey("Id");
b.ToTable("Posts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -14,7 +14,9 @@ namespace SieveTests
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
BuildWebHost(args).Run(); var host = BuildWebHost(args);
host.Run();
} }
public static IWebHost BuildWebHost(string[] args) => public static IWebHost BuildWebHost(string[] args) =>

View File

@ -18,12 +18,11 @@
}, },
"SieveTests": { "SieveTests": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values", "launchUrl": "api/values",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"applicationUrl": "http://localhost:65137/" "applicationUrl": "http://localhost:6500/"
} }
} }
} }

View File

@ -4,6 +4,11 @@
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Migrations\20180127005211_Itit.cs" />
<Compile Remove="Migrations\20180127005211_Itit.Designer.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="wwwroot\" /> <Folder Include="wwwroot\" />
</ItemGroup> </ItemGroup>
@ -16,4 +21,8 @@
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Sieve\Sieve.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -4,10 +4,14 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Sieve.Models;
using Sieve.Services;
using SieveTests.Entities;
namespace SieveTests namespace SieveTests
{ {
@ -24,6 +28,16 @@ namespace SieveTests
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddMvc(); services.AddMvc();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TestSqlServer")));
services.Configure<SieveOptions>(Configuration.GetSection("SieveConfig"));
//services.AddScoped<ISieveProcessor, SieveProcessor>();
services.AddScoped<ISieveProcessor<Post>, SieveProcessor<Post>>();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -1,4 +1,10 @@
{ {
"ConnectionStrings": {
"TestSqlServer": "Server=(localdb)\\MSSQLLocalDB; Database=SieveTests;"
},
"SieveConfig": {
},
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"Debug": { "Debug": {