Skip to content

Commit 4a2abe9

Browse files
author
Bart Koelman
authored
Remove short-hand interfaces for TId is int (#1093)
* Removed single-parameter controllers * Removed base class: I can't think of a reason why we should have an intermediate base class for these tests * Removed single-parameter resource services * Removed single-parameter resource repositories * Removed single-parameter resource definitions * Removed non-generic Identifiable and throw for resource classes that only implement IIdentifiable (without ID) when building the resource graph * Updated documentation
1 parent 758a191 commit 4a2abe9

File tree

259 files changed

+592
-1005
lines changed

Some content is hidden

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

259 files changed

+592
-1005
lines changed

benchmarks/BenchmarkResource.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Benchmarks
66
{
77
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
8-
public sealed class BenchmarkResource : Identifiable
8+
public sealed class BenchmarkResource : Identifiable<int>
99
{
1010
[Attr(PublicName = BenchmarkResourcePublicNames.NameAttr)]
1111
public string Name { get; set; }

benchmarks/Deserialization/DeserializationBenchmarkBase.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected DeserializationBenchmarkBase()
3030
var resourceDefinitionAccessor = new ResourceDefinitionAccessor(resourceGraph, serviceContainer);
3131

3232
serviceContainer.AddService(typeof(IResourceDefinitionAccessor), resourceDefinitionAccessor);
33-
serviceContainer.AddService(typeof(IResourceDefinition<ResourceA>), new JsonApiResourceDefinition<ResourceA>(resourceGraph));
33+
serviceContainer.AddService(typeof(IResourceDefinition<ResourceA, int>), new JsonApiResourceDefinition<ResourceA, int>(resourceGraph));
3434

3535
// ReSharper disable once VirtualMemberCallInConstructor
3636
JsonApiRequest request = CreateJsonApiRequest(resourceGraph);
@@ -56,7 +56,7 @@ protected DeserializationBenchmarkBase()
5656
protected abstract JsonApiRequest CreateJsonApiRequest(IResourceGraph resourceGraph);
5757

5858
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
59-
public sealed class ResourceA : Identifiable
59+
public sealed class ResourceA : Identifiable<int>
6060
{
6161
[Attr]
6262
public bool Attribute01 { get; set; }

benchmarks/Serialization/SerializationBenchmarkBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ protected SerializationBenchmarkBase()
6464
protected abstract IEvaluatedIncludeCache CreateEvaluatedIncludeCache(IResourceGraph resourceGraph);
6565

6666
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
67-
public sealed class ResourceA : Identifiable
67+
public sealed class ResourceA : Identifiable<int>
6868
{
6969
[Attr]
7070
public bool Attribute01 { get; set; }

benchmarks/SubResource.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Benchmarks
66
{
77
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
8-
public sealed class SubResource : Identifiable
8+
public sealed class SubResource : Identifiable<int>
99
{
1010
[Attr]
1111
public string Value { get; set; }

docs/api/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ This section documents the package API and is generated from the XML source comm
66

77
- [`JsonApiOptions`](JsonApiDotNetCore.Configuration.JsonApiOptions.yml)
88
- [`IResourceGraph`](JsonApiDotNetCore.Configuration.IResourceGraph.yml)
9-
- [`JsonApiResourceDefinition<TResource>`](JsonApiDotNetCore.Resources.JsonApiResourceDefinition-1.yml)
9+
- [`JsonApiResourceDefinition<TResource, TId>`](JsonApiDotNetCore.Resources.JsonApiResourceDefinition-2.yml)

docs/getting-started/step-by-step.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ Install-Package JsonApiDotNetCore
3535
### Define Models
3636

3737
Define your domain models such that they implement `IIdentifiable<TId>`.
38-
The easiest way to do this is to inherit from `Identifiable`
38+
The easiest way to do this is to inherit from `Identifiable<TId>`.
3939

4040
```c#
41-
public class Person : Identifiable
41+
public class Person : Identifiable<int>
4242
{
4343
[Attr]
4444
public string Name { get; set; }
@@ -47,7 +47,7 @@ public class Person : Identifiable
4747

4848
### Define DbContext
4949

50-
Nothing special here, just an ordinary `DbContext`
50+
Nothing special here, just an ordinary `DbContext`.
5151

5252
```
5353
public class AppDbContext : DbContext
@@ -63,14 +63,14 @@ public class AppDbContext : DbContext
6363

6464
### Define Controllers
6565

66-
You need to create controllers that inherit from `JsonApiController<TResource>` or `JsonApiController<TResource, TId>`
67-
where `TResource` is the model that inherits from `Identifiable<TId>`
66+
You need to create controllers that inherit from `JsonApiController<TResource, TId>`
67+
where `TResource` is the model that inherits from `Identifiable<TId>`.
6868

6969
```c#
70-
public class PeopleController : JsonApiController<Person>
70+
public class PeopleController : JsonApiController<Person, int>
7171
{
7272
public PeopleController(IJsonApiOptions options, ILoggerFactory loggerFactory,
73-
IResourceService<Person> resourceService)
73+
IResourceService<Person, int> resourceService)
7474
: base(options, loggerFactory, resourceService)
7575
{
7676
}

docs/usage/extensibility/controllers.md

+7-24
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,12 @@
11
# Controllers
22

3-
You need to create controllers that inherit from `JsonApiController<TResource>`
4-
5-
```c#
6-
public class ArticlesController : JsonApiController<Article>
7-
{
8-
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
9-
IResourceService<Article> resourceService)
10-
: base(options, loggerFactory, resourceService)
11-
{
12-
}
13-
}
14-
```
15-
16-
## Non-Integer Type Keys
17-
18-
If your model is using a type other than `int` for the primary key, you must explicitly declare it in the controller/service/repository definitions.
3+
You need to create controllers that inherit from `JsonApiController<TResource, TId>`
194

205
```c#
216
public class ArticlesController : JsonApiController<Article, Guid>
22-
//---------------------------------------------------------- ^^^^
237
{
248
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
259
IResourceService<Article, Guid> resourceService)
26-
//----------------------- ^^^^
2710
: base(options, loggerFactory, resourceService)
2811
{
2912
}
@@ -39,10 +22,10 @@ In this example, if a client attempts to do anything other than GET a resource,
3922
This approach is ok, but introduces some boilerplate that can easily be avoided.
4023

4124
```c#
42-
public class ArticlesController : BaseJsonApiController<Article>
25+
public class ArticlesController : BaseJsonApiController<Article, int>
4326
{
4427
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
45-
IResourceService<Article> resourceService)
28+
IResourceService<Article, int> resourceService)
4629
: base(options, loggerFactory, resourceService)
4730
{
4831
}
@@ -76,10 +59,10 @@ An attempt to use one of the blacklisted methods will result in a HTTP 405 Metho
7659

7760
```c#
7861
[HttpReadOnly]
79-
public class ArticlesController : BaseJsonApiController<Article>
62+
public class ArticlesController : BaseJsonApiController<Article, int>
8063
{
8164
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
82-
IResourceService<Article> resourceService)
65+
IResourceService<Article, int> resourceService)
8366
: base(options, loggerFactory, resourceService)
8467
{
8568
}
@@ -95,10 +78,10 @@ As with the ActionFilter attributes, if a service implementation is not availabl
9578
For more information about resource service injection, see [Replacing injected services](~/usage/extensibility/layer-overview.md#replacing-injected-services) and [Resource Services](~/usage/extensibility/services.md).
9679

9780
```c#
98-
public class ReportsController : BaseJsonApiController<Report>
81+
public class ReportsController : BaseJsonApiController<Report, int>
9982
{
10083
public ReportsController(IJsonApiOptions options, ILoggerFactory loggerFactory,
101-
IGetAllService<Report> getAllService)
84+
IGetAllService<Report, int> getAllService)
10285
: base(options, loggerFactory, getAllService)
10386
{
10487
}

docs/usage/extensibility/repositories.md

+15-16
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ The repository should then be registered in Startup.cs.
88
```c#
99
public void ConfigureServices(IServiceCollection services)
1010
{
11-
services.AddScoped<IResourceRepository<Article>, ArticleRepository>();
12-
services.AddScoped<IResourceReadRepository<Article>, ArticleRepository>();
13-
services.AddScoped<IResourceWriteRepository<Article>, ArticleRepository>();
11+
services.AddScoped<IResourceRepository<Article, int>, ArticleRepository>();
12+
services.AddScoped<IResourceReadRepository<Article, int>, ArticleRepository>();
13+
services.AddScoped<IResourceWriteRepository<Article, int>, ArticleRepository>();
1414
}
1515
```
1616

@@ -34,18 +34,18 @@ A sample implementation that performs authorization might look like this.
3434
All of the methods in EntityFrameworkCoreRepository will use the `GetAll()` method to get the `DbSet<TResource>`, so this is a good method to apply filters such as user or tenant authorization.
3535

3636
```c#
37-
public class ArticleRepository : EntityFrameworkCoreRepository<Article>
37+
public class ArticleRepository : EntityFrameworkCoreRepository<Article, int>
3838
{
3939
private readonly IAuthenticationService _authenticationService;
4040

4141
public ArticleRepository(IAuthenticationService authenticationService,
4242
ITargetedFields targetedFields, IDbContextResolver dbContextResolver,
43-
IResourceGraph resourceGraph, IGenericServiceFactory genericServiceFactory,
44-
IResourceFactory resourceFactory,
43+
IResourceGraph resourceGraph, IResourceFactory resourceFactory,
4544
IEnumerable<IQueryConstraintProvider> constraintProviders,
46-
ILoggerFactory loggerFactory)
47-
: base(targetedFields, dbContextResolver, resourceGraph, genericServiceFactory,
48-
resourceFactory, constraintProviders, loggerFactory)
45+
ILoggerFactory loggerFactory,
46+
IResourceDefinitionAccessor resourceDefinitionAccessor)
47+
: base(targetedFields, dbContextResolver, resourceGraph, resourceFactory,
48+
constraintProviders, loggerFactory, resourceDefinitionAccessor)
4949
{
5050
_authenticationService = authenticationService;
5151
}
@@ -64,18 +64,17 @@ If you need to use multiple Entity Framework Core DbContexts, first create a rep
6464
This example shows a single `DbContextARepository` for all entities that are members of `DbContextA`.
6565

6666
```c#
67-
public class DbContextARepository<TResource> : EntityFrameworkCoreRepository<TResource>
68-
where TResource : class, IIdentifiable<int>
67+
public class DbContextARepository<TResource, TId> : EntityFrameworkCoreRepository<TResource, TId>
68+
where TResource : class, IIdentifiable<TId>
6969
{
7070
public DbContextARepository(ITargetedFields targetedFields,
7171
DbContextResolver<DbContextA> dbContextResolver,
7272
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
73-
IResourceGraph resourceGraph, IGenericServiceFactory genericServiceFactory,
74-
IResourceFactory resourceFactory,
73+
IResourceGraph resourceGraph, IResourceFactory resourceFactory,
7574
IEnumerable<IQueryConstraintProvider> constraintProviders,
76-
ILoggerFactory loggerFactory)
77-
: base(targetedFields, dbContextResolver, resourceGraph, genericServiceFactory,
78-
resourceFactory, constraintProviders, loggerFactory)
75+
ILoggerFactory loggerFactory, IResourceDefinitionAccessor resourceDefinitionAccessor)
76+
: base(targetedFields, dbContextResolver, resourceGraph, resourceFactory,
77+
constraintProviders, loggerFactory, resourceDefinitionAccessor)
7978
{
8079
}
8180
}

docs/usage/extensibility/resource-definitions.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ public class Startup
2323
resource definition on the container yourself:
2424

2525
```c#
26-
services.AddScoped<ResourceDefinition<Product>, ProductResource>();
26+
services.AddScoped<ResourceDefinition<Product, int>, ProductDefinition>();
2727
```
2828

2929
## Customizing queries
3030

3131
_since v4.0_
3232

3333
For various reasons (see examples below) you may need to change parts of the query, depending on resource type.
34-
`JsonApiResourceDefinition<TResource>` (which is an empty implementation of `IResourceDefinition<TResource>`) provides overridable methods that pass you the result of query string parameter parsing.
34+
`JsonApiResourceDefinition<TResource, TId>` (which is an empty implementation of `IResourceDefinition<TResource, TId>`) provides overridable methods that pass you the result of query string parameter parsing.
3535
The value returned by you determines what will be used to execute the query.
3636

3737
An intermediate format (`QueryExpression` and derived types) is used, which enables us to separate JSON:API implementation
@@ -45,7 +45,7 @@ For example, you may accept some sensitive data that should only be exposed to a
4545
**Note:** to exclude attributes unconditionally, use `[Attr(Capabilities = ~AttrCapabilities.AllowView)]` on a resource class property.
4646

4747
```c#
48-
public class UserDefinition : JsonApiResourceDefinition<User>
48+
public class UserDefinition : JsonApiResourceDefinition<User, int>
4949
{
5050
public UserDefinition(IResourceGraph resourceGraph)
5151
: base(resourceGraph)
@@ -104,7 +104,7 @@ Content-Type: application/vnd.api+json
104104
You can define the default sort order if no `sort` query string parameter is provided.
105105

106106
```c#
107-
public class AccountDefinition : JsonApiResourceDefinition<Account>
107+
public class AccountDefinition : JsonApiResourceDefinition<Account, int>
108108
{
109109
public AccountDefinition(IResourceGraph resourceGraph)
110110
: base(resourceGraph)
@@ -132,7 +132,7 @@ public class AccountDefinition : JsonApiResourceDefinition<Account>
132132
You may want to enforce pagination on large database tables.
133133

134134
```c#
135-
public class AccessLogDefinition : JsonApiResourceDefinition<AccessLog>
135+
public class AccessLogDefinition : JsonApiResourceDefinition<AccessLog, int>
136136
{
137137
public AccessLogDefinition(IResourceGraph resourceGraph)
138138
: base(resourceGraph)
@@ -163,7 +163,7 @@ public class AccessLogDefinition : JsonApiResourceDefinition<AccessLog>
163163
The next example filters out `Account` resources that are suspended.
164164

165165
```c#
166-
public class AccountDefinition : JsonApiResourceDefinition<Account>
166+
public class AccountDefinition : JsonApiResourceDefinition<Account, int>
167167
{
168168
public AccountDefinition(IResourceGraph resourceGraph)
169169
: base(resourceGraph)
@@ -192,7 +192,7 @@ public class AccountDefinition : JsonApiResourceDefinition<Account>
192192
In the example below, an error is returned when a user tries to include the manager of an employee.
193193

194194
```c#
195-
public class EmployeeDefinition : JsonApiResourceDefinition<Employee>
195+
public class EmployeeDefinition : JsonApiResourceDefinition<Employee, int>
196196
{
197197
public EmployeeDefinition(IResourceGraph resourceGraph)
198198
: base(resourceGraph)
@@ -227,7 +227,7 @@ Note this directly influences the Entity Framework Core `IQueryable`. As opposed
227227
But it only works on primary resource endpoints (for example: /articles, but not on /blogs/1/articles or /blogs?include=articles).
228228

229229
```c#
230-
public class ItemDefinition : JsonApiResourceDefinition<Item>
230+
public class ItemDefinition : JsonApiResourceDefinition<Item, int>
231231
{
232232
public ItemDefinition(IResourceGraph resourceGraph)
233233
: base(resourceGraph)

docs/usage/extensibility/services.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ This allows you to customize it however you want. This is also a good place to i
55

66
## Supplementing Default Behavior
77

8-
If you don't need to alter the underlying mechanisms, you can inherit from `JsonApiResourceService<TResource>` and override the existing methods.
8+
If you don't need to alter the underlying mechanisms, you can inherit from `JsonApiResourceService<TResource, TId>` and override the existing methods.
99
In simple cases, you can also just wrap the base implementation with your custom logic.
1010

1111
A simple example would be to send notifications when a resource gets created.
1212

1313
```c#
14-
public class TodoItemService : JsonApiResourceService<TodoItem>
14+
public class TodoItemService : JsonApiResourceService<TodoItem, int>
1515
{
1616
private readonly INotificationService _notificationService;
1717

@@ -43,21 +43,21 @@ public class TodoItemService : JsonApiResourceService<TodoItem>
4343
## Not Using Entity Framework Core?
4444

4545
As previously discussed, this library uses Entity Framework Core by default.
46-
If you'd like to use another ORM that does not provide what JsonApiResourceService depends upon, you can use a custom `IResourceService<TResource>` implementation.
46+
If you'd like to use another ORM that does not provide what JsonApiResourceService depends upon, you can use a custom `IResourceService<TResource, TId>` implementation.
4747

4848
```c#
4949
// Startup.cs
5050
public void ConfigureServices(IServiceCollection services)
5151
{
5252
// add the service override for Product
53-
services.AddScoped<IResourceService<Product>, ProductService>();
53+
services.AddScoped<IResourceService<Product, int>, ProductService>();
5454

5555
// add your own Data Access Object
5656
services.AddScoped<IProductDao, ProductDao>();
5757
}
5858

5959
// ProductService.cs
60-
public class ProductService : IResourceService<Product>
60+
public class ProductService : IResourceService<Product, int>
6161
{
6262
private readonly IProductDao _dao;
6363

@@ -154,7 +154,7 @@ public class Startup
154154
Then in the controller, you should inherit from the base controller and pass the services into the named, optional base parameters:
155155

156156
```c#
157-
public class ArticlesController : BaseJsonApiController<Article>
157+
public class ArticlesController : BaseJsonApiController<Article, int>
158158
{
159159
public ArticlesController(IJsonApiOptions options, ILoggerFactory loggerFactory,
160160
ICreateService<Article, int> create, IDeleteService<Article, int> delete)

docs/usage/meta.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ public sealed class CopyrightResponseMeta : IResponseMeta
3939

4040
## Resource Meta
4141

42-
Resource-specific metadata can be added by implementing `IResourceDefinition<TResource, TId>.GetMeta` (or overriding it on `JsonApiResourceDefinition`):
42+
Resource-specific metadata can be added by implementing `IResourceDefinition<TResource, TId>.GetMeta` (or overriding it on `JsonApiResourceDefinition<TResource, TId>`):
4343

4444
```c#
45-
public class PersonDefinition : JsonApiResourceDefinition<Person>
45+
public class PersonDefinition : JsonApiResourceDefinition<Person, int>
4646
{
4747
public PersonDefinition(IResourceGraph resourceGraph)
4848
: base(resourceGraph)

docs/usage/options.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ options.ValidateModelState = true;
109109
```
110110

111111
```c#
112-
public class Person : Identifiable
112+
public class Person : Identifiable<int>
113113
{
114114
[Attr]
115115
[Required]

docs/usage/resource-graph.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ services.AddJsonApi(resources: builder =>
8585
2. The model is decorated with a `ResourceAttribute`
8686
```c#
8787
[Resource("myResources")]
88-
public class MyModel : Identifiable
88+
public class MyModel : Identifiable<int>
8989
{
9090
}
9191
```
9292

9393
3. The configured naming convention (by default this is camel-case).
9494
```c#
9595
// this will be registered as "myModels"
96-
public class MyModel : Identifiable
96+
public class MyModel : Identifiable<int>
9797
{
9898
}
9999
```

0 commit comments

Comments
 (0)