Skip to content

Commit f8a7ac2

Browse files
committed
Merge branch 'feat/cqrs' into unstable
2 parents 6b505b9 + 86311d9 commit f8a7ac2

Some content is hidden

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

45 files changed

+1292
-224
lines changed

appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ deploy:
4343
server: https://www.myget.org/F/research-institute/api/v2/package
4444
api_key:
4545
secure: 6CeYcZ4Ze+57gxfeuHzqP6ldbUkPtF6pfpVM1Gw/K2jExFrAz763gNAQ++tiacq3
46-
skip_symbols: true
46+
skip_symbols: false
4747
on:
4848
branch: develop
4949
- provider: NuGet
5050
server: https://www.myget.org/F/jadnc/api/v2/package
5151
api_key:
5252
secure: 6CeYcZ4Ze+57gxfeuHzqP6ldbUkPtF6pfpVM1Gw/K2jExFrAz763gNAQ++tiacq3
53-
skip_symbols: true
53+
skip_symbols: false
5454
on:
5555
branch: unstable
5656
- provider: NuGet

docs/EntityRepositories.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ A sample implementation that performs data authorization might look like:
2424
public class MyAuthorizedEntityRepository : DefaultEntityRepository<MyEntity>
2525
{
2626
private readonly ILogger _logger;
27-
private readonly AppDbContext _context;
2827
private readonly IAuthenticationService _authenticationService;
2928

30-
public MyAuthorizedEntityRepository(AppDbContext context,
29+
public MyAuthorizedEntityRepository(
3130
ILoggerFactory loggerFactory,
3231
IJsonApiContext jsonApiContext,
3332
IAuthenticationService authenticationService)
34-
: base(context, loggerFactory, jsonApiContext)
35-
{
36-
_context = context;
33+
: base(loggerFactory, jsonApiContext)
34+
{
3735
_logger = loggerFactory.CreateLogger<MyEntityRepository>();
3836
_authenticationService = authenticationService;
3937
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using JsonApiDotNetCore.Internal;
4+
using JsonApiDotNetCore.Models;
5+
using JsonApiDotNetCore.Services;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.Extensions.Logging;
8+
9+
namespace JsonApiDotNetCore.Controllers
10+
{
11+
public class BaseJsonApiController<T, TId>
12+
: JsonApiControllerMixin
13+
where T : class, IIdentifiable<TId>
14+
{
15+
private readonly IResourceQueryService<T, TId> _queryService;
16+
private readonly IResourceCmdService<T, TId> _cmdService;
17+
private readonly IJsonApiContext _jsonApiContext;
18+
19+
protected BaseJsonApiController(
20+
IJsonApiContext jsonApiContext,
21+
IResourceService<T, TId> resourceService)
22+
{
23+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
24+
_queryService = resourceService;
25+
_cmdService = resourceService;
26+
}
27+
28+
protected BaseJsonApiController(
29+
IJsonApiContext jsonApiContext,
30+
IResourceQueryService<T, TId> queryService)
31+
{
32+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
33+
_queryService = queryService;
34+
}
35+
36+
protected BaseJsonApiController(
37+
IJsonApiContext jsonApiContext,
38+
IResourceCmdService<T, TId> cmdService)
39+
{
40+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
41+
_cmdService = cmdService;
42+
}
43+
44+
public virtual async Task<IActionResult> GetAsync()
45+
{
46+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
47+
48+
var entities = await _queryService.GetAsync();
49+
50+
return Ok(entities);
51+
}
52+
53+
public virtual async Task<IActionResult> GetAsync(TId id)
54+
{
55+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
56+
57+
var entity = await _queryService.GetAsync(id);
58+
59+
if (entity == null)
60+
return NotFound();
61+
62+
return Ok(entity);
63+
}
64+
65+
public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
66+
{
67+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
68+
69+
var relationship = await _queryService.GetRelationshipsAsync(id, relationshipName);
70+
if (relationship == null)
71+
return NotFound();
72+
73+
return Ok(relationship);
74+
}
75+
76+
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
77+
{
78+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
79+
80+
var relationship = await _queryService.GetRelationshipAsync(id, relationshipName);
81+
82+
return Ok(relationship);
83+
}
84+
85+
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
86+
{
87+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
88+
89+
if (entity == null)
90+
return UnprocessableEntity();
91+
92+
if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
93+
return Forbidden();
94+
95+
entity = await _cmdService.CreateAsync(entity);
96+
97+
return Created($"{HttpContext.Request.Path}/{entity.Id}", entity);
98+
}
99+
100+
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
101+
{
102+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
103+
104+
if (entity == null)
105+
return UnprocessableEntity();
106+
107+
var updatedEntity = await _cmdService.UpdateAsync(id, entity);
108+
109+
if (updatedEntity == null)
110+
return NotFound();
111+
112+
return Ok(updatedEntity);
113+
}
114+
115+
public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
116+
{
117+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
118+
119+
await _cmdService.UpdateRelationshipsAsync(id, relationshipName, relationships);
120+
121+
return Ok();
122+
}
123+
124+
public virtual async Task<IActionResult> DeleteAsync(TId id)
125+
{
126+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
127+
128+
var wasDeleted = await _cmdService.DeleteAsync(id);
129+
130+
if (!wasDeleted)
131+
return NotFound();
132+
133+
return NoContent();
134+
}
135+
}
136+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
using System.Threading.Tasks;
5+
using JsonApiDotNetCore.Controllers;
6+
using JsonApiDotNetCore.Internal;
7+
using Microsoft.AspNetCore.Mvc.Filters;
8+
9+
namespace JsonApiDotNetCore.Controllers
10+
{
11+
public abstract class HttpRestrictAttribute : ActionFilterAttribute, IAsyncActionFilter
12+
{
13+
protected abstract string[] Methods { get; }
14+
15+
public override async Task OnActionExecutionAsync(
16+
ActionExecutingContext context,
17+
ActionExecutionDelegate next)
18+
{
19+
var method = context.HttpContext.Request.Method;
20+
21+
if(CanExecuteAction(method) == false)
22+
throw new JsonApiException(405, $"This resource does not support {method} requests.");
23+
24+
await next();
25+
}
26+
27+
private bool CanExecuteAction(string requestMethod)
28+
{
29+
return Methods.Contains(requestMethod) == false;
30+
}
31+
}
32+
33+
public class HttpReadOnlyAttribute : HttpRestrictAttribute
34+
{
35+
protected override string[] Methods { get; } = new string[] { "POST", "PATCH", "DELETE" };
36+
}
37+
38+
public class NoHttpPostAttribute : HttpRestrictAttribute
39+
{
40+
protected override string[] Methods { get; } = new string[] { "POST" };
41+
}
42+
43+
public class NoHttpPatchAttribute : HttpRestrictAttribute
44+
{
45+
protected override string[] Methods { get; } = new string[] { "PATCH" };
46+
}
47+
48+
public class NoHttpDeleteAttribute : HttpRestrictAttribute
49+
{
50+
protected override string[] Methods { get; } = new string[] { "DELETE" };
51+
}
52+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using JsonApiDotNetCore.Models;
4+
using JsonApiDotNetCore.Services;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace JsonApiDotNetCore.Controllers
9+
{
10+
public class JsonApiCmdController<T>
11+
: JsonApiCmdController<T, int> where T : class, IIdentifiable<int>
12+
{
13+
public JsonApiCmdController(
14+
IJsonApiContext jsonApiContext,
15+
IResourceService<T, int> resourceService)
16+
: base(jsonApiContext, resourceService)
17+
{ }
18+
}
19+
20+
public class JsonApiCmdController<T, TId>
21+
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
22+
{
23+
public JsonApiCmdController(
24+
IJsonApiContext jsonApiContext,
25+
IResourceService<T, TId> resourceService)
26+
: base(jsonApiContext, resourceService)
27+
{ }
28+
29+
[HttpPost]
30+
public override async Task<IActionResult> PostAsync([FromBody] T entity)
31+
=> await base.PostAsync(entity);
32+
33+
[HttpPatch("{id}")]
34+
public override async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
35+
=> await base.PatchAsync(id, entity);
36+
37+
[HttpPatch("{id}/relationships/{relationshipName}")]
38+
public override async Task<IActionResult> PatchRelationshipsAsync(
39+
TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
40+
=> await base.PatchRelationshipsAsync(id, relationshipName, relationships);
41+
42+
[HttpDelete("{id}")]
43+
public override async Task<IActionResult> DeleteAsync(TId id) => await base.DeleteAsync(id);
44+
}
45+
}

0 commit comments

Comments
 (0)