@ -1,3 +1 @@ | |||||
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type=json --patch="$(cat nginx-ingress\publish-service-patch.yaml)" | |||||
kubectl apply -f nginx-ingress\azure\service.yaml | |||||
kubectl apply -f nginx-ingress\patch-service-without-rbac.yaml | |||||
kubectl apply -f nginx-ingress\cloud-generic.yaml |
@ -0,0 +1,2 @@ | |||||
kubectl apply -f nginx-ingress\cm.yaml | |||||
kubectl apply -f nginx-ingress\cloud-generic.yaml |
@ -1,12 +1,5 @@ | |||||
kubectl apply -f ingress.yaml | |||||
# Deploy nginx-ingress core files | # Deploy nginx-ingress core files | ||||
kubectl apply -f nginx-ingress\namespace.yaml | |||||
kubectl apply -f nginx-ingress\default-backend.yaml | |||||
kubectl apply -f nginx-ingress\configmap.yaml | |||||
kubectl apply -f nginx-ingress\tcp-services-configmap.yaml | |||||
kubectl apply -f nginx-ingress\udp-services-configmap.yaml | |||||
kubectl apply -f nginx-ingress\without-rbac.yaml | |||||
kubectl apply -f nginx-ingress\mandatory.yaml | |||||
@ -0,0 +1,18 @@ | |||||
apiVersion: v1 | |||||
kind: ServiceAccount | |||||
metadata: | |||||
name: tiller | |||||
namespace: kube-system | |||||
--- | |||||
apiVersion: rbac.authorization.k8s.io/v1 | |||||
kind: ClusterRoleBinding | |||||
metadata: | |||||
name: tiller | |||||
roleRef: | |||||
apiGroup: rbac.authorization.k8s.io | |||||
kind: ClusterRole | |||||
name: cluster-admin | |||||
subjects: | |||||
- kind: ServiceAccount | |||||
name: tiller | |||||
namespace: kube-system |
@ -0,0 +1,5 @@ | |||||
ingress: | |||||
annotations: | |||||
kubernetes.io/ingress.class: "nginx" | |||||
ingress.kubernetes.io/ssl-redirect: "false" | |||||
nginx.ingress.kubernetes.io/ssl-redirect: "false" |
@ -1,19 +0,0 @@ | |||||
kind: Service | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: ingress-nginx | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app: ingress-nginx | |||||
spec: | |||||
externalTrafficPolicy: Local | |||||
type: LoadBalancer | |||||
selector: | |||||
app: ingress-nginx | |||||
ports: | |||||
- name: http | |||||
port: 80 | |||||
targetPort: http | |||||
- name: https | |||||
port: 443 | |||||
targetPort: https |
@ -0,0 +1,21 @@ | |||||
kind: Service | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: ingress-nginx | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
spec: | |||||
externalTrafficPolicy: Local | |||||
type: LoadBalancer | |||||
selector: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
ports: | |||||
- name: http | |||||
port: 80 | |||||
targetPort: http | |||||
- name: https | |||||
port: 443 | |||||
targetPort: https |
@ -1,11 +0,0 @@ | |||||
kind: ConfigMap | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: nginx-configuration | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app: ingress-nginx | |||||
data: | |||||
ssl-redirect: "false" | |||||
proxy-buffer-size: "128k" | |||||
proxy-buffers: "4 256k" |
@ -1,52 +0,0 @@ | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Deployment | |||||
metadata: | |||||
name: default-http-backend | |||||
labels: | |||||
app: default-http-backend | |||||
namespace: ingress-nginx | |||||
spec: | |||||
replicas: 1 | |||||
template: | |||||
metadata: | |||||
labels: | |||||
app: default-http-backend | |||||
spec: | |||||
terminationGracePeriodSeconds: 60 | |||||
containers: | |||||
- name: default-http-backend | |||||
# Any image is permissable as long as: | |||||
# 1. It serves a 404 page at / | |||||
# 2. It serves 200 on a /healthz endpoint | |||||
image: gcr.io/google_containers/defaultbackend:1.4 | |||||
livenessProbe: | |||||
httpGet: | |||||
path: /healthz | |||||
port: 8080 | |||||
scheme: HTTP | |||||
initialDelaySeconds: 30 | |||||
timeoutSeconds: 5 | |||||
ports: | |||||
- containerPort: 8080 | |||||
resources: | |||||
limits: | |||||
cpu: 10m | |||||
memory: 20Mi | |||||
requests: | |||||
cpu: 10m | |||||
memory: 20Mi | |||||
--- | |||||
apiVersion: v1 | |||||
kind: Service | |||||
metadata: | |||||
name: default-http-backend | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app: default-http-backend | |||||
spec: | |||||
ports: | |||||
- port: 80 | |||||
targetPort: 8080 | |||||
selector: | |||||
app: default-http-backend |
@ -0,0 +1,3 @@ | |||||
data: | |||||
mvc_e: http://10.0.75.1/webmvc | |||||
@ -0,0 +1,3 @@ | |||||
data: | |||||
urls__IdentityUrl: http://10.0.75.1/identity | |||||
urls__mvc: http://10.0.75.1/webmvc |
@ -0,0 +1,39 @@ | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Ingress | |||||
metadata: | |||||
annotations: | |||||
ingress.kubernetes.io/ssl-redirect: "false" | |||||
kubernetes.io/ingress.class: nginx | |||||
nginx.ingress.kubernetes.io/ssl-redirect: "false" | |||||
labels: | |||||
app: webmvc | |||||
name: eshop-webmvc-loopback | |||||
namespace: default | |||||
spec: | |||||
rules: | |||||
- http: | |||||
paths: | |||||
- backend: | |||||
serviceName: webmvc | |||||
servicePort: http | |||||
path: /webmvc | |||||
--- | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Ingress | |||||
metadata: | |||||
annotations: | |||||
ingress.kubernetes.io/ssl-redirect: "false" | |||||
kubernetes.io/ingress.class: nginx | |||||
nginx.ingress.kubernetes.io/ssl-redirect: "false" | |||||
labels: | |||||
app: identity-api | |||||
name: eshop-identity-api-loopback | |||||
namespace: default | |||||
spec: | |||||
rules: | |||||
- http: | |||||
paths: | |||||
- backend: | |||||
serviceName: identity | |||||
servicePort: http | |||||
path: /identity |
@ -0,0 +1,238 @@ | |||||
apiVersion: v1 | |||||
kind: Namespace | |||||
metadata: | |||||
name: ingress-nginx | |||||
--- | |||||
kind: ConfigMap | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: nginx-configuration | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
--- | |||||
apiVersion: v1 | |||||
kind: ServiceAccount | |||||
metadata: | |||||
name: nginx-ingress-serviceaccount | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
--- | |||||
apiVersion: rbac.authorization.k8s.io/v1beta1 | |||||
kind: ClusterRole | |||||
metadata: | |||||
name: nginx-ingress-clusterrole | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
rules: | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- configmaps | |||||
- endpoints | |||||
- nodes | |||||
- pods | |||||
- secrets | |||||
verbs: | |||||
- list | |||||
- watch | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- nodes | |||||
verbs: | |||||
- get | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- services | |||||
verbs: | |||||
- get | |||||
- list | |||||
- watch | |||||
- apiGroups: | |||||
- "extensions" | |||||
resources: | |||||
- ingresses | |||||
verbs: | |||||
- get | |||||
- list | |||||
- watch | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- events | |||||
verbs: | |||||
- create | |||||
- patch | |||||
- apiGroups: | |||||
- "extensions" | |||||
resources: | |||||
- ingresses/status | |||||
verbs: | |||||
- update | |||||
--- | |||||
apiVersion: rbac.authorization.k8s.io/v1beta1 | |||||
kind: Role | |||||
metadata: | |||||
name: nginx-ingress-role | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
rules: | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- configmaps | |||||
- pods | |||||
- secrets | |||||
- namespaces | |||||
verbs: | |||||
- get | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- configmaps | |||||
resourceNames: | |||||
# Defaults to "<election-id>-<ingress-class>" | |||||
# Here: "<ingress-controller-leader>-<nginx>" | |||||
# This has to be adapted if you change either parameter | |||||
# when launching the nginx-ingress-controller. | |||||
- "ingress-controller-leader-nginx" | |||||
verbs: | |||||
- get | |||||
- update | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- configmaps | |||||
verbs: | |||||
- create | |||||
- apiGroups: | |||||
- "" | |||||
resources: | |||||
- endpoints | |||||
verbs: | |||||
- get | |||||
--- | |||||
apiVersion: rbac.authorization.k8s.io/v1beta1 | |||||
kind: RoleBinding | |||||
metadata: | |||||
name: nginx-ingress-role-nisa-binding | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
roleRef: | |||||
apiGroup: rbac.authorization.k8s.io | |||||
kind: Role | |||||
name: nginx-ingress-role | |||||
subjects: | |||||
- kind: ServiceAccount | |||||
name: nginx-ingress-serviceaccount | |||||
namespace: ingress-nginx | |||||
--- | |||||
apiVersion: rbac.authorization.k8s.io/v1beta1 | |||||
kind: ClusterRoleBinding | |||||
metadata: | |||||
name: nginx-ingress-clusterrole-nisa-binding | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
roleRef: | |||||
apiGroup: rbac.authorization.k8s.io | |||||
kind: ClusterRole | |||||
name: nginx-ingress-clusterrole | |||||
subjects: | |||||
- kind: ServiceAccount | |||||
name: nginx-ingress-serviceaccount | |||||
namespace: ingress-nginx | |||||
--- | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Deployment | |||||
metadata: | |||||
name: nginx-ingress-controller | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
spec: | |||||
replicas: 1 | |||||
selector: | |||||
matchLabels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
template: | |||||
metadata: | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
annotations: | |||||
prometheus.io/port: "10254" | |||||
prometheus.io/scrape: "true" | |||||
spec: | |||||
serviceAccountName: nginx-ingress-serviceaccount | |||||
containers: | |||||
- name: nginx-ingress-controller | |||||
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0 | |||||
args: | |||||
- /nginx-ingress-controller | |||||
- --configmap=$(POD_NAMESPACE)/nginx-configuration | |||||
- --publish-service=$(POD_NAMESPACE)/ingress-nginx | |||||
- --annotations-prefix=nginx.ingress.kubernetes.io | |||||
securityContext: | |||||
capabilities: | |||||
drop: | |||||
- ALL | |||||
add: | |||||
- NET_BIND_SERVICE | |||||
# www-data -> 33 | |||||
runAsUser: 33 | |||||
env: | |||||
- name: POD_NAME | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.name | |||||
- name: POD_NAMESPACE | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.namespace | |||||
ports: | |||||
- name: http | |||||
containerPort: 80 | |||||
- name: https | |||||
containerPort: 443 | |||||
livenessProbe: | |||||
failureThreshold: 3 | |||||
httpGet: | |||||
path: /healthz | |||||
port: 10254 | |||||
scheme: HTTP | |||||
initialDelaySeconds: 10 | |||||
periodSeconds: 10 | |||||
successThreshold: 1 | |||||
timeoutSeconds: 1 | |||||
readinessProbe: | |||||
failureThreshold: 3 | |||||
httpGet: | |||||
path: /healthz | |||||
port: 10254 | |||||
scheme: HTTP | |||||
periodSeconds: 10 | |||||
successThreshold: 1 | |||||
timeoutSeconds: 1 |
@ -1,4 +0,0 @@ | |||||
apiVersion: v1 | |||||
kind: Namespace | |||||
metadata: | |||||
name: ingress-nginx |
@ -1,40 +0,0 @@ | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Deployment | |||||
metadata: | |||||
name: nginx-ingress-controller | |||||
namespace: ingress-nginx | |||||
spec: | |||||
replicas: 1 | |||||
selector: | |||||
matchLabels: | |||||
app: ingress-nginx | |||||
template: | |||||
metadata: | |||||
labels: | |||||
app: ingress-nginx | |||||
spec: | |||||
containers: | |||||
- name: nginx-ingress-controller | |||||
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0 | |||||
args: | |||||
- /nginx-ingress-controller | |||||
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend | |||||
- --configmap=$(POD_NAMESPACE)/nginx-configuration | |||||
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services | |||||
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services | |||||
- --publish-service=$(POD_NAMESPACE)/ingress-nginx | |||||
- --annotations-prefix=nginx.ingress.kubernetes.io | |||||
env: | |||||
- name: POD_NAME | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.name | |||||
- name: POD_NAMESPACE | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.namespace | |||||
ports: | |||||
- name: http | |||||
containerPort: 80 | |||||
- name: https | |||||
containerPort: 443 |
@ -1,7 +0,0 @@ | |||||
[ | |||||
{ | |||||
'op': 'add', | |||||
'path': '/spec/template/spec/containers/0/args/-', | |||||
'value': '--publish-service=$(POD_NAMESPACE)/ingress-nginx' | |||||
} | |||||
] |
@ -0,0 +1,22 @@ | |||||
apiVersion: v1 | |||||
kind: Service | |||||
metadata: | |||||
name: ingress-nginx | |||||
namespace: ingress-nginx | |||||
labels: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx | |||||
spec: | |||||
type: NodePort | |||||
ports: | |||||
- name: http | |||||
port: 80 | |||||
targetPort: 80 | |||||
protocol: TCP | |||||
- name: https | |||||
port: 443 | |||||
targetPort: 443 | |||||
protocol: TCP | |||||
selector: | |||||
app.kubernetes.io/name: ingress-nginx | |||||
app.kubernetes.io/part-of: ingress-nginx |
@ -1,5 +0,0 @@ | |||||
kind: ConfigMap | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: tcp-services | |||||
namespace: ingress-nginx |
@ -1,5 +0,0 @@ | |||||
kind: ConfigMap | |||||
apiVersion: v1 | |||||
metadata: | |||||
name: udp-services | |||||
namespace: ingress-nginx |
@ -1,61 +0,0 @@ | |||||
apiVersion: extensions/v1beta1 | |||||
kind: Deployment | |||||
metadata: | |||||
name: nginx-ingress-controller | |||||
namespace: ingress-nginx | |||||
spec: | |||||
replicas: 1 | |||||
selector: | |||||
matchLabels: | |||||
app: ingress-nginx | |||||
template: | |||||
metadata: | |||||
labels: | |||||
app: ingress-nginx | |||||
annotations: | |||||
prometheus.io/port: '10254' | |||||
prometheus.io/scrape: 'true' | |||||
spec: | |||||
containers: | |||||
- name: nginx-ingress-controller | |||||
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0 | |||||
args: | |||||
- /nginx-ingress-controller | |||||
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend | |||||
- --configmap=$(POD_NAMESPACE)/nginx-configuration | |||||
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services | |||||
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services | |||||
- --annotations-prefix=nginx.ingress.kubernetes.io | |||||
env: | |||||
- name: POD_NAME | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.name | |||||
- name: POD_NAMESPACE | |||||
valueFrom: | |||||
fieldRef: | |||||
fieldPath: metadata.namespace | |||||
ports: | |||||
- name: http | |||||
containerPort: 80 | |||||
- name: https | |||||
containerPort: 443 | |||||
livenessProbe: | |||||
failureThreshold: 3 | |||||
httpGet: | |||||
path: /healthz | |||||
port: 10254 | |||||
scheme: HTTP | |||||
initialDelaySeconds: 10 | |||||
periodSeconds: 10 | |||||
successThreshold: 1 | |||||
timeoutSeconds: 1 | |||||
readinessProbe: | |||||
failureThreshold: 3 | |||||
httpGet: | |||||
path: /healthz | |||||
port: 10254 | |||||
scheme: HTTP | |||||
periodSeconds: 10 | |||||
successThreshold: 1 | |||||
timeoutSeconds: 1 |
@ -1,11 +1,16 @@ | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Microsoft.AspNetCore.Authentication; | |||||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Services | namespace Microsoft.eShopOnContainers.Services.Identity.API.Services | ||||
{ | { | ||||
public interface ILoginService<T> | public interface ILoginService<T> | ||||
{ | { | ||||
Task<bool> ValidateCredentials(T user, string password); | Task<bool> ValidateCredentials(T user, string password); | ||||
Task<T> FindByUsername(string user); | Task<T> FindByUsername(string user); | ||||
Task SignIn(T user); | Task SignIn(T user); | ||||
Task SignInAsync(T user, AuthenticationProperties properties, string authenticationMethod = null); | |||||
} | } | ||||
} | } |
@ -0,0 +1,62 @@ | |||||
using MediatR; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; | |||||
using Microsoft.Extensions.Logging; | |||||
using Ordering.API.Application.IntegrationEvents; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Behaviors | |||||
{ | |||||
public class TransactionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> | |||||
{ | |||||
private readonly ILogger<TransactionBehaviour<TRequest, TResponse>> _logger; | |||||
private readonly OrderingContext _dbContext; | |||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; | |||||
public TransactionBehaviour(OrderingContext dbContext, | |||||
IOrderingIntegrationEventService orderingIntegrationEventService, | |||||
ILogger<TransactionBehaviour<TRequest, TResponse>> logger) | |||||
{ | |||||
_dbContext = dbContext ?? throw new ArgumentException(nameof(OrderingContext)); | |||||
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentException(nameof(orderingIntegrationEventService)); | |||||
_logger = logger ?? throw new ArgumentException(nameof(ILogger)); | |||||
} | |||||
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) | |||||
{ | |||||
TResponse response = default(TResponse); | |||||
try | |||||
{ | |||||
var strategy = _dbContext.Database.CreateExecutionStrategy(); | |||||
await strategy.ExecuteAsync(async () => | |||||
{ | |||||
_logger.LogInformation($"Begin transaction {typeof(TRequest).Name}"); | |||||
await _dbContext.BeginTransactionAsync(); | |||||
response = await next(); | |||||
await _dbContext.CommitTransactionAsync(); | |||||
_logger.LogInformation($"Committed transaction {typeof(TRequest).Name}"); | |||||
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(); | |||||
}); | |||||
return response; | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
_logger.LogInformation($"Rollback transaction executed {typeof(TRequest).Name}"); | |||||
_dbContext.RollbackTransaction(); | |||||
throw; | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
using MediatR; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Runtime.Serialization; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class SetAwaitingValidationOrderStatusCommand : IRequest<bool> | |||||
{ | |||||
[DataMember] | |||||
public int OrderNumber { get; private set; } | |||||
public SetAwaitingValidationOrderStatusCommand(int orderNumber) | |||||
{ | |||||
OrderNumber = orderNumber; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,52 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
// Regular CommandHandler | |||||
public class SetAwaitingValidationOrderStatusCommandHandler : IRequestHandler<SetAwaitingValidationOrderStatusCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public SetAwaitingValidationOrderStatusCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// graceperiod has finished | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(SetAwaitingValidationOrderStatusCommand command, CancellationToken cancellationToken) | |||||
{ | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
if(orderToUpdate == null) | |||||
{ | |||||
return false; | |||||
} | |||||
orderToUpdate.SetAwaitingValidationStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
// Use for Idempotency in Command process | |||||
public class SetAwaitingValidationIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetAwaitingValidationOrderStatusCommand, bool> | |||||
{ | |||||
public SetAwaitingValidationIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
using MediatR; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Runtime.Serialization; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class SetPaidOrderStatusCommand : IRequest<bool> | |||||
{ | |||||
[DataMember] | |||||
public int OrderNumber { get; private set; } | |||||
public SetPaidOrderStatusCommand(int orderNumber) | |||||
{ | |||||
OrderNumber = orderNumber; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,55 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
// Regular CommandHandler | |||||
public class SetPaidOrderStatusCommandHandler : IRequestHandler<SetPaidOrderStatusCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public SetPaidOrderStatusCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// Shipment service confirms the payment | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(SetPaidOrderStatusCommand command, CancellationToken cancellationToken) | |||||
{ | |||||
// Simulate a work time for validating the payment | |||||
await Task.Delay(10000); | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
if(orderToUpdate == null) | |||||
{ | |||||
return false; | |||||
} | |||||
orderToUpdate.SetPaidStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
// Use for Idempotency in Command process | |||||
public class SetPaidIdentifiedOrderStatusCommandHandler : IdentifiedCommandHandler<SetPaidOrderStatusCommand, bool> | |||||
{ | |||||
public SetPaidIdentifiedOrderStatusCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
using MediatR; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Runtime.Serialization; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class SetStockConfirmedOrderStatusCommand : IRequest<bool> | |||||
{ | |||||
[DataMember] | |||||
public int OrderNumber { get; private set; } | |||||
public SetStockConfirmedOrderStatusCommand(int orderNumber) | |||||
{ | |||||
OrderNumber = orderNumber; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,55 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
// Regular CommandHandler | |||||
public class SetStockConfirmedOrderStatusCommandHandler : IRequestHandler<SetStockConfirmedOrderStatusCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public SetStockConfirmedOrderStatusCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// Stock service confirms the request | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(SetStockConfirmedOrderStatusCommand command, CancellationToken cancellationToken) | |||||
{ | |||||
// Simulate a work time for confirming the stock | |||||
await Task.Delay(10000); | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
if(orderToUpdate == null) | |||||
{ | |||||
return false; | |||||
} | |||||
orderToUpdate.SetStockConfirmedStatus(); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
// Use for Idempotency in Command process | |||||
public class SetStockConfirmedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockConfirmedOrderStatusCommand, bool> | |||||
{ | |||||
public SetStockConfirmedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,25 @@ | |||||
using MediatR; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Runtime.Serialization; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
public class SetStockRejectedOrderStatusCommand : IRequest<bool> | |||||
{ | |||||
[DataMember] | |||||
public int OrderNumber { get; private set; } | |||||
[DataMember] | |||||
public List<int> OrderStockItems { get; private set; } | |||||
public SetStockRejectedOrderStatusCommand(int orderNumber, List<int> orderStockItems) | |||||
{ | |||||
OrderNumber = orderNumber; | |||||
OrderStockItems = orderStockItems; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,56 @@ | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
namespace Ordering.API.Application.Commands | |||||
{ | |||||
// Regular CommandHandler | |||||
public class SetStockRejectedOrderStatusCommandHandler : IRequestHandler<SetStockRejectedOrderStatusCommand, bool> | |||||
{ | |||||
private readonly IOrderRepository _orderRepository; | |||||
public SetStockRejectedOrderStatusCommandHandler(IOrderRepository orderRepository) | |||||
{ | |||||
_orderRepository = orderRepository; | |||||
} | |||||
/// <summary> | |||||
/// Handler which processes the command when | |||||
/// Stock service rejects the request | |||||
/// </summary> | |||||
/// <param name="command"></param> | |||||
/// <returns></returns> | |||||
public async Task<bool> Handle(SetStockRejectedOrderStatusCommand command, CancellationToken cancellationToken) | |||||
{ | |||||
// Simulate a work time for rejecting the stock | |||||
await Task.Delay(10000); | |||||
var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber); | |||||
if(orderToUpdate == null) | |||||
{ | |||||
return false; | |||||
} | |||||
orderToUpdate.SetCancelledStatusWhenStockIsRejected(command.OrderStockItems); | |||||
return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
} | |||||
} | |||||
// Use for Idempotency in Command process | |||||
public class SetStockRejectedOrderStatusIdenfifiedCommandHandler : IdentifiedCommandHandler<SetStockRejectedOrderStatusCommand, bool> | |||||
{ | |||||
public SetStockRejectedOrderStatusIdenfifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | |||||
{ | |||||
} | |||||
protected override bool CreateResultForDuplicateRequest() | |||||
{ | |||||
return true; // Ignore duplicate requests for processing order. | |||||
} | |||||
} | |||||
} |
@ -1,27 +1,27 @@ | |||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling | namespace Ordering.API.Application.IntegrationEvents.EventHandling | ||||
{ | { | ||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | ||||
using Ordering.API.Application.Commands; | |||||
using Ordering.API.Application.IntegrationEvents.Events; | using Ordering.API.Application.IntegrationEvents.Events; | ||||
using System; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
public class OrderPaymentFailedIntegrationEventHandler : | public class OrderPaymentFailedIntegrationEventHandler : | ||||
IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent> | IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent> | ||||
{ | { | ||||
private readonly IOrderRepository _orderRepository; | |||||
private readonly IMediator _mediator; | |||||
public OrderPaymentFailedIntegrationEventHandler(IOrderRepository orderRepository) | |||||
public OrderPaymentFailedIntegrationEventHandler(IMediator mediator) | |||||
{ | { | ||||
_orderRepository = orderRepository; | |||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); | |||||
} | } | ||||
public async Task Handle(OrderPaymentFailedIntegrationEvent @event) | public async Task Handle(OrderPaymentFailedIntegrationEvent @event) | ||||
{ | { | ||||
var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | |||||
orderToUpdate.SetCancelledStatus(); | |||||
await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
var command = new CancelOrderCommand(@event.OrderId); | |||||
await _mediator.Send(command); | |||||
} | } | ||||
} | } | ||||
} | } |
@ -1,30 +1,27 @@ | |||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling | namespace Ordering.API.Application.IntegrationEvents.EventHandling | ||||
{ | { | ||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | ||||
using Ordering.API.Application.Commands; | |||||
using Ordering.API.Application.IntegrationEvents.Events; | using Ordering.API.Application.IntegrationEvents.Events; | ||||
using System; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
public class OrderPaymentSuccededIntegrationEventHandler : | public class OrderPaymentSuccededIntegrationEventHandler : | ||||
IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent> | IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent> | ||||
{ | { | ||||
private readonly IOrderRepository _orderRepository; | |||||
private readonly IMediator _mediator; | |||||
public OrderPaymentSuccededIntegrationEventHandler(IOrderRepository orderRepository) | |||||
public OrderPaymentSuccededIntegrationEventHandler(IMediator mediator) | |||||
{ | { | ||||
_orderRepository = orderRepository; | |||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); | |||||
} | } | ||||
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event) | public async Task Handle(OrderPaymentSuccededIntegrationEvent @event) | ||||
{ | { | ||||
// Simulate a work time for validating the payment | |||||
await Task.Delay(10000); | |||||
var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); | |||||
orderToUpdate.SetPaidStatus(); | |||||
await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | |||||
var command = new SetPaidOrderStatusCommand(@event.OrderId); | |||||
await _mediator.Send(command); | |||||
} | } | ||||
} | } | ||||
} | } |