@ -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 | |||
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 Microsoft.AspNetCore.Authentication; | |||
namespace Microsoft.eShopOnContainers.Services.Identity.API.Services | |||
{ | |||
public interface ILoginService<T> | |||
{ | |||
Task<bool> ValidateCredentials(T user, string password); | |||
Task<T> FindByUsername(string 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 | |||
{ | |||
using MediatR; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||
using Ordering.API.Application.Commands; | |||
using Ordering.API.Application.IntegrationEvents.Events; | |||
using System; | |||
using System.Threading.Tasks; | |||
public class OrderPaymentFailedIntegrationEventHandler : | |||
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) | |||
{ | |||
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 | |||
{ | |||
using MediatR; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; | |||
using Ordering.API.Application.Commands; | |||
using Ordering.API.Application.IntegrationEvents.Events; | |||
using System; | |||
using System.Threading.Tasks; | |||
public class OrderPaymentSuccededIntegrationEventHandler : | |||
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) | |||
{ | |||
// 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); | |||
} | |||
} | |||
} |