MAX-911 RDB Relaties samenvoegen vanuit LEF en update ontvangen in LEF
MAX-1081 POC Dictionary tasks in Web voor request Setup voor Transient request response met TODO's
This commit is contained in:
parent
9bb192c067
commit
6bc6cfe216
@ -105,9 +105,9 @@ namespace Tapeti.Flow.Default
|
|||||||
|
|
||||||
// TODO disallow if replyto is not specified?
|
// TODO disallow if replyto is not specified?
|
||||||
if (reply.ReplyTo != null)
|
if (reply.ReplyTo != null)
|
||||||
await publisher.PublishDirect(message, reply.ReplyTo, properties, true);
|
await publisher.PublishDirect(message, reply.ReplyTo, properties, reply.Mandatory);
|
||||||
else
|
else
|
||||||
await publisher.Publish(message, properties, true);
|
await publisher.Publish(message, properties, reply.Mandatory);
|
||||||
|
|
||||||
await context.Delete();
|
await context.Delete();
|
||||||
}
|
}
|
||||||
@ -129,8 +129,8 @@ namespace Tapeti.Flow.Default
|
|||||||
throw new ArgumentException("responseHandler must be a registered message handler", nameof(responseHandler));
|
throw new ArgumentException("responseHandler must be a registered message handler", nameof(responseHandler));
|
||||||
|
|
||||||
var requestAttribute = request.GetType().GetCustomAttribute<RequestAttribute>();
|
var requestAttribute = request.GetType().GetCustomAttribute<RequestAttribute>();
|
||||||
if (requestAttribute?.Response != null && requestAttribute.Response != binding.MessageClass)
|
if (requestAttribute?.Response != null && !binding.Accept(requestAttribute.Response))
|
||||||
throw new ArgumentException($"responseHandler must accept message of type {binding.MessageClass}", nameof(responseHandler));
|
throw new ArgumentException($"responseHandler must accept message of type {requestAttribute.Response}", nameof(responseHandler));
|
||||||
|
|
||||||
var continuationAttribute = binding.Method.GetCustomAttribute<ContinuationAttribute>();
|
var continuationAttribute = binding.Method.GetCustomAttribute<ContinuationAttribute>();
|
||||||
if (continuationAttribute == null)
|
if (continuationAttribute == null)
|
||||||
@ -157,7 +157,8 @@ namespace Tapeti.Flow.Default
|
|||||||
{
|
{
|
||||||
CorrelationId = context.Properties.CorrelationId,
|
CorrelationId = context.Properties.CorrelationId,
|
||||||
ReplyTo = context.Properties.ReplyTo,
|
ReplyTo = context.Properties.ReplyTo,
|
||||||
ResponseTypeName = requestAttribute.Response.FullName
|
ResponseTypeName = requestAttribute.Response.FullName,
|
||||||
|
Mandatory = context.Properties.Persistent
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@ namespace Tapeti.Flow.Default
|
|||||||
public string CorrelationId { get; set; }
|
public string CorrelationId { get; set; }
|
||||||
public string ResponseTypeName { get; set; }
|
public string ResponseTypeName { get; set; }
|
||||||
|
|
||||||
|
public bool Mandatory { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public ReplyMetadata Clone()
|
public ReplyMetadata Clone()
|
||||||
{
|
{
|
||||||
@ -64,7 +66,8 @@ namespace Tapeti.Flow.Default
|
|||||||
{
|
{
|
||||||
ReplyTo = ReplyTo,
|
ReplyTo = ReplyTo,
|
||||||
CorrelationId = CorrelationId,
|
CorrelationId = CorrelationId,
|
||||||
ResponseTypeName = ResponseTypeName
|
ResponseTypeName = ResponseTypeName,
|
||||||
|
Mandatory = Mandatory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
Tapeti.Tests/TransientFilterMiddleware.cs
Normal file
14
Tapeti.Tests/TransientFilterMiddleware.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Tapeti.Config;
|
||||||
|
|
||||||
|
namespace Tapeti.Tests
|
||||||
|
{
|
||||||
|
public class TransientFilterMiddleware : IMessageFilterMiddleware
|
||||||
|
{
|
||||||
|
public Task Handle(IMessageContext context, Func<Task> next)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Tapeti.Transient/ConfigExtentions.cs
Normal file
13
Tapeti.Transient/ConfigExtentions.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public static class ConfigExtensions
|
||||||
|
{
|
||||||
|
public static TapetiConfig WithTransient(this TapetiConfig config, TimeSpan defaultTimeout, string dynamicQueuePrefix = "transient")
|
||||||
|
{
|
||||||
|
config.Use(new TransientMiddleware(defaultTimeout, dynamicQueuePrefix));
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Tapeti.Transient/ITransientPublisher.cs
Normal file
9
Tapeti.Transient/ITransientPublisher.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public interface ITransientPublisher
|
||||||
|
{
|
||||||
|
Task<TResponse> RequestResponse<TRequest, TResponse>(TRequest request);
|
||||||
|
}
|
||||||
|
}
|
11
Tapeti.Transient/Tapeti.Transient.csproj
Normal file
11
Tapeti.Transient/Tapeti.Transient.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Tapeti\Tapeti.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
52
Tapeti.Transient/TransientGenericBinding.cs
Normal file
52
Tapeti.Transient/TransientGenericBinding.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Tapeti.Config;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public class TransientGenericBinding : ICustomBinding
|
||||||
|
{
|
||||||
|
private readonly TransientRouter router;
|
||||||
|
|
||||||
|
public TransientGenericBinding(TransientRouter router, string dynamicQueuePrefix)
|
||||||
|
{
|
||||||
|
this.router = router;
|
||||||
|
DynamicQueuePrefix = dynamicQueuePrefix;
|
||||||
|
Method = typeof(TransientRouter).GetMethod("GenericHandleResponse");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type Controller => typeof(TransientRouter);
|
||||||
|
|
||||||
|
public MethodInfo Method { get; }
|
||||||
|
|
||||||
|
public QueueBindingMode QueueBindingMode => QueueBindingMode.DirectToQueue;
|
||||||
|
|
||||||
|
public string StaticQueueName => null;
|
||||||
|
|
||||||
|
public string DynamicQueuePrefix { get; }
|
||||||
|
|
||||||
|
public Type MessageClass => null;
|
||||||
|
|
||||||
|
public bool Accept(Type messageClass)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Accept(IMessageContext context, object message)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Invoke(IMessageContext context, object message)
|
||||||
|
{
|
||||||
|
router.GenericHandleResponse(message, context);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetQueueName(string queueName)
|
||||||
|
{
|
||||||
|
router.TransientResponseQueueName = queueName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
Tapeti.Transient/TransientMiddleware.cs
Normal file
34
Tapeti.Transient/TransientMiddleware.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Tapeti.Config;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public class TransientMiddleware : ITapetiExtension, ITapetiExtentionBinding
|
||||||
|
{
|
||||||
|
private string dynamicQueuePrefix;
|
||||||
|
private TimeSpan defaultTimeout;
|
||||||
|
|
||||||
|
public TransientMiddleware(TimeSpan defaultTimeout, string dynamicQueuePrefix)
|
||||||
|
{
|
||||||
|
this.dynamicQueuePrefix = dynamicQueuePrefix;
|
||||||
|
this.defaultTimeout = defaultTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterDefaults(IDependencyContainer container)
|
||||||
|
{
|
||||||
|
container.RegisterDefaultSingleton(() => new TransientRouter(container.Resolve<IInternalPublisher>(), defaultTimeout));
|
||||||
|
container.RegisterDefault<ITransientPublisher, TransientPublisher>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<object> GetMiddleware(IDependencyResolver dependencyResolver)
|
||||||
|
{
|
||||||
|
return new object[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ICustomBinding> GetBindings(IDependencyResolver dependencyResolver)
|
||||||
|
{
|
||||||
|
yield return new TransientGenericBinding(dependencyResolver.Resolve<TransientRouter>(), dynamicQueuePrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Tapeti.Transient/TransientPublisher.cs
Normal file
22
Tapeti.Transient/TransientPublisher.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public class TransientPublisher : ITransientPublisher
|
||||||
|
{
|
||||||
|
private readonly TransientRouter router;
|
||||||
|
|
||||||
|
public TransientPublisher(TransientRouter router)
|
||||||
|
{
|
||||||
|
this.router = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TResponse> RequestResponse<TRequest, TResponse>(TRequest request)
|
||||||
|
{
|
||||||
|
return (TResponse)(await router.RequestResponse(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
Tapeti.Transient/TransientRouter.cs
Normal file
74
Tapeti.Transient/TransientRouter.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using RabbitMQ.Client.Framing;
|
||||||
|
using Tapeti.Config;
|
||||||
|
|
||||||
|
namespace Tapeti.Transient
|
||||||
|
{
|
||||||
|
public class TransientRouter
|
||||||
|
{
|
||||||
|
private readonly TimeSpan defaultTimeout;
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<Guid, TaskCompletionSource<object>> map = new ConcurrentDictionary<Guid, TaskCompletionSource<object>>();
|
||||||
|
|
||||||
|
private readonly IInternalPublisher internalPublisher;
|
||||||
|
|
||||||
|
public string TransientResponseQueueName { get; set; }
|
||||||
|
|
||||||
|
public TransientRouter(IInternalPublisher internalPublisher, TimeSpan defaultTimeout)
|
||||||
|
{
|
||||||
|
this.internalPublisher = internalPublisher;
|
||||||
|
this.defaultTimeout = defaultTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GenericHandleResponse(object response, IMessageContext context)
|
||||||
|
{
|
||||||
|
if (context.Properties.CorrelationId == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Guid.TryParse(context.Properties.CorrelationId, out var continuationID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (map.TryRemove(continuationID, out var tcs))
|
||||||
|
tcs.SetResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<object> RequestResponse(object request)
|
||||||
|
{
|
||||||
|
var correlation = Guid.NewGuid();
|
||||||
|
var tcs = map.GetOrAdd(correlation, c => new TaskCompletionSource<object>());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var properties = new BasicProperties
|
||||||
|
{
|
||||||
|
CorrelationId = correlation.ToString(),
|
||||||
|
ReplyTo = TransientResponseQueueName,
|
||||||
|
Persistent = false
|
||||||
|
};
|
||||||
|
|
||||||
|
await internalPublisher.Publish(request, properties, false);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Simple cleanup of the task and map dictionary.
|
||||||
|
if (map.TryRemove(correlation, out tcs))
|
||||||
|
tcs.TrySetResult(null);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (new Timer(TimeoutResponse, tcs, defaultTimeout, TimeSpan.MaxValue))
|
||||||
|
{
|
||||||
|
return await tcs.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimeoutResponse(object tcs)
|
||||||
|
{
|
||||||
|
((TaskCompletionSource<object>)tcs).SetException(new TimeoutException("Transient RequestResponse timed out at " + defaultTimeout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.Tests", "Tapeti.Tests\Tapeti.Tests.csproj", "{334F3715-63CF-4D13-B09A-38E2A616D4F5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.Tests", "Tapeti.Tests\Tapeti.Tests.csproj", "{334F3715-63CF-4D13-B09A-38E2A616D4F5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tapeti.Serilog", "Tapeti.Serilog\Tapeti.Serilog.csproj", "{43AA5DF3-49D5-4795-A290-D6511502B564}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.Serilog", "Tapeti.Serilog\Tapeti.Serilog.csproj", "{43AA5DF3-49D5-4795-A290-D6511502B564}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tapeti.Transient", "Tapeti.Transient\Tapeti.Transient.csproj", "{A6355E63-19AB-47EA-91FA-49B5E9B41F88}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -63,6 +65,10 @@ Global
|
|||||||
{43AA5DF3-49D5-4795-A290-D6511502B564}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{43AA5DF3-49D5-4795-A290-D6511502B564}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{43AA5DF3-49D5-4795-A290-D6511502B564}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{43AA5DF3-49D5-4795-A290-D6511502B564}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{43AA5DF3-49D5-4795-A290-D6511502B564}.Release|Any CPU.Build.0 = Release|Any CPU
|
{43AA5DF3-49D5-4795-A290-D6511502B564}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A6355E63-19AB-47EA-91FA-49B5E9B41F88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A6355E63-19AB-47EA-91FA-49B5E9B41F88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A6355E63-19AB-47EA-91FA-49B5E9B41F88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A6355E63-19AB-47EA-91FA-49B5E9B41F88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -46,6 +46,7 @@ namespace Tapeti.Config
|
|||||||
IReadOnlyList<IMessageFilterMiddleware> MessageFilterMiddleware { get; }
|
IReadOnlyList<IMessageFilterMiddleware> MessageFilterMiddleware { get; }
|
||||||
IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
||||||
|
|
||||||
|
bool Accept(Type messageClass);
|
||||||
bool Accept(IMessageContext context, object message);
|
bool Accept(IMessageContext context, object message);
|
||||||
Task Invoke(IMessageContext context, object message);
|
Task Invoke(IMessageContext context, object message);
|
||||||
}
|
}
|
||||||
|
31
Tapeti/Config/ICustomBinding.cs
Normal file
31
Tapeti/Config/ICustomBinding.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Tapeti.Config
|
||||||
|
{
|
||||||
|
public interface ICustomBinding
|
||||||
|
{
|
||||||
|
Type Controller { get; }
|
||||||
|
|
||||||
|
MethodInfo Method { get; }
|
||||||
|
|
||||||
|
QueueBindingMode QueueBindingMode { get; }
|
||||||
|
|
||||||
|
string StaticQueueName { get; }
|
||||||
|
|
||||||
|
string DynamicQueuePrefix { get; }
|
||||||
|
|
||||||
|
Type MessageClass { get; } // Needed to get routing key information when QueueBindingMode = RoutingKey
|
||||||
|
|
||||||
|
bool Accept(Type messageClass);
|
||||||
|
|
||||||
|
bool Accept(IMessageContext context, object message);
|
||||||
|
|
||||||
|
Task Invoke(IMessageContext context, object message);
|
||||||
|
|
||||||
|
void SetQueueName(string queueName);
|
||||||
|
}
|
||||||
|
}
|
10
Tapeti/Config/ITapetiExtentionBinding.cs
Normal file
10
Tapeti/Config/ITapetiExtentionBinding.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Tapeti.Config
|
||||||
|
{
|
||||||
|
public interface ITapetiExtentionBinding
|
||||||
|
{
|
||||||
|
IEnumerable<ICustomBinding> GetBindings(IDependencyResolver dependencyResolver);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -109,6 +109,9 @@ namespace Tapeti.Connection
|
|||||||
{
|
{
|
||||||
if (binding.QueueBindingMode == QueueBindingMode.RoutingKey)
|
if (binding.QueueBindingMode == QueueBindingMode.RoutingKey)
|
||||||
{
|
{
|
||||||
|
if (binding.MessageClass == null)
|
||||||
|
throw new NullReferenceException("Binding with QueueBindingMode = RoutingKey must have a MessageClass");
|
||||||
|
|
||||||
var routingKey = routingKeyStrategy.GetRoutingKey(binding.MessageClass);
|
var routingKey = routingKeyStrategy.GetRoutingKey(binding.MessageClass);
|
||||||
var exchange = exchangeStrategy.GetExchange(binding.MessageClass);
|
var exchange = exchangeStrategy.GetExchange(binding.MessageClass);
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ namespace Tapeti
|
|||||||
|
|
||||||
public class TapetiConfig
|
public class TapetiConfig
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, List<Binding>> staticRegistrations = new Dictionary<string, List<Binding>>();
|
private readonly Dictionary<string, List<IBinding>> staticRegistrations = new Dictionary<string, List<IBinding>>();
|
||||||
private readonly Dictionary<string, Dictionary<Type, List<Binding>>> dynamicRegistrations = new Dictionary<string, Dictionary<Type, List<Binding>>>();
|
private readonly Dictionary<string, Dictionary<Type, List<IBinding>>> dynamicRegistrations = new Dictionary<string, Dictionary<Type, List<IBinding>>>();
|
||||||
|
|
||||||
private readonly List<IBindingMiddleware> bindingMiddleware = new List<IBindingMiddleware>();
|
private readonly List<IBindingMiddleware> bindingMiddleware = new List<IBindingMiddleware>();
|
||||||
private readonly List<IMessageMiddleware> messageMiddleware = new List<IMessageMiddleware>();
|
private readonly List<IMessageMiddleware> messageMiddleware = new List<IMessageMiddleware>();
|
||||||
@ -79,12 +79,12 @@ namespace Tapeti
|
|||||||
//
|
//
|
||||||
foreach (var prefixGroup in dynamicRegistrations)
|
foreach (var prefixGroup in dynamicRegistrations)
|
||||||
{
|
{
|
||||||
var dynamicBindings = new List<List<Binding>>();
|
var dynamicBindings = new List<List<IBinding>>();
|
||||||
|
|
||||||
foreach (var bindings in prefixGroup.Value.Values)
|
foreach (var bindings in prefixGroup.Value.Values)
|
||||||
{
|
{
|
||||||
while (dynamicBindings.Count < bindings.Count)
|
while (dynamicBindings.Count < bindings.Count)
|
||||||
dynamicBindings.Add(new List<Binding>());
|
dynamicBindings.Add(new List<IBinding>());
|
||||||
|
|
||||||
for (var bindingIndex = 0; bindingIndex < bindings.Count; bindingIndex++)
|
for (var bindingIndex = 0; bindingIndex < bindings.Count; bindingIndex++)
|
||||||
dynamicBindings[bindingIndex].Add(bindings[bindingIndex]);
|
dynamicBindings[bindingIndex].Add(bindings[bindingIndex]);
|
||||||
@ -144,6 +144,8 @@ namespace Tapeti
|
|||||||
|
|
||||||
var middlewareBundle = extension.GetMiddleware(dependencyResolver);
|
var middlewareBundle = extension.GetMiddleware(dependencyResolver);
|
||||||
|
|
||||||
|
(extension as ITapetiExtentionBinding)?.GetBindings(dependencyResolver);
|
||||||
|
|
||||||
// ReSharper disable once InvertIf
|
// ReSharper disable once InvertIf
|
||||||
if (middlewareBundle != null)
|
if (middlewareBundle != null)
|
||||||
{
|
{
|
||||||
@ -212,6 +214,7 @@ namespace Tapeti
|
|||||||
{
|
{
|
||||||
var controllerQueueInfo = GetQueueInfo(controller);
|
var controllerQueueInfo = GetQueueInfo(controller);
|
||||||
|
|
||||||
|
if (!controller.IsInterface)
|
||||||
(dependencyResolver as IDependencyContainer)?.RegisterController(controller);
|
(dependencyResolver as IDependencyContainer)?.RegisterController(controller);
|
||||||
|
|
||||||
foreach (var method in controller.GetMembers(BindingFlags.Public | BindingFlags.Instance)
|
foreach (var method in controller.GetMembers(BindingFlags.Public | BindingFlags.Instance)
|
||||||
@ -359,7 +362,7 @@ namespace Tapeti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void AddStaticRegistration(IBindingContext context, Binding binding)
|
protected void AddStaticRegistration(IBindingContext context, IBindingQueueInfo binding)
|
||||||
{
|
{
|
||||||
if (staticRegistrations.ContainsKey(binding.QueueInfo.Name))
|
if (staticRegistrations.ContainsKey(binding.QueueInfo.Name))
|
||||||
{
|
{
|
||||||
@ -372,23 +375,23 @@ namespace Tapeti
|
|||||||
existing.Add(binding);
|
existing.Add(binding);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
staticRegistrations.Add(binding.QueueInfo.Name, new List<Binding> { binding });
|
staticRegistrations.Add(binding.QueueInfo.Name, new List<IBinding> { binding });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void AddDynamicRegistration(IBindingContext context, Binding binding)
|
protected void AddDynamicRegistration(IBindingContext context, IBindingQueueInfo binding)
|
||||||
{
|
{
|
||||||
var prefix = binding.QueueInfo.Name ?? "";
|
var prefix = binding.QueueInfo.Name ?? "";
|
||||||
|
|
||||||
if (!dynamicRegistrations.TryGetValue(prefix, out Dictionary<Type, List<Binding>> prefixRegistrations))
|
if (!dynamicRegistrations.TryGetValue(prefix, out Dictionary<Type, List<IBinding>> prefixRegistrations))
|
||||||
{
|
{
|
||||||
prefixRegistrations = new Dictionary<Type, List<Binding>>();
|
prefixRegistrations = new Dictionary<Type, List<IBinding>>();
|
||||||
dynamicRegistrations.Add(prefix, prefixRegistrations);
|
dynamicRegistrations.Add(prefix, prefixRegistrations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prefixRegistrations.TryGetValue(context.MessageClass, out List<Binding> bindings))
|
if (!prefixRegistrations.TryGetValue(context.MessageClass, out List<IBinding> bindings))
|
||||||
{
|
{
|
||||||
bindings = new List<Binding>();
|
bindings = new List<IBinding>();
|
||||||
prefixRegistrations.Add(context.MessageClass, bindings);
|
prefixRegistrations.Add(context.MessageClass, bindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,8 +494,12 @@ namespace Tapeti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected interface IBindingQueueInfo : IBuildBinding
|
||||||
|
{
|
||||||
|
QueueInfo QueueInfo { get; }
|
||||||
|
}
|
||||||
|
|
||||||
protected class Binding : IBuildBinding
|
protected class Binding : IBindingQueueInfo
|
||||||
{
|
{
|
||||||
public Type Controller { get; set; }
|
public Type Controller { get; set; }
|
||||||
public MethodInfo Method { get; set; }
|
public MethodInfo Method { get; set; }
|
||||||
@ -523,6 +530,11 @@ namespace Tapeti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool Accept(Type messageClass)
|
||||||
|
{
|
||||||
|
return MessageClass.IsAssignableFrom(messageClass);
|
||||||
|
}
|
||||||
|
|
||||||
public bool Accept(IMessageContext context, object message)
|
public bool Accept(IMessageContext context, object message)
|
||||||
{
|
{
|
||||||
return message.GetType() == MessageClass;
|
return message.GetType() == MessageClass;
|
||||||
@ -536,6 +548,69 @@ namespace Tapeti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected class CustomBinding : IBindingQueueInfo
|
||||||
|
{
|
||||||
|
private readonly ICustomBinding inner;
|
||||||
|
|
||||||
|
public CustomBinding(ICustomBinding inner)
|
||||||
|
{
|
||||||
|
this.inner = inner;
|
||||||
|
|
||||||
|
// Copy all variables to make them guaranteed readonly.
|
||||||
|
Controller = inner.Controller;
|
||||||
|
Method = inner.Method;
|
||||||
|
QueueBindingMode = inner.QueueBindingMode;
|
||||||
|
MessageClass = inner.MessageClass;
|
||||||
|
|
||||||
|
QueueInfo = inner.StaticQueueName != null
|
||||||
|
? new QueueInfo()
|
||||||
|
{
|
||||||
|
Dynamic = false,
|
||||||
|
Name = inner.StaticQueueName
|
||||||
|
}
|
||||||
|
: new QueueInfo()
|
||||||
|
{
|
||||||
|
Dynamic = true,
|
||||||
|
Name = inner.DynamicQueuePrefix
|
||||||
|
};
|
||||||
|
|
||||||
|
// Custom bindings cannot have other middleware messing with the binding.
|
||||||
|
MessageFilterMiddleware = new IMessageFilterMiddleware[0];
|
||||||
|
MessageMiddleware = new IMessageMiddleware[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type Controller { get; }
|
||||||
|
public MethodInfo Method { get; }
|
||||||
|
public string QueueName { get; private set; }
|
||||||
|
public QueueBindingMode QueueBindingMode { get; set; }
|
||||||
|
public IReadOnlyList<IMessageFilterMiddleware> MessageFilterMiddleware { get; }
|
||||||
|
public IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
||||||
|
|
||||||
|
public bool Accept(Type messageClass)
|
||||||
|
{
|
||||||
|
return inner.Accept(messageClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Accept(IMessageContext context, object message)
|
||||||
|
{
|
||||||
|
return inner.Accept(context, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Invoke(IMessageContext context, object message)
|
||||||
|
{
|
||||||
|
return inner.Invoke(context, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetQueueName(string queueName)
|
||||||
|
{
|
||||||
|
QueueName = queueName;
|
||||||
|
inner.SetQueueName(queueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type MessageClass { get; }
|
||||||
|
public QueueInfo QueueInfo { get; }
|
||||||
|
}
|
||||||
|
|
||||||
internal interface IBindingParameterAccess
|
internal interface IBindingParameterAccess
|
||||||
{
|
{
|
||||||
ValueFactory GetBinding();
|
ValueFactory GetBinding();
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using SimpleInjector;
|
using SimpleInjector;
|
||||||
using Tapeti;
|
using Tapeti;
|
||||||
using Tapeti.DataAnnotations;
|
using Tapeti.DataAnnotations;
|
||||||
using Tapeti.Flow;
|
using Tapeti.Flow;
|
||||||
using Tapeti.SimpleInjector;
|
using Tapeti.SimpleInjector;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Tapeti.Annotations;
|
||||||
|
|
||||||
namespace Test
|
namespace Test
|
||||||
{
|
{
|
||||||
|
public interface IDummy
|
||||||
|
{
|
||||||
|
[DynamicQueue("test1")]
|
||||||
|
void HandleMessage(PoloConfirmationResponseMessage msg);
|
||||||
|
}
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
private static void Main()
|
private static void Main()
|
||||||
@ -25,6 +33,7 @@ namespace Test
|
|||||||
.WithFlow()
|
.WithFlow()
|
||||||
.WithDataAnnotations()
|
.WithDataAnnotations()
|
||||||
.RegisterAllControllers()
|
.RegisterAllControllers()
|
||||||
|
.RegisterController(typeof(IDummy))
|
||||||
//.DisablePublisherConfirms() -> you probably never want to do this if you're using Flow or want requeues when a publish fails
|
//.DisablePublisherConfirms() -> you probably never want to do this if you're using Flow or want requeues when a publish fails
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user