From 442314ae23d4d78e45a1538e2974ed923c267975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20M=2E=20Olesen?= <62885@grundfos.com> Date: Tue, 16 Jan 2018 07:51:19 +0100 Subject: [PATCH] Override of default mapping between event and handler now possible --- README.md | 33 ++++++++++++++ SharpEventGridServer.sln | 8 +++- SharpEventGridServer/EventGridMapper.cs | 23 ++++++++++ SharpEventGridServer/EventGridOptions.cs | 32 ++++++++------ .../SharpEventGridServer.csproj | 1 + .../Controllers/SendEventsController.cs | 44 +++++++++++++++++++ .../EventHandlers/DefaultMappingHandler.cs | 12 +++++ .../mySubject_NewCustomerEventHandler.cs | 20 +++++++++ .../mySubject_SomeEventHandler.cs | 12 +++++ .../NewCustomerEvent.cs | 5 +++ SharpMappingOverrideSample/Program.cs | 18 ++++++++ .../Properties/launchSettings.json | 29 ++++++++++++ .../Services/Database.cs | 9 ++++ .../Services/IDatabase.cs | 7 +++ .../SharpMappingOverrideSample.csproj | 23 ++++++++++ SharpMappingOverrideSample/Startup.cs | 43 ++++++++++++++++++ .../SubjectConventionMapper.cs | 29 ++++++++++++ .../appsettings.Development.json | 10 +++++ SharpMappingOverrideSample/appsettings.json | 15 +++++++ 19 files changed, 359 insertions(+), 14 deletions(-) create mode 100644 SharpEventGridServer/EventGridMapper.cs create mode 100644 SharpMappingOverrideSample/Controllers/SendEventsController.cs create mode 100644 SharpMappingOverrideSample/EventHandlers/DefaultMappingHandler.cs create mode 100644 SharpMappingOverrideSample/EventHandlers/mySubject_NewCustomerEventHandler.cs create mode 100644 SharpMappingOverrideSample/EventHandlers/mySubject_SomeEventHandler.cs create mode 100644 SharpMappingOverrideSample/NewCustomerEvent.cs create mode 100644 SharpMappingOverrideSample/Program.cs create mode 100644 SharpMappingOverrideSample/Properties/launchSettings.json create mode 100644 SharpMappingOverrideSample/Services/Database.cs create mode 100644 SharpMappingOverrideSample/Services/IDatabase.cs create mode 100644 SharpMappingOverrideSample/SharpMappingOverrideSample.csproj create mode 100644 SharpMappingOverrideSample/Startup.cs create mode 100644 SharpMappingOverrideSample/SubjectConventionMapper.cs create mode 100644 SharpMappingOverrideSample/appsettings.Development.json create mode 100644 SharpMappingOverrideSample/appsettings.json diff --git a/README.md b/README.md index 69338a0..2788bbe 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,36 @@ public class NewCustomerEventHandler : IEventGridHandler { } } ``` +## Custom mapping +To use a custom mapping, create your own implementation of ShartEventGridMapper. +The following mapper, will map based on a convention that the eventhandler must start with {eventsubject}_ + +```cs + public class SubjectConventionMapper : EventGridMapper + { + private readonly Dictionary> handlers = new Dictionary>(); + + public override void AddMapping(string eventType, Type type) + { + if (handlers.Any(h => h.Key == eventType.ToLower())) + handlers[eventType].Add(type); + else + handlers.Add(eventType.ToLower(), new List { type }); + } + + public override Type LookUpMapping(Event item) + { + var key = item.EventType.ToLower(); + if (handlers.ContainsKey(key) && handlers[key].Any(t => t.Name.StartsWith(item.Subject + "_"))) + return handlers[key].First(t => t.Name.StartsWith(item.Subject + "_")); + return null; + } + } +``` + +To use the new mapper, add it to the EventGridOptions + +```cs +opt.Mapper=new SubjectConventionMapper(); +``` + diff --git a/SharpEventGridServer.sln b/SharpEventGridServer.sln index 8be1d39..fc114ab 100644 --- a/SharpEventGridServer.sln +++ b/SharpEventGridServer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26923.0 +VisualStudioVersion = 15.0.27130.2010 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpEventGridServer", "SharpEventGridServer\SharpEventGridServer.csproj", "{AE0D64BC-F59D-42F4-8533-F7724F1410BB}" EndProject @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{46039ACF-7 README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpMappingOverrideSample", "SharpMappingOverrideSample\SharpMappingOverrideSample.csproj", "{553B96A6-9C1B-4182-8BA4-5590BCD59860}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {97BC76E8-A746-4F28-BC38-701648ED78EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {97BC76E8-A746-4F28-BC38-701648ED78EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {97BC76E8-A746-4F28-BC38-701648ED78EC}.Release|Any CPU.Build.0 = Release|Any CPU + {553B96A6-9C1B-4182-8BA4-5590BCD59860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {553B96A6-9C1B-4182-8BA4-5590BCD59860}.Debug|Any CPU.Build.0 = Debug|Any CPU + {553B96A6-9C1B-4182-8BA4-5590BCD59860}.Release|Any CPU.ActiveCfg = Release|Any CPU + {553B96A6-9C1B-4182-8BA4-5590BCD59860}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SharpEventGridServer/EventGridMapper.cs b/SharpEventGridServer/EventGridMapper.cs new file mode 100644 index 0000000..c5873f2 --- /dev/null +++ b/SharpEventGridServer/EventGridMapper.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SharpEventGrid; + +namespace SharpEventGridServer +{ + public class EventGridMapper + { + private readonly Dictionary handlers = new Dictionary(); + + public virtual void AddMapping(string eventType, Type type) + { + handlers.Add(eventType.ToLower(), type); + } + + public virtual Type LookUpMapping(Event item) + { + var resulttype = handlers.FirstOrDefault(i => i.Key == item.EventType.ToLower()); + return resulttype.Equals(default(KeyValuePair)) ? null : resulttype.Value; + } + } +} diff --git a/SharpEventGridServer/EventGridOptions.cs b/SharpEventGridServer/EventGridOptions.cs index 27f4039..3d9b693 100644 --- a/SharpEventGridServer/EventGridOptions.cs +++ b/SharpEventGridServer/EventGridOptions.cs @@ -1,11 +1,12 @@ using System; -using System.Collections.Generic; using SharpEventGrid; -namespace SharpEventGridServer { - public class EventGridOptions { - private Type _defaultMapping; - private Dictionary _handlers = new Dictionary(); +namespace SharpEventGridServer +{ + public class EventGridOptions + { + protected Type _defaultMapping; + internal IServiceProvider ServiceProvider { get; set; } public string EventsPath { get; set; } = "api/events"; @@ -14,22 +15,27 @@ public class EventGridOptions { public string ValidationKey { get; set; } public string ValidationValue { get; set; } public Action AutoValidateSubscriptionAttemptNotifier { get; set; } - - public void MapEvent(string eventType) where T : IEventGridHandler { - _handlers.Add(eventType.ToLower(), typeof(T)); + public EventGridMapper Mapper = new EventGridMapper(); + public virtual void MapEvent(string eventType) where T : IEventGridHandler + { + Mapper.AddMapping(eventType, typeof(T)); } - public void MapDefault() where T : IEventGridHandler { + public void MapDefault() where T : IEventGridHandler + { _defaultMapping = typeof(T); } - public void SetValidationKey(string key, string value) { + public void SetValidationKey(string key, string value) + { ValidationKey = key; ValidationValue = value; } - internal IEventGridHandler ResolveHandler(Event item) { - var key = item.EventType.ToLower(); - Type typeToCreate = _handlers.ContainsKey(key) ? _handlers[key] : _defaultMapping; + internal virtual IEventGridHandler ResolveHandler(Event item) + { + var typeToCreate = Mapper.LookUpMapping(item); + if (typeToCreate == null) + typeToCreate = _defaultMapping; var handler = ServiceProvider.GetService(typeToCreate) ?? Activator.CreateInstance(typeToCreate); return (IEventGridHandler)handler; } diff --git a/SharpEventGridServer/SharpEventGridServer.csproj b/SharpEventGridServer/SharpEventGridServer.csproj index adbff00..0e582b7 100644 --- a/SharpEventGridServer/SharpEventGridServer.csproj +++ b/SharpEventGridServer/SharpEventGridServer.csproj @@ -16,6 +16,7 @@ + diff --git a/SharpMappingOverrideSample/Controllers/SendEventsController.cs b/SharpMappingOverrideSample/Controllers/SendEventsController.cs new file mode 100644 index 0000000..7b0ae9e --- /dev/null +++ b/SharpMappingOverrideSample/Controllers/SendEventsController.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using SharpEventGrid; + +namespace SharpMappingOverrideSample { + public class SendEventsController : Controller { + private readonly HttpClient _client; + + public SendEventsController(HttpClient client) { + _client = client; + } + + [HttpGet("api/test/subscription")] + public async Task TestSubscription() { + var response = await SendEvent(EventTypes.SubscriptionValidationEvent, new ValidationEvent { ValidationCode = "foo" }); + return Ok(response); + } + + [HttpGet("api/test/event")] + public async Task TestEvent(string eventType, string message) { + var response = await SendEvent(eventType, message); + return Ok(response); + } + private async Task SendEvent(string eventType, object data) { + var url = $"{Request.Scheme}://{Request.Host.Value}/api/events?{Request.QueryString}"; + var item = new Event { + EventType = eventType, + Subject = "mySubject", + Data = data + }; + var json = JsonConvert.SerializeObject(new List { item }); + var response = await _client.PostAsync(url, new StringContent(json)); + var body = await response.Content.ReadAsStringAsync(); + if (String.IsNullOrEmpty(body)) { + body = "OK"; + } + return body; + } + } +} diff --git a/SharpMappingOverrideSample/EventHandlers/DefaultMappingHandler.cs b/SharpMappingOverrideSample/EventHandlers/DefaultMappingHandler.cs new file mode 100644 index 0000000..46347ff --- /dev/null +++ b/SharpMappingOverrideSample/EventHandlers/DefaultMappingHandler.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using SharpEventGrid; +using SharpEventGridServer; + +namespace SharpMappingOverrideSample { + public class DefaultMappingHandler : IEventGridHandler { + public async Task ProcessEvent(Event eventItem) { + Debug.WriteLine($"{nameof(DefaultMappingHandler)} {eventItem.EventType}"); + } + } +} diff --git a/SharpMappingOverrideSample/EventHandlers/mySubject_NewCustomerEventHandler.cs b/SharpMappingOverrideSample/EventHandlers/mySubject_NewCustomerEventHandler.cs new file mode 100644 index 0000000..4b6c2a7 --- /dev/null +++ b/SharpMappingOverrideSample/EventHandlers/mySubject_NewCustomerEventHandler.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using SharpEventGrid; +using SharpEventGridServer; + +namespace SharpMappingOverrideSample { + public class mySubject_NewCustomerEventHandler : IEventGridHandler { + + private IDatabase _database; + public mySubject_NewCustomerEventHandler(IDatabase database) { + _database = database; + } + + public async Task ProcessEvent(Event eventItem) { + var newCustomerEvent = eventItem.DeserializeEvent(); + await _database.SaveAsync(newCustomerEvent); + Debug.WriteLine($"{nameof(mySubject_NewCustomerEventHandler)} {eventItem.EventType}"); + } + } +} diff --git a/SharpMappingOverrideSample/EventHandlers/mySubject_SomeEventHandler.cs b/SharpMappingOverrideSample/EventHandlers/mySubject_SomeEventHandler.cs new file mode 100644 index 0000000..8cd293f --- /dev/null +++ b/SharpMappingOverrideSample/EventHandlers/mySubject_SomeEventHandler.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using SharpEventGrid; +using SharpEventGridServer; + +namespace SharpMappingOverrideSample { + public class mySubject_SomeEventHandler : IEventGridHandler { + public async Task ProcessEvent(Event eventItem) { + Debug.WriteLine($"{nameof(mySubject_SomeEventHandler)} {eventItem.EventType}"); + } + } +} diff --git a/SharpMappingOverrideSample/NewCustomerEvent.cs b/SharpMappingOverrideSample/NewCustomerEvent.cs new file mode 100644 index 0000000..87824e6 --- /dev/null +++ b/SharpMappingOverrideSample/NewCustomerEvent.cs @@ -0,0 +1,5 @@ +namespace SharpMappingOverrideSample { + public class NewCustomerEvent { + + } +} diff --git a/SharpMappingOverrideSample/Program.cs b/SharpMappingOverrideSample/Program.cs new file mode 100644 index 0000000..7d80798 --- /dev/null +++ b/SharpMappingOverrideSample/Program.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; + +namespace SharpMappingOverrideSample +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/SharpMappingOverrideSample/Properties/launchSettings.json b/SharpMappingOverrideSample/Properties/launchSettings.json new file mode 100644 index 0000000..0530f67 --- /dev/null +++ b/SharpMappingOverrideSample/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:29119/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "SharpEventGridServerSample": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:29120/" + } + } +} diff --git a/SharpMappingOverrideSample/Services/Database.cs b/SharpMappingOverrideSample/Services/Database.cs new file mode 100644 index 0000000..928f252 --- /dev/null +++ b/SharpMappingOverrideSample/Services/Database.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace SharpMappingOverrideSample { + public class Database : IDatabase { + public async Task SaveAsync(object item) { + //example + } + } +} \ No newline at end of file diff --git a/SharpMappingOverrideSample/Services/IDatabase.cs b/SharpMappingOverrideSample/Services/IDatabase.cs new file mode 100644 index 0000000..17212ba --- /dev/null +++ b/SharpMappingOverrideSample/Services/IDatabase.cs @@ -0,0 +1,7 @@ +using System.Threading.Tasks; + +namespace SharpMappingOverrideSample { + public interface IDatabase { + Task SaveAsync(object item); + } +} \ No newline at end of file diff --git a/SharpMappingOverrideSample/SharpMappingOverrideSample.csproj b/SharpMappingOverrideSample/SharpMappingOverrideSample.csproj new file mode 100644 index 0000000..6528dec --- /dev/null +++ b/SharpMappingOverrideSample/SharpMappingOverrideSample.csproj @@ -0,0 +1,23 @@ + + + + netcoreapp2.0 + + + + + + + + + + + + + + + + + + + diff --git a/SharpMappingOverrideSample/Startup.cs b/SharpMappingOverrideSample/Startup.cs new file mode 100644 index 0000000..f5db0f2 --- /dev/null +++ b/SharpMappingOverrideSample/Startup.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using System.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using SharpEventGridServer; + +namespace SharpMappingOverrideSample { + public class Startup { + public Startup(IConfiguration configuration) { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) { + services.AddSingleton(new HttpClient()); + services.AddSingleton(new mySubject_SomeEventHandler()); + services.AddSingleton(); + services.AddMvc(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { + if (env.IsDevelopment()) { + app.UseDeveloperExceptionPage(); + } + var opt = new EventGridOptions(); + opt.AutoValidateSubscription = true; + opt.AutoValidateSubscriptionAttemptNotifier = (url, success, message) => { + Debug.WriteLine($"Validation attempt: {url} -> Success: {success}: {message}"); + }; + opt.EventsPath = "api/events"; + opt.MapEvent("someEventType"); + opt.MapEvent("newCustomerEventType"); + opt.MapDefault(); + opt.SetValidationKey("key", "foo"); + app.UseEventGrid(opt); + opt.Mapper=new SubjectConventionMapper(); + app.UseMvc(); + } + } +} diff --git a/SharpMappingOverrideSample/SubjectConventionMapper.cs b/SharpMappingOverrideSample/SubjectConventionMapper.cs new file mode 100644 index 0000000..2820dd4 --- /dev/null +++ b/SharpMappingOverrideSample/SubjectConventionMapper.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SharpEventGrid; +using SharpEventGridServer; + +namespace SharpMappingOverrideSample +{ + public class SubjectConventionMapper : EventGridMapper + { + private readonly Dictionary> handlers = new Dictionary>(); + + public override void AddMapping(string eventType, Type type) + { + if (handlers.Any(h => h.Key == eventType.ToLower())) + handlers[eventType].Add(type); + else + handlers.Add(eventType.ToLower(), new List { type }); + } + + public override Type LookUpMapping(Event item) + { + var key = item.EventType.ToLower(); + if (handlers.ContainsKey(key) && handlers[key].Any(t => t.Name.StartsWith(item.Subject + "_"))) + return handlers[key].First(t => t.Name.StartsWith(item.Subject + "_")); + return null; + } + } +} diff --git a/SharpMappingOverrideSample/appsettings.Development.json b/SharpMappingOverrideSample/appsettings.Development.json new file mode 100644 index 0000000..fa8ce71 --- /dev/null +++ b/SharpMappingOverrideSample/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/SharpMappingOverrideSample/appsettings.json b/SharpMappingOverrideSample/appsettings.json new file mode 100644 index 0000000..26bb0ac --- /dev/null +++ b/SharpMappingOverrideSample/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +}