Browse Source

Added RFID use case, and support for events being saved in the tenants microservice. The tenant manager is responsible whether a certain event is customised for a certain tenant.

pull/1240/head
espent1004 5 years ago
parent
commit
e6296df5d1
13 changed files with 299 additions and 190 deletions
  1. +6
    -2
      src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs
  2. +31
    -17
      src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs
  3. +0
    -133
      src/Services/TenantCustomisations/TenantACustomisations/Controllers/OrderStatusChangedToSubmittedIntegrationEventsController.cs
  4. +183
    -0
      src/Services/TenantCustomisations/TenantACustomisations/Controllers/SavedEventsController.cs
  5. +11
    -0
      src/Services/TenantCustomisations/TenantACustomisations/Database/SavedEvent.cs
  6. +1
    -1
      src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs
  7. +30
    -0
      src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs
  8. +14
    -0
      src/Services/TenantManager/TenantManager/Controllers/CustomisationsController.cs
  9. +11
    -32
      src/Services/TenantManager/TenantManager/Database/DbInitializer.cs
  10. +8
    -1
      src/Services/TenantManager/TenantManager/Models/Customisation.cs
  11. +1
    -1
      src/Services/TenantManager/TenantManager/Models/Methods.cs
  12. +2
    -2
      src/Services/TenantManager/TenantManager/Models/Tenant.cs
  13. +1
    -1
      src/Web/WebMVC/Controllers/OrderController.cs

+ 6
- 2
src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs View File

@ -10,6 +10,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
Id = Guid.NewGuid();
CreationDate = DateTime.UtcNow;
CheckForCustomisation = true;
TenantId = 1;
}
public IntegrationEvent(Boolean checkForCustomisation)
@ -17,6 +18,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
Id = Guid.NewGuid();
CreationDate = DateTime.UtcNow;
CheckForCustomisation = checkForCustomisation;
TenantId = 1;
}
[JsonConstructor]
@ -24,6 +26,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
{
Id = id;
CreationDate = createDate;
TenantId = 1;
}
[JsonProperty]
@ -35,7 +38,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
[JsonProperty]
public Boolean CheckForCustomisation { get; set; }
/*[JsonProperty]
public String TenantId { get; set; }*/
//TODO fix this somehow
[JsonProperty]
public int TenantId { get; set; }
}
}

+ 31
- 17
src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs View File

@ -16,6 +16,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
@ -273,37 +274,44 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
return channel;
}
private async void SendEventToTenant(Object @event)
private async void SendEventToTenant(String content, String id, String eventName)
{
string myJson = JsonConvert.SerializeObject(@event);
var temp = new SavedEvent();
temp.Content = content;
temp.SavedEventId = id;
temp.EventName = eventName;
string myJson = JsonConvert.SerializeObject(temp);
using (var client = new HttpClient())
{
try
{
//TODO replace URL with response from tenantmanager
var response = await client.PostAsync(
tenantACustomisationUrl + "api/OrderStatusChangedToSubmittedIntegrationEvents",
tenantACustomisationUrl + "api/SavedEvents",
new StringContent(myJson, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
_logger.LogInformation("----- Event sent to tenant{@event} -----", @event);
_logger.LogInformation("----- Event sent to tenant{@id} -----", id);
}
catch (Exception e)
{
_logger.LogInformation("----- Exception{@e} -- Event{@event} -----", e, @event);
_logger.LogInformation("----- Exception{@e} -- Event{@id} -----", e, @id);
}
}
}
private async Task<Boolean> IsEventCustomised(String eventName, String tenantId)
private async Task<Boolean> IsEventCustomised(String eventName, int tenantId)
{
CustomisationInfo customisationInfo = new CustomisationInfo();
customisationInfo.EventName = eventName;
customisationInfo.TenantId = tenantId;
Boolean isCustomised = false;
var builder = new UriBuilder(tenantManagerUrl + "api/Customisations");
var builder = new UriBuilder(tenantManagerUrl + "api/Customisations/IsCustomised");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["eventName"] = eventName;
query["tenantId"] = tenantId;
query["tenantId"] = tenantId.ToString();
builder.Query = query.ToString();
string url = builder.ToString();
@ -355,19 +363,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName);
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
//IsEventCustomised(eventName, integrationEvent.TenantId);
if (eventName.Equals("OrderStatusChangedToSubmittedIntegrationEvent") &&
integrationEvent is IntegrationEvent) //TODO replace with tenantmanager
if (integrationEvent is IntegrationEvent evt && IsEventCustomised(eventName, evt.TenantId).Result) //TODO replace with tenantmanager
{
//Casting
IntegrationEvent evt = (IntegrationEvent) integrationEvent;
//Checking if event should be sent to tenant, or handled normally
//Can instead create an endpoint in the tenant manager that also handles all the events that a tenant wants to postpone
//Additionally, an endpoint in the tenant manager is required, where the tenant
//Issue with the tenant knowing the id of the event
if (evt.CheckForCustomisation)
{
SendEventToTenant(integrationEvent);
SendEventToTenant(message, evt.Id.ToString(), eventName);
break;
}
}
@ -387,4 +388,17 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
}
}
}
}
class SavedEvent
{
public string SavedEventId { get; set; }
public string Content { get; set; }
public String EventName { get; set; }
}
class CustomisationInfo
{
public string EventName { get; set; }
public int TenantId { get; set; }
}

+ 0
- 133
src/Services/TenantCustomisations/TenantACustomisations/Controllers/OrderStatusChangedToSubmittedIntegrationEventsController.cs View File

@ -1,133 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.Extensions.Logging;
using TenantACustomisations.Database;
using TenantACustomisations.IntegrationEvents.Events;
namespace TenantACustomisations.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class OrderStatusChangedToSubmittedIntegrationEventsController : ControllerBase
{
private readonly TenantAContext _context;
private readonly IEventBus _eventBus;
private readonly ILogger<OrderStatusChangedToSubmittedIntegrationEventsController> _logger;
public OrderStatusChangedToSubmittedIntegrationEventsController(TenantAContext context, IEventBus eventBus, ILogger<OrderStatusChangedToSubmittedIntegrationEventsController> logger)
{
_context = context;
_eventBus = eventBus;
_logger = logger;
}
// GET: api/OrderStatusChangedToSubmittedIntegrationEvents
[HttpGet]
public async Task<ActionResult<IEnumerable<OrderStatusChangedToSubmittedIntegrationEvent>>> GetOrderStatusChangedToSubmittedIntegrationEvent(String orderId)
{
if (String.IsNullOrEmpty(orderId))
{
return await _context.OrderStatusChangedToSubmittedIntegrationEvent.ToListAsync();
}
else
{
var orderStatusChangedToSubmittedIntegrationEvent = _context.OrderStatusChangedToSubmittedIntegrationEvent.Where(x => x.OrderId == Int32.Parse(orderId)).ToListAsync();
return await orderStatusChangedToSubmittedIntegrationEvent;
}
}
// GET: api/OrderStatusChangedToSubmittedIntegrationEvents/5
[HttpGet("{id}")]
public async Task<ActionResult<OrderStatusChangedToSubmittedIntegrationEvent>> GetOrderStatusChangedToSubmittedIntegrationEvent(Guid id)
{
var orderStatusChangedToSubmittedIntegrationEvent = await _context.OrderStatusChangedToSubmittedIntegrationEvent.FindAsync(id);
if (orderStatusChangedToSubmittedIntegrationEvent == null)
{
return NotFound();
}
return orderStatusChangedToSubmittedIntegrationEvent;
}
// PUT: api/OrderStatusChangedToSubmittedIntegrationEvents/5
[HttpPut("{id}")]
public async Task<IActionResult> PutOrderStatusChangedToSubmittedIntegrationEvent(Guid id, OrderStatusChangedToSubmittedIntegrationEvent orderStatusChangedToSubmittedIntegrationEvent)
{
if (id != orderStatusChangedToSubmittedIntegrationEvent.Id)
{
return BadRequest();
}
_context.Entry(orderStatusChangedToSubmittedIntegrationEvent).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!OrderStatusChangedToSubmittedIntegrationEventExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/OrderStatusChangedToSubmittedIntegrationEvents
[HttpPost]
public async Task<ActionResult<OrderStatusChangedToSubmittedIntegrationEvent>> PostOrderStatusChangedToSubmittedIntegrationEvent(OrderStatusChangedToSubmittedIntegrationEvent orderStatusChangedToSubmittedIntegrationEvent)
{
_context.OrderStatusChangedToSubmittedIntegrationEvent.Add(orderStatusChangedToSubmittedIntegrationEvent);
await _context.SaveChangesAsync();
return CreatedAtAction("GetOrderStatusChangedToSubmittedIntegrationEvent", new { id = orderStatusChangedToSubmittedIntegrationEvent.Id }, orderStatusChangedToSubmittedIntegrationEvent);
}
// DELETE: api/OrderStatusChangedToSubmittedIntegrationEvents/5
[HttpDelete("{id}")]
public async Task<ActionResult<OrderStatusChangedToSubmittedIntegrationEvent>> DeleteOrderStatusChangedToSubmittedIntegrationEvent(Guid id)
{
var orderStatusChangedToSubmittedIntegrationEvent = await _context.OrderStatusChangedToSubmittedIntegrationEvent.FindAsync(id);
if (orderStatusChangedToSubmittedIntegrationEvent == null)
{
return NotFound();
}
try
{
_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController - ({@IntegrationEvent})", orderStatusChangedToSubmittedIntegrationEvent.Id, orderStatusChangedToSubmittedIntegrationEvent);
orderStatusChangedToSubmittedIntegrationEvent.CheckForCustomisation = false;
_eventBus.Publish(orderStatusChangedToSubmittedIntegrationEvent);
_context.OrderStatusChangedToSubmittedIntegrationEvent.Remove(orderStatusChangedToSubmittedIntegrationEvent);
await _context.SaveChangesAsync();
return orderStatusChangedToSubmittedIntegrationEvent;
}
catch (Exception ex)
{
_logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController", orderStatusChangedToSubmittedIntegrationEvent.Id);
throw;
}
}
private bool OrderStatusChangedToSubmittedIntegrationEventExists(Guid id)
{
return _context.OrderStatusChangedToSubmittedIntegrationEvent.Any(e => e.Id == id);
}
}
}

+ 183
- 0
src/Services/TenantCustomisations/TenantACustomisations/Controllers/SavedEventsController.cs View File

@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using TenantACustomisations.Database;
using TenantACustomisations.IntegrationEvents.Events;
namespace TenantACustomisations.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SavedEventsController : ControllerBase
{
private readonly TenantAContext _context;
private readonly ILogger<SavedEventsController> _logger;
private readonly IEventBus _eventBus;
private List<Type> types = new List<Type>()
{
typeof(OrderStatusChangedToSubmittedIntegrationEvent),
typeof(OrderStatusChangedToAwaitingValidationIntegrationEvent)
};
public SavedEventsController(TenantAContext context, ILogger<SavedEventsController> logger, IEventBus eventBus)
{
_context = context;
_logger = logger;
_eventBus = eventBus;
}
// GET: api/SavedEvents
[HttpGet]
public async Task<ActionResult<IEnumerable<SavedEvent>>> GetSavedEvent(String orderId)
{
if (String.IsNullOrEmpty(orderId))
{
return await _context.SavedEvent.ToListAsync();
}
//Getting saved events
var savedEvents = await _context.SavedEvent.ToListAsync();
//Returning if list is empty
if (savedEvents.Count == 0)
{
return NotFound();
}
List<IntegrationEvent> events = new List<IntegrationEvent>();
//Converting events to actual type
savedEvents.ForEach(e =>
{
var integrationEvent =JsonConvert.DeserializeObject(e.Content, GetEventTypeByName(e.EventName));
IntegrationEvent evt = (IntegrationEvent)integrationEvent;
events.Add(evt);
});
bool found = false;
//Casting to class to check the orderId
events.ForEach(e =>
{
if(e is OrderStatusChangedToAwaitingValidationIntegrationEvent)
{
OrderStatusChangedToAwaitingValidationIntegrationEvent evt = (OrderStatusChangedToAwaitingValidationIntegrationEvent)e;
if (evt.OrderId == Int32.Parse(orderId))
{
found = true;
}
}
else if(e is OrderStatusChangedToSubmittedIntegrationEvent)
{
OrderStatusChangedToSubmittedIntegrationEvent evt = (OrderStatusChangedToSubmittedIntegrationEvent)e;
if (evt.OrderId == Int32.Parse(orderId))
{
found = true;
}
}
});
if (!found)
{
return NotFound();
}
return savedEvents;
}
// PUT: api/SavedEvents/5
[HttpPut("{id}")]
public async Task<IActionResult> PutSavedEvent(string id, SavedEvent savedEvent)
{
if (id != savedEvent.SavedEventId)
{
return BadRequest();
}
_context.Entry(savedEvent).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!SavedEventExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/SavedEvents
[HttpPost]
public async Task<ActionResult<SavedEvent>> PostSavedEvent(SavedEvent savedEvent)
{
_context.SavedEvent.Add(savedEvent);
await _context.SaveChangesAsync();
return CreatedAtAction("GetSavedEvent", new {id = savedEvent.SavedEventId}, savedEvent);
}
// DELETE: api/SavedEvents/5
[HttpDelete("{id}")]
public async Task<ActionResult<SavedEvent>> DeleteSavedEvent(string id)
{
var savedEvent = await _context.SavedEvent.FindAsync(id);
if (savedEvent == null)
{
return NotFound();
}
var integrationEvent =
JsonConvert.DeserializeObject(savedEvent.Content, GetEventTypeByName(savedEvent.EventName));
IntegrationEvent evt = (IntegrationEvent) integrationEvent;
try
{
_logger.LogInformation(
"----- Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController - ({@IntegrationEvent})",
evt.Id, evt);
evt.CheckForCustomisation = false;
_eventBus.Publish(evt);
_context.SavedEvent.Remove(savedEvent);
await _context.SaveChangesAsync();
return savedEvent;
}
catch (Exception ex)
{
_logger.LogError(ex,
"ERROR Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController",
evt.Id);
throw;
}
_context.SavedEvent.Remove(savedEvent);
await _context.SaveChangesAsync();
return savedEvent;
}
private bool SavedEventExists(string id)
{
return _context.SavedEvent.Any(e => e.SavedEventId == id);
}
private Type GetEventTypeByName(string eventName) => types.SingleOrDefault(t => t.Name == eventName);
}
}

+ 11
- 0
src/Services/TenantCustomisations/TenantACustomisations/Database/SavedEvent.cs View File

@ -0,0 +1,11 @@
using System;
namespace TenantACustomisations.Database
{
public class SavedEvent
{
public string SavedEventId { get; set; }
public string Content { get; set; }
public String EventName { get; set; }
}
}

+ 1
- 1
src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs View File

@ -18,7 +18,7 @@ namespace TenantACustomisations.Database
public DbSet<ShippingInformation> ShippingInformation { get; set; }
public DbSet<OrderStatusChangedToSubmittedIntegrationEvent> OrderStatusChangedToSubmittedIntegrationEvent
public DbSet<SavedEvent> SavedEvent
{
get;
set;


+ 30
- 0
src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToAwaitingValidationIntegrationEvent.cs View File

@ -0,0 +1,30 @@
using System.Collections.Generic;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
namespace TenantACustomisations.IntegrationEvents.Events
{
public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }
public IEnumerable<OrderStockItem> OrderStockItems { get; }
public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId,
IEnumerable<OrderStockItem> orderStockItems)
{
OrderId = orderId;
OrderStockItems = orderStockItems;
}
}
public class OrderStockItem
{
public int ProductId { get; }
public int Units { get; }
public OrderStockItem(int productId, int units)
{
ProductId = productId;
Units = units;
}
}
}

+ 14
- 0
src/Services/TenantManager/TenantManager/Controllers/CustomisationsController.cs View File

@ -41,6 +41,20 @@ namespace TenantManager.Controllers
return customisation;
}
// GET: api/Customisations/5
[HttpGet("isCustomised")]
public async Task<ActionResult<Boolean>> IsCustomised(String eventName, int tenantId)
{
var customisation = await _context.Customisation.Include(c => c.Method).Include(c => c.Tenant).Where(c => c.Method.MethodName.Equals(eventName) && c.TenantId == tenantId).FirstOrDefaultAsync();
if (customisation == null)
{
return false;
}
return true;
}
// PUT: api/Customisations/5
[HttpPut("{id}")]


+ 11
- 32
src/Services/TenantManager/TenantManager/Database/DbInitializer.cs View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Linq;
using TenantManager.Models;
namespace TenantManager.Database
@ -17,28 +14,13 @@ namespace TenantManager.Database
return;
}
var tenant1 = new Tenant() { TenantName = "Tekna" };
var tenant2 = new Tenant() { TenantName = "NITO" };
var tenant3 = new Tenant() { TenantName = "LO" };
var tenant1 = new Tenant { TenantName = "Tekna" };
context.Tenant.Add(tenant1);
var method1 = new Method { MethodName = "OrderStatusChangedToSubmittedIntegrationEvent" };
var method2 = new Method { MethodName = "OrderStatusChangedToAwaitingValidationIntegrationEvent" };
var tenants = new Tenant[]
{
tenant1,
tenant2,
tenant3
};
foreach(Tenant t in tenants)
{
context.Tenant.Add(t);
}
context.SaveChanges();
var method1 = new Method() { MethodName = "GetPrice" };
var method2 = new Method() { MethodName = "GetItem" };
var methods = new Method[]
var methods = new[]
{
method1,
method2
@ -48,14 +30,11 @@ namespace TenantManager.Database
{
context.Method.Add(m);
}
context.SaveChanges();
var customisations = new Customisation[]
var customisations = new[]
{
new Customisation(){Tenant=tenant1, Method=method1 },
new Customisation(){Tenant=tenant1, Method=method2},
new Customisation(){Tenant=tenant2, Method=method1 }
new Customisation {Tenant=tenant1, Method=method1 },
new Customisation {Tenant=tenant1, Method=method2}
};
foreach(Customisation c in customisations)


+ 8
- 1
src/Services/TenantManager/TenantManager/Models/Customisation.cs View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
@ -8,9 +9,15 @@ namespace TenantManager.Models
public class Customisation
{
public int CustomisationId { get; set; }
//Foreign keys
public int TenantId { get; set; }
public virtual Tenant Tenant { get; set; }
public int MethodId { get; set; }
[ForeignKey("TenantId")]
public virtual Tenant Tenant { get; set; }
[ForeignKey("MethodId")]
public virtual Method Method { get; set; }
}
}

+ 1
- 1
src/Services/TenantManager/TenantManager/Models/Methods.cs View File

@ -10,6 +10,6 @@ namespace TenantManager.Models
{
public int MethodId { get; set; }
public String MethodName { get; set; }
public ICollection<Customisation> Customisations { get; set; }
public List<Customisation> Customisations { get; set; }
}
}

+ 2
- 2
src/Services/TenantManager/TenantManager/Models/Tenant.cs View File

@ -10,7 +10,7 @@ namespace TenantManager.Models
{
public String TenantName { get; set; }
[Key]
public long TenantId { get; set; }
public ICollection<Customisation> Customisations { get; set; }
public int TenantId { get; set; }
public List<Customisation> Customisations { get; set; }
}
}

+ 1
- 1
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -102,7 +102,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
private async Task<Boolean> AllGoodsRFIDScanned(String orderId)
{
var builder = new UriBuilder(tenantACustomisationsUrl + "api/OrderStatusChangedToSubmittedIntegrationEvents");
var builder = new UriBuilder(tenantACustomisationsUrl + "api/SavedEvents");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["orderId"] = orderId;


Loading…
Cancel
Save