Since shortly you can use Event Grid in Azure. The idea is to provide you with a "cloud event system". An application that wants to trigger an event, sends a message to the event grid. Other applications can subscribe to the event grid for receiving events.
This kind of looks interesting to me, for using this in a microservice-architecture. In a microservice-architecure each microservice should have it's own domain data and logic. So how do you keep the different microservices consistent? One possibility is that a microservice posts an event on the event grid. The other microservices that are interested in the event can respond to it, for getting eventual consistency.
Most of the demos you can find on the internet use Azure Functions for reacting to the events. Information on how to make your own REST service respond is a bit spread, so I just thought I could put an example together here.
Some general information can be found here
Sending events
Start by creating an event grid (obviously...) in the portal.
Image 1: Creating an Event Grid in the portal
As with many Azure offering you get two Access keys.You'll need one of these for sending event-information. Sending event is actually just calling a REST-service, passing a key in the header.
HttpClient client = new HttpClient { BaseAddress = new Uri("https://mvwgrid.westeurope-1.eventgrid.azure.net/api/") };
client.DefaultRequestHeaders.Add("aeg-sas-key", "vnx.....yD4C8=");
The event-information we'll send needs at least some custom data, a subject, an event-time, a unique id and an event-type. So we'll create a generic class for that.
public class GridEvent<T>
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Subject { get; set; }
public string EventType { get; set; }
public DateTime EventTime { get; set; } = DateTime.Now;
public T Data { get; set; }
}
In my case I'm imitating an order-process. So my data will be an order with some orderdetails.
[
{
"id":"35d85def-0991-43be-be98-5f8c35b0c3d7",
"subject":"1",
"eventType":"OrderProcessed","eventTime":"2018-03-27T18:01:51.4765547+02:00",
"data":
{
"orderId":1,
"customerName":"U2U Training",
"orderLines":
[
{"quantity":12,"productName":"WestVleteren 12"},{"quantity":22,"productName":"Rochefort 10"}
]
}
}
]
public class Order
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public List<OrderLine> OrderLines { get; set; } = new List<OrderLine>();
}
public class OrderLine
{
public int Quantity { get; set; }
public string ProductName { get; set; }
}
So my event looks like this:
Order order = new Order
{
CustomerName = "U2U Training",
OrderId = 1,
OrderLines = new List<OrderLine>() { line1,line2}
};
GridEvent<Order> ev = new GridEvent<Order>()
{
Data = order,
Subject = order.OrderId.ToString(),
EventType = "OrderProcessed"
};
If you look to the JSON-structure, you can see that even for one event, I have to pass a collection. So:
List<GridEvent<Order>> lgo = new List<GridEvent<Order>> { ev }
var resp = await client.PostAsJsonAsync("events", lgo);
Registering an event-receiver
Sending events is fairly simple. The registering-part took me some more time to figure out. You can register an event-receiver in the portal.
Image 2: Registration of an event-receiver
I'm running locally, meaning on localhost, which cannot be used in this scenario. You can see from the screenshot above that we're using Ngrok for solving this. You can download this little gem here.
At the moment of registration, the event grid posts a message to the Subscriber-endpoint, with eventtype Microsoft.EventGrid.SubscriptionValidationEvent
containing a validationCode. Your event-receiver needs to return this code as confirmation. The receiving message will again be formatted as the JSON-example above. So we can use our GridEvent<T>
class again, this time using ValidationInfo
as data, and responding with a SubscriptionResponse
.
public class ValidationInfo
{
public string ValidationCode { get; set; }
}
public class SubscriptionResponse
{
public SubscriptionResponse(string validationCode)
{
ValidationResponse = validationCode;
}
public string ValidationResponse { get; set; }
}
So our code for returning the validationinfo looks like this :
public ActionResult PostEvent()
{
Stream s = Request.Body;
StreamReader reader = new StreamReader(s);
var body = reader.ReadToEnd();
var eventInfo = JsonConvert.DeserializeObject<List<GridEvent<ValidationInfo>>>(body);
var evt = eventInfo[0];
if (evt.EventType== "Microsoft.EventGrid.SubscriptionValidationEvent")
{
return Ok(new SubscriptionResponse(evt.Data.ValidationCode));
}
//more...
}
And of course, if it's another event we're getting, we'll just process the data...