Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using cdmdotnet.Logging;
11 : using Cqrs.Events;
12 : using Cqrs.Messages;
13 : using System.Net;
14 : using Cqrs.Commands;
15 : using Cqrs.Configuration;
16 : using Cqrs.Infrastructure;
17 : using Cqrs.Bus;
18 :
19 : namespace Cqrs.Hosts
20 : {
21 : /// <summary>
22 : /// Configure and start command and event handlers in a host
23 : /// </summary>
24 : public abstract class CoreHost<TAuthenticationToken>
25 1 : {
26 : /// <summary>
27 : /// The <see cref="IConfigurationManager"/> that can be use before the <see cref="DependencyResolver.Current"/> is set.
28 : /// </summary>
29 : protected abstract IConfigurationManager ConfigurationManager { get; }
30 :
31 : /// <summary>
32 : /// Each <see cref="Type"/> will be traced back to it's assembly, and that assembly will be scanned for other handlers to auto register.
33 : /// </summary>
34 : protected Type[] HandlerTypes { get; set; }
35 :
36 : /// <summary>
37 : /// The <see cref="IEventReceiver"/> that will be configured to receive <see cref="IEvent{TAuthenticationToken}">events</see>.
38 : /// </summary>
39 : protected IEventReceiver<TAuthenticationToken> EventBus { get; private set; }
40 :
41 : /// <summary>
42 : /// The <see cref="ICommandReceiver"/> that will be configured to receive <see cref="ICommand{TAuthenticationToken}">commands</see>.
43 : /// </summary>
44 : protected ICommandReceiver<TAuthenticationToken> CommandBus { get; private set; }
45 :
46 : /// <summary>
47 : /// The hosts telemetry name if telemetry is configured
48 : /// </summary>
49 : protected string TelemetryName { get; set; }
50 :
51 : /// <summary>
52 : /// The <see cref="ICorrelationIdHelper"/> that will be used when starting and stopping the host.
53 : /// </summary>
54 : protected ICorrelationIdHelper CorrelationIdHelper { get; private set; }
55 :
56 : /// <summary>
57 : /// The <see cref="ILogger"/> that will be used when starting and stopping the host.
58 : /// </summary>
59 : protected ILogger Logger { get; private set; }
60 :
61 : // ReSharper disable DoNotCallOverridableMethodsInConstructor
62 : /// <summary>
63 : /// Instantiate a new instance of a <see cref="CoreHost{TAuthenticationToken}"/>
64 : /// </summary>
65 1 : protected CoreHost()
66 : {
67 : HandlerTypes = new Type[]{};
68 : bool pauseAndWait;
69 : long waitCounter = 0;
70 : long maximumCount;
71 : if (!long.TryParse(ConfigurationManager.GetSetting("Cqrs.Hosts.PauseAndWaitMaximumCount"), out maximumCount))
72 : maximumCount = 300;
73 : SpinWait.SpinUntil
74 : (
75 : () =>
76 : {
77 : if (waitCounter++ > maximumCount)
78 : return true;
79 : Console.WriteLine("Pause and wait counter is at {0:N0}", waitCounter);
80 : return !bool.TryParse(ConfigurationManager.GetSetting("Cqrs.Hosts.PauseAndWait"), out pauseAndWait) || !pauseAndWait;
81 : },
82 : (short)1000
83 : );
84 :
85 : TelemetryName = ConfigurationManager.GetSetting("Cqrs.Hosts.AppName") ?? AppDomain.CurrentDomain.FriendlyName;
86 : ConfigureTelemetry();
87 : }
88 : // ReSharper restore DoNotCallOverridableMethodsInConstructor
89 :
90 : /// <summary>
91 : /// When overridden, allows you to configure Telemetry
92 : /// </summary>
93 1 : protected virtual void ConfigureTelemetry()
94 : {
95 : }
96 :
97 : /// <summary>
98 : /// Calls <see cref="Prepare"/>, <paramref name="handlerRegistation"/> and then <see cref="Start"/>
99 : /// </summary>
100 1 : public virtual void Run(Action handlerRegistation = null)
101 : {
102 : Prepare();
103 : if (handlerRegistation != null)
104 : handlerRegistation();
105 : Start();
106 : }
107 :
108 : /// <summary>
109 : /// Sets the <see cref="ServicePointManager.SecurityProtocol"/> to <see cref="SecurityProtocolType.Tls"/>.
110 : /// You might want to override this to .net 4.5 and above to SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls
111 : /// </summary>
112 1 : protected virtual void PrepareSecurityProtocol()
113 : {
114 : ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
115 : }
116 :
117 : /// <summary>
118 : /// Prepare the host before registering handlers and starting the host.
119 : /// </summary>
120 1 : protected virtual void Prepare()
121 : {
122 : PrepareSecurityProtocol();
123 : // https://alexandrebrisebois.wordpress.com/2013/03/24/why-are-webrequests-throttled-i-want-more-throughput/
124 : ServicePointManager.UseNagleAlgorithm = false;
125 : ServicePointManager.DefaultConnectionLimit = 1000;
126 :
127 : new StartUp(ConfigureDefaultDependencyResolver).Initialise();
128 : EventBus = DependencyResolver.Current.Resolve<IEventReceiver<TAuthenticationToken>>();
129 : CommandBus = DependencyResolver.Current.Resolve<ICommandReceiver<TAuthenticationToken>>();
130 : Guid correlationId = Guid.NewGuid();
131 : CorrelationIdHelper = DependencyResolver.Current.Resolve<ICorrelationIdHelper>();
132 : CorrelationIdHelper.SetCorrelationId(correlationId);
133 :
134 : Logger = DependencyResolver.Current.Resolve<ILogger>();
135 : }
136 :
137 : /// <summary>
138 : /// Configure the <see cref="DependencyResolver"/>.
139 : /// </summary>
140 1 : protected abstract void ConfigureDefaultDependencyResolver();
141 :
142 : /// <summary>
143 : /// Start the host post preparing and registering handlers.
144 : /// </summary>
145 1 : protected virtual void Start()
146 : {
147 : StartBusRegistrar();
148 :
149 : var configurationManager = DependencyResolver.Current.Resolve<IConfigurationManager>();
150 : bool setting;
151 : if (!configurationManager.TryGetSetting("Cqrs.Hosts.EnableEventReceiving", out setting))
152 : setting = true;
153 : if (setting)
154 : EventBus.Start();
155 : if (!configurationManager.TryGetSetting("Cqrs.Hosts.EnableCommandReceiving", out setting))
156 : setting = true;
157 : if (setting)
158 : CommandBus.Start();
159 : }
160 :
161 : /// <summary>
162 : /// Register an event handler that will listen and respond to events.
163 : /// </summary>
164 : /// <param name="eventHandler">The event handler to call</param>
165 : /// <param name="holdMessageLock">If false, this will spin off another thread. This is a bad performance impact. Strongly suggest you use lock renewing instead... which is configuration based... so even better.</param>
166 1 : protected virtual void ManuallyRegisterEventHandler<TMessage>(Action<TMessage> eventHandler, bool holdMessageLock = true)
167 : where TMessage : IMessage
168 : {
169 : var eventHandlerRegistrar = DependencyResolver.Current.Resolve<IEventHandlerRegistrar>();
170 : eventHandlerRegistrar.RegisterHandler(eventHandler, holdMessageLock);
171 : }
172 :
173 : /// <summary>
174 : /// Register an command handler that will listen and respond to commands.
175 : /// </summary>
176 : /// <param name="commandHandler">The command handler to call</param>
177 : /// <param name="holdMessageLock">If false, this will spin off another thread. This is a bad performance impact. Strongly suggest you use lock renewing instead... which is configuration based... so even better.</param>
178 1 : protected virtual void ManuallyRegisterCommandHandler<TMessage>(Action<TMessage> commandHandler, bool holdMessageLock = true)
179 : where TMessage : IMessage
180 : {
181 : var eventHandlerRegistrar = DependencyResolver.Current.Resolve<IEventHandlerRegistrar>();
182 : eventHandlerRegistrar.RegisterHandler(commandHandler, holdMessageLock);
183 : }
184 :
185 : /// <summary>
186 : /// Start the <see cref="BusRegistrar"/> by calling <see cref="BusRegistrar.Register(System.Type[])"/> passing <see cref="HandlerTypes"/>
187 : /// </summary>
188 1 : protected virtual void StartBusRegistrar()
189 : {
190 : var registrar = new BusRegistrar(DependencyResolver.Current);
191 : registrar.Register(HandlerTypes);
192 : }
193 : }
194 : }
|