Skip to content

Commit 4d8294f

Browse files
authored
Merge pull request #94 from Research-Institute/develop
v2.0.0
2 parents 219ccfc + 66dbdc5 commit 4d8294f

File tree

103 files changed

+2702
-565
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+2702
-565
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
\.vs/
2+
3+
*.user

JsonApiDotnetCore.sln

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
21
Microsoft Visual Studio Solution File, Format Version 12.00
32
# Visual Studio 15
4-
VisualStudioVersion = 15.0.26228.4
3+
VisualStudioVersion = 15.0.26228.9
54
MinimumVisualStudioVersion = 10.0.40219.1
65
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{C0EC9E70-EB2E-436F-9D94-FA16FA774123}"
76
EndProject
@@ -16,26 +15,71 @@ EndProject
1615
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}"
1716
ProjectSection(SolutionItems) = preProject
1817
.gitignore = .gitignore
18+
README.md = README.md
1919
EndProjectSection
2020
EndProject
21+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkExample", "src\NoEntityFrameworkExample\NoEntityFrameworkExample.csproj", "{570165EC-62B5-4684-A139-8D2A30DD4475}"
22+
EndProject
23+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkTests", "test\NoEntityFrameworkTests\NoEntityFrameworkTests.csproj", "{73DA578D-A63F-4956-83ED-6D7102E09140}"
24+
EndProject
2125
Global
2226
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2327
Debug|Any CPU = Debug|Any CPU
28+
Debug|x64 = Debug|x64
29+
Debug|x86 = Debug|x86
2430
Release|Any CPU = Release|Any CPU
31+
Release|x64 = Release|x64
32+
Release|x86 = Release|x86
2533
EndGlobalSection
2634
GlobalSection(ProjectConfigurationPlatforms) = postSolution
2735
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2836
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|Any CPU.Build.0 = Debug|Any CPU
37+
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|x64.ActiveCfg = Debug|Any CPU
38+
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|x86.ActiveCfg = Debug|Any CPU
2939
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|Any CPU.ActiveCfg = Release|Any CPU
3040
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|Any CPU.Build.0 = Release|Any CPU
41+
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|x64.ActiveCfg = Release|Any CPU
42+
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|x86.ActiveCfg = Release|Any CPU
3143
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3244
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|Any CPU.Build.0 = Debug|Any CPU
45+
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|x64.ActiveCfg = Debug|Any CPU
46+
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|x86.ActiveCfg = Debug|Any CPU
3347
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|Any CPU.ActiveCfg = Release|Any CPU
3448
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|Any CPU.Build.0 = Release|Any CPU
49+
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|x64.ActiveCfg = Release|Any CPU
50+
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|x86.ActiveCfg = Release|Any CPU
3551
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3652
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
53+
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|x64.ActiveCfg = Debug|Any CPU
54+
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|x86.ActiveCfg = Debug|Any CPU
3755
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
3856
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|Any CPU.Build.0 = Release|Any CPU
57+
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|x64.ActiveCfg = Release|Any CPU
58+
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|x86.ActiveCfg = Release|Any CPU
59+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|Any CPU.Build.0 = Debug|Any CPU
61+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|x64.ActiveCfg = Debug|Any CPU
62+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|x64.Build.0 = Debug|Any CPU
63+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|x86.ActiveCfg = Debug|Any CPU
64+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Debug|x86.Build.0 = Debug|Any CPU
65+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|Any CPU.ActiveCfg = Release|Any CPU
66+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|Any CPU.Build.0 = Release|Any CPU
67+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|x64.ActiveCfg = Release|Any CPU
68+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|x64.Build.0 = Release|Any CPU
69+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|x86.ActiveCfg = Release|Any CPU
70+
{570165EC-62B5-4684-A139-8D2A30DD4475}.Release|x86.Build.0 = Release|Any CPU
71+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
72+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|Any CPU.Build.0 = Debug|Any CPU
73+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|x64.ActiveCfg = Debug|Any CPU
74+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|x64.Build.0 = Debug|Any CPU
75+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|x86.ActiveCfg = Debug|Any CPU
76+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Debug|x86.Build.0 = Debug|Any CPU
77+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|Any CPU.ActiveCfg = Release|Any CPU
78+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|Any CPU.Build.0 = Release|Any CPU
79+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|x64.ActiveCfg = Release|Any CPU
80+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|x64.Build.0 = Release|Any CPU
81+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|x86.ActiveCfg = Release|Any CPU
82+
{73DA578D-A63F-4956-83ED-6D7102E09140}.Release|x86.Build.0 = Release|Any CPU
3983
EndGlobalSection
4084
GlobalSection(SolutionProperties) = preSolution
4185
HideSolutionNode = FALSE
@@ -44,5 +88,7 @@ Global
4488
{C0EC9E70-EB2E-436F-9D94-FA16FA774123} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}
4589
{97EE048B-16C0-43F6-BDA9-4E762B2F579F} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}
4690
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F}
91+
{570165EC-62B5-4684-A139-8D2A30DD4475} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}
92+
{73DA578D-A63F-4956-83ED-6D7102E09140} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F}
4793
EndGlobalSection
4894
EndGlobal

README.md

+122-24
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
JsonApiDotnetCore provides a framework for building [json:api](http://jsonapi.org/) compliant web servers. Unlike other .Net implementations, this library provides all the required middleware to build a complete server. All you need to focus on is defining the resources. However, the library is also fully extensible so you can customize the implementation to meet your specific needs.
1010

1111
# Table Of Contents
12-
- [Comprehensive Demo](#comprehensive-demo)
1312
- [Installation](#installation)
14-
- [Generators](#generators)
1513
- [Usage](#usage)
1614
- [Middleware and Services](#middleware-and-services)
1715
- [Defining Models](#defining-models)
1816
- [Specifying Public Attributes](#specifying-public-attributes)
1917
- [Relationships](#relationships)
18+
- [Resource Names](#resource-names)
2019
- [Defining Controllers](#defining-controllers)
2120
- [Non-Integer Type Keys](#non-integer-type-keys)
2221
- [Routing](#routing)
2322
- [Namespacing and Versioning URLs](#namespacing-and-versioning-urls)
23+
- [Disable Convention](#disable-convention)
2424
- [Defining Custom Data Access Methods](#defining-custom-data-access-methods)
2525
- [Pagination](#pagination)
2626
- [Filtering](#filtering)
@@ -32,12 +32,6 @@ JsonApiDotnetCore provides a framework for building [json:api](http://jsonapi.or
3232
- [Sparse Fieldsets](#sparse-fieldsets)
3333
- [Tests](#tests)
3434

35-
## Comprehensive Demo
36-
37-
The following is a WIP demo showing how to create a web application using this library, EmberJS and PostgreSQL. If there are specific topics you'd like to see in future videos, comment on the playlist.
38-
39-
[![Goto Playlist](https://img.youtube.com/vi/KAMuo6K7VcE/0.jpg)](https://www.youtube.com/watch?v=KAMuo6K7VcE&list=PLu4Bq53iqJJAo1RF0TY4Q5qCG7n9AqSZf)
40-
4135
## Installation
4236

4337
- Visual Studio
@@ -47,14 +41,14 @@ Install-Package JsonApiDotnetCore
4741

4842
- project.json
4943
```json
50-
"JsonApiDotNetCore": "1.3.0"
44+
"JsonApiDotNetCore": "2.0.0"
5145
```
5246

5347
- *.csproj
5448
```xml
5549
<ItemGroup>
5650
<!-- ... -->
57-
<PackageReference Include="JsonApiDotNetCore" Version="1.3.0" />
51+
<PackageReference Include="JsonApiDotNetCore" Version="2.0.0" />
5852
</ItemGroup>
5953
```
6054

@@ -64,22 +58,14 @@ For pre-releases, add the [MyGet](https://www.myget.org/feed/Details/research-in
6458
(https://www.myget.org/F/research-institute/api/v3/index.json)
6559
to your nuget configuration.
6660

67-
## Generators
68-
69-
You can install the [Yeoman generators](https://github.com/Research-Institute/json-api-dotnet-core-generators)
70-
to make building applications much easier.
71-
7261
## Usage
7362

74-
You need to do 3 things:
63+
The most basic use case requires 3 things:
7564

7665
- Add Middleware and Services
7766
- Define Models
7867
- Define Controllers
7968

80-
I recommend reading the details below, but once you're familiar with the
81-
setup, you can use the Yeoman generator to generate the required classes.
82-
8369
### Middleware and Services
8470

8571
Add the following to your `Startup.ConfigureServices` method.
@@ -169,6 +155,23 @@ public class TodoItem : Identifiable<int>
169155
}
170156
```
171157

158+
#### Resource Names
159+
160+
If a DbContext is specified when adding the services, the context will be used to define the resources and their names.
161+
162+
```csharp
163+
public DbSet<MyModel> SomeModels { get; set; } // this will be translated into "some-models"
164+
```
165+
166+
However, you can specify a custom name like so:
167+
168+
```csharp
169+
[Resource("some-models")]
170+
public DbSet<MyModel> MyModels { get; set; } // this will be translated into "some-models"
171+
```
172+
173+
For further resource customizations, please see the section on [Defining Custom Data Access Methods](#defining-custom-data-access-methods).
174+
172175
### Defining Controllers
173176

174177
You need to create controllers that inherit from `JsonApiController<TEntity>` or `JsonApiController<TEntity, TId>`
@@ -180,9 +183,9 @@ public class ThingsController : JsonApiController<Thing>
180183
{
181184
public ThingsController(
182185
IJsonApiContext jsonApiContext,
183-
IEntityRepository<Thing> entityRepository,
186+
IResourceService<Thing> resourceService,
184187
ILoggerFactory loggerFactory)
185-
: base(jsonApiContext, entityRepository, loggerFactory)
188+
: base(jsonApiContext, resourceService, loggerFactory)
186189
{ }
187190
}
188191
```
@@ -199,9 +202,9 @@ public class ThingsController : JsonApiController<Thing, Guid>
199202
{
200203
public ThingsController(
201204
IJsonApiContext jsonApiContext,
202-
IEntityRepository<Thing, Guid> entityRepository,
205+
IResourceService<Thing, Guid> resourceService,
203206
ILoggerFactory loggerFactory)
204-
: base(jsonApiContext, entityRepository, loggerFactory)
207+
: base(jsonApiContext, resourceService, loggerFactory)
205208
{ }
206209
}
207210
```
@@ -226,9 +229,104 @@ services.AddJsonApi<AppDbContext>(
226229
opt => opt.Namespace = "api/v1");
227230
```
228231

232+
#### Disable Convention
233+
234+
You can disable the dasherized convention and specify your own template
235+
by using the `DisableRoutingConvention` Attribute.
236+
237+
```csharp
238+
[Route("[controller]")]
239+
[DisableRoutingConvention]
240+
public class CamelCasedModelsController : JsonApiController<CamelCasedModel>
241+
{
242+
public CamelCasedModelsController(
243+
IJsonApiContext jsonApiContext,
244+
IResourceService<CamelCasedModel> resourceService,
245+
ILoggerFactory loggerFactory)
246+
: base(jsonApiContext, resourceService, loggerFactory)
247+
{ }
248+
}
249+
```
250+
251+
It is important to note that your routes *must* still end with the model name in the same format
252+
as the resource name. This is so that we can build accurrate resource links in the json:api document.
253+
For example, if you define a resource as `MyModels` the controller route must match:
254+
255+
```csharp
256+
// resource definition
257+
builder.AddResource<TodoItem>("myModels");
258+
259+
// controller definition
260+
[Route("api/myModels")]
261+
[DisableRoutingConvention]
262+
public class TodoItemsController : JsonApiController<TodoItem>
263+
{ //...
264+
}
265+
```
266+
229267
### Defining Custom Data Access Methods
230268

231-
You can implement custom methods for accessing the data by creating an implementation of
269+
By default, data retrieval is distributed across 3 layers:
270+
271+
1. `JsonApiController`
272+
2. `EntityResourceService`
273+
3. `DefaultEntityRepository`
274+
275+
Customization can be done at any of these layers. However, it is recommended that you make your customizations at the service or the repository layer when possible to keep the controllers free of unnecessary logic.
276+
277+
#### Not Using Entity Framework?
278+
279+
Out of the box, the library uses your `DbContext` to create a "ContextGraph" or map of all your models and their relationships. If, however, you have models that are not members of a `DbContext`, you can manually create this graph like so:
280+
281+
```csharp
282+
// Startup.cs
283+
public void ConfigureServices(IServiceCollection services)
284+
{
285+
// Add framework services.
286+
var mvcBuilder = services.AddMvc();
287+
288+
services.AddJsonApi(options => {
289+
options.Namespace = "api/v1";
290+
options.BuildContextGraph((builder) => {
291+
builder.AddResource<MyModel>("my-models");1
292+
});
293+
}, mvcBuilder);
294+
// ...
295+
}
296+
```
297+
298+
#### Custom Resource Service Implementation
299+
300+
By default, this library uses Entity Framework. If you'd like to use another ORM that does not implement `IQueryable`, you can inject a custom service like so:
301+
302+
```csharp
303+
// Startup.cs
304+
public void ConfigureServices(IServiceCollection services)
305+
{
306+
services.AddScoped<IResourceService<MyModel>, MyModelService>();
307+
// ...
308+
}
309+
```
310+
311+
```csharp
312+
// MyModelService.cs
313+
public class MyModelService : IResourceService<MyModel>
314+
{
315+
private readonly IMyModelDAL _dal;
316+
public MyModelService(IMyModelDAL dal)
317+
{
318+
_dal = dal;
319+
}
320+
public Task<IEnumerable<MyModel>> GetAsync()
321+
{
322+
return await _dal.GetModelAsync();
323+
}
324+
}
325+
```
326+
327+
#### Custom Entity Repository Implementation
328+
329+
If you want to use EF, but need additional data access logic (such as authorization), you can implement custom methods for accessing the data by creating an implementation of
232330
`IEntityRepository<TEntity, TId>`. If you only need minor changes you can override the
233331
methods defined in `DefaultEntityRepository<TEntity, TId>`. The repository should then be
234332
add to the service collection in `Startup.ConfigureServices` like so:

build.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ set -e
66
dotnet restore ./src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
77
dotnet restore ./src/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
88
dotnet restore ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj
9+
dotnet restore ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj
910

10-
dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj
11+
dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj
12+
dotnet test ./test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj

0 commit comments

Comments
 (0)