I am working with code that currently does not use any dependency injection, and makes multiple service calls through a WCF client.
public class MyClass
{
public void Method()
{
try
{
ServiceClient client = new ServiceClient();
client.Operation1();
}
catch(Exception ex)
{
// Handle Exception
}
finally
{
client = null;
}
try
{
ServiceClient client = new ServiceClient();
client.Operation2();
}
catch(Exception ex)
{
// Handle Exception
}
finally
{
client = null;
}
}
}
My goal is to make this code unit-testable through the use of dependency injection. My first thought was to simply pass an instance of the service client to the class constructor. Then in my unit tests, I can create a mock client for testing purposes that does not make actual requests to the web service.
public class MyClass
{
IServiceClient client;
public MyClass(IServiceClient client)
{
this.client = client;
}
public void Method()
{
try
{
client.Operation1();
}
catch(Exception ex)
{
// Handle Exception
}
try
{
client.Operation2();
}
catch(Exception ex)
{
// Handle Exception
}
}
}
However, I realized that this changes the code in a way that affects its original behavior, based on the information from this question: Reuse a client class in WCF after it is faulted
In the original code, if the call to Operation1 fails and the client is put in a faulted state, a new instance of ServiceClient is created, and Operation2 will still be called.
In the updated code, if the call to Operation1 fails, the same client is reused to call Operation2, but this call will fail if the client is in a faulted state.
Is it possible to create a new instance of the client while keeping the dependency injection pattern? I realize that reflection can be used to instantiate a class from a string, but I feel like reflection isn't the right way to go about this.
You need to inject factory rather than instance itself:
public class ServiceClientFactory : IServiceClientFactory
{
public IServiceClient CreateInstance()
{
return new ServiceClient();
}
}
Then in MyClass you simply use factory to get instance each time it is required:
// Injection
public MyClass(IServiceClientFactory serviceClientFactory)
{
this.serviceClientFactory = serviceClientFactory;
}
// Usage
try
{
var client = serviceClientFactory.CreateInstance();
client.Operation1();
}
Alternatively, you can inject function returning such client using Func<IServiceClient> delegate so that you can avoid creating extra class and interface:
// Injection
public MyClass(Func<IServiceClient> createServiceClient)
{
this.createServiceClient = createServiceClient;
}
// Usage
try
{
var client = createServiceClient();
client.Operation1();
}
// Instance creation
var myClass = new MyClass(() => new ServiceClient());
In your case Func<IServiceClient> should be sufficient. Once instance creation logic gets more complicated it would be a time reconsider explicitly implemented factory.
What I did in the past was have a generic client (with 'interception' using Unity) which creates a new connection from the ChannelFactory, based on the service's business interface, for each call and close that connection after each call, deciding on whether to indicate the connection is faulted based on whether an exception or normal response was returned. (See below.)
My real code using this client just requests an instance implementing the business interface and it will get an instance of this generic wrapper. The instance returned does not need to be disposed of, or treated differently based on whether an exception was returned. To get a service client (using the wrapper below) my code does: var client = SoapClientInterceptorBehavior<T>.CreateInstance(new ChannelFactory<T>("*")), which is usually hidden in a registry or passed in as a constructor argument. So in your case I would end up with var myClass = new MyClass(SoapClientInterceptorBehavior<IServiceClient>.CreateInstance(new ChannelFactory<IServiceClient>("*"))); (you probably want to put the whole call to create the instance in some factory method of your own, just requiring IServiceClient as input type, to make it a bit more readable. ;-))
In my tests I can just injected a mocked implementation of the service and test whether the right business methods were called and their results properly handled.
/// <summary>
/// IInterceptionBehavior that will request a new channel from a ChannelFactory for each call,
/// and close (or abort) it after each call.
/// </summary>
/// <typeparam name="T">business interface of SOAP service to call</typeparam>
public class SoapClientInterceptorBehavior<T> : IInterceptionBehavior
{
// create a logger to include the interface name, so we can configure log level per interface
// Warn only logs exceptions (with arguments)
// Info can be enabled to get overview (and only arguments on exception),
// Debug always provides arguments and Trace also provides return value
private static readonly Logger Logger = LogManager.GetLogger(LoggerName());
private static string LoggerName()
{
string baseName = MethodBase.GetCurrentMethod().DeclaringType.FullName;
baseName = baseName.Remove(baseName.IndexOf('`'));
return baseName + "." + typeof(T).Name;
}
private readonly Func<T> _clientCreator;
/// <summary>
/// Creates new, using channelFactory.CreatChannel to create a channel to the SOAP service.
/// </summary>
/// <param name="channelFactory">channelfactory to obtain connections from</param>
public SoapClientInterceptorBehavior(ChannelFactory<T> channelFactory)
: this(channelFactory.CreateChannel)
{
}
/// <summary>
/// Creates new, using the supplied method to obtain a connection per call.
/// </summary>
/// <param name="clientCreationFunc">delegate to obtain client connection from</param>
public SoapClientInterceptorBehavior(Func<T> clientCreationFunc)
{
_clientCreator = clientCreationFunc;
}
/// <summary>
/// Intercepts calls to SOAP service, ensuring proper creation and closing of communication
/// channel.
/// </summary>
/// <param name="input">invocation being intercepted.</param>
/// <param name="getNext">next interceptor in chain (will not be called)</param>
/// <returns>result from SOAP call</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Logger.Info(() => "Invoking method: " + input.MethodBase.Name + "()");
// we will not invoke an actual target, or call next interception behaviors, instead we will
// create a new client, call it, close it if it is a channel, and return its
// return value.
T client = _clientCreator.Invoke();
Logger.Trace(() => "Created client");
var channel = client as IClientChannel;
IMethodReturn result;
int size = input.Arguments.Count;
var args = new object[size];
for(int i = 0; i < size; i++)
{
args[i] = input.Arguments[i];
}
Logger.Trace(() => "Arguments: " + string.Join(", ", args));
try
{
object val = input.MethodBase.Invoke(client, args);
if (Logger.IsTraceEnabled)
{
Logger.Trace(() => "Completed " + input.MethodBase.Name + "(" + string.Join(", ", args) + ") return-value: " + val);
}
else if (Logger.IsDebugEnabled)
{
Logger.Debug(() => "Completed " + input.MethodBase.Name + "(" + string.Join(", ", args) + ")");
}
else
{
Logger.Info(() => "Completed " + input.MethodBase.Name + "()");
}
result = input.CreateMethodReturn(val, args);
if (channel != null)
{
Logger.Trace("Closing channel");
channel.Close();
}
}
catch (TargetInvocationException tie)
{
// remove extra layer of exception added by reflective usage
result = HandleException(input, args, tie.InnerException, channel);
}
catch (Exception e)
{
result = HandleException(input, args, e, channel);
}
return result;
}
private static IMethodReturn HandleException(IMethodInvocation input, object[] args, Exception e, IClientChannel channel)
{
if (Logger.IsWarnEnabled)
{
// we log at Warn, caller might handle this without need to log
string msg = string.Format("Exception from " + input.MethodBase.Name + "(" + string.Join(", ", args) + ")");
Logger.Warn(msg, e);
}
IMethodReturn result = input.CreateExceptionMethodReturn(e);
if (channel != null)
{
Logger.Trace("Aborting channel");
channel.Abort();
}
return result;
}
/// <summary>
/// Returns the interfaces required by the behavior for the objects it intercepts.
/// </summary>
/// <returns>
/// The required interfaces.
/// </returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return new [] { typeof(T) };
}
/// <summary>
/// Returns a flag indicating if this behavior will actually do anything when invoked.
/// </summary>
/// <remarks>
/// This is used to optimize interception. If the behaviors won't actually
/// do anything (for example, PIAB where no policies match) then the interception
/// mechanism can be skipped completely.
/// </remarks>
public bool WillExecute
{
get { return true; }
}
/// <summary>
/// Creates new client, that will obtain a fresh connection before each call
/// and closes the channel after each call.
/// </summary>
/// <param name="factory">channel factory to connect to service</param>
/// <returns>instance which will have SoapClientInterceptorBehavior applied</returns>
public static T CreateInstance(ChannelFactory<T> factory)
{
IInterceptionBehavior behavior = new SoapClientInterceptorBehavior<T>(factory);
return (T)Intercept.ThroughProxy<IMy>(
new MyClass(),
new InterfaceInterceptor(),
new[] { behavior });
}
/// <summary>
/// Dummy class to use as target (which will never be called, as this behavior will not delegate to it).
/// Unity Interception does not allow ONLY interceptor, it needs a target instance
/// which must implement at least one public interface.
/// </summary>
public class MyClass : IMy
{
}
/// <summary>
/// Public interface for dummy target.
/// Unity Interception does not allow ONLY interceptor, it needs a target instance
/// which must implement at least one public interface.
/// </summary>
public interface IMy
{
}
}
Related
I have a method which accepts a list of domain events which implement the interface IDomainEvent. What I'm trying to do is get the underlying type of the IDomainEvent and then use IServiceProvider to get a service matching the underlying system type.
For example, this works;
TicketCreatedEvent event = new TicketCreatedEvent();
var service = _serviceProvider.GetService(typeof(IEventHandler<TicketCreatedEvent>));
// Where _serviceProvider is ASP.NET Cores standard DI provider.
But this doesn't as the event object is created as an interface rather than it's concrete type.
IDomainEvent event = new TicketCreatedEvent();
var service = _serviceProvider.GetService(typeof(IEventHandler<TicketCreatedEvent>));
I know I can retrieve the underlying type by using event.GetType().UnderlyingSystemType but I cannot figure out how to then use this within the _serviceProvider.GetService(), I thought I could have done the following, but it isn't valid;
IDomainEvent event = new TicketCreatedEvent();
Type type = event.GetType().UnderlyingSystemType;
var service = _serviceProvider.GetService(typeof(IEventHandler<type>));
Any advice on how to do this would be appreciated.
Sorry, it seems I missed some important information out of my question.
In my example above, the event is created just before the _serviceProvider is used, by in reality the event is passed to a method on an EventRaiser object, like this;
public static Raise<T>(T args) {
var service = (IEventHandler<T>) _locator.GetService(typeof(IEventHandler<T>));
}
TicketCreatedEvent event = new TicketCreatedEvent();
Raise(event); // Works
IDomainEvent event = new TicketCreatedEvent();
Raise(event); // Doesn't work as it cannot locate the service
Where T is created using the interface, the service cannot be located, it only works if T is directly of the concrete implementation.
To help solving the problem, here is my complete DomainEventRaiser class. There are two important methods, the first is Raise', which will raise an event right away without being deferred. The second isRaisedDeferredwhich accepts a list of events and handles them,RaisedDeferred` will be called when events need to be deferred, such as after a domain object has been persists.
public class DomainEventsRaiser
{
[ThreadStatic] //so that each thread has its own callbacks
private static List<Delegate> _actions;
// ASP.NET Core DI Service Provider
private static IServiceProvider _locator;
/// <summary>
/// Lets the event raiser know what DI provider to use to find event handlers
/// </summary>
/// <param name="provider"></param>
public static void RegisterProvider(IServiceProvider provider)
{
_locator = provider;
}
public static void Register2<T>(Action<T> callback) where T : IDomainEvent
{
if (_actions == null)
{
_actions = new List<Delegate>();
}
_actions.Add(callback);
}
public static void ClearCallbacks()
{
_actions = null;
}
/// <summary>
/// Accepts a list of events, usually deferred events
/// </summary>
/// <param name="events">list of events to handle</param>
public static void RaiseDeferred(IList<IDomainEvent> events)
{
if (events != null)
{
foreach (IDomainEvent ev in events)
{
Type eventType = ev.GetType().UnderlyingSystemType;
Type genericHandlerType = typeof(IEventHandler<>);
Type constructedHandlerType = genericHandlerType.MakeGenericType(eventType);
var service = _locator.GetService(constructedHandlerType);
constructedHandlerType.GetMethod("Handle").Invoke(service, null);
if (service != null)
{
service.Handle(args); // Cannot resolve symbol 'Handle'
}
}
}
}
/// <summary>
/// Handles an event right away
/// </summary>
/// <param name="args">event arguments</param>
/// <typeparam name="T">the event to handle</typeparam>
public static void Raise<T>(T args) where T : IDomainEvent
{
if (_locator != null)
{
var service = (IEventHandler<T>) _locator.GetService(typeof(IEventHandler<T>));
if (service != null)
{
service.Handle(args);
}
}
if (_actions != null)
{
foreach (var action in _actions)
{
if (action is Action<T>)
{
((Action<T>) action)(args);
}
}
}
}
}
You can probably do something like this:
IDomainEvent #event = new TicketCreatedEvent();
Type eventType = #event.GetType().UnderlyingSystemType;
Type genericHandlerType = typeof(IEventHandler<>);
Type constructedHandlerType = genericHandlerType.MakeGenericType(eventType);
var service = _serviceProvider.GetService(constructedHandlerType);
I assume you're registering your handlers in Startup.cs like:
services.AddTransient<IEventHandler<TicketCreatedEvent>, TicketCreatedEventHandler>();
For more info, see How to: Examine and Instantiate Generic Types with Reflection.
So I've have a working example of Chrome Native Messaging working with C# and it works great sending down to the application and then getting a response back. What I really need to do though, is to be able to call my native application and have it send information to the chrome extension (to load a website url).
The issue is, when I call my exe (console app) with arguments, chrome isn't listening. When I have chrome listening first, it starts up my application and I can no longer send it commands first and if I start it again chrome wasn't connected to that one, so nothing happens.
Ideally I want to call my application like:
nativeapplication.exe viewAccount ABCDEFG
and have my extension that's listening run its viewAccount method with that argument of ABCDEFG.
I have it fine working from chrome -> application -> chrome, but I want to go other application (or command line with arguments) -> application -> chrome.
Is the only way to do this to make my application act as a wcf service or similar, and have another application send it the data and then send the message to chrome? I would like to avoid having my application sit and read from a file or otherwise use resources while "idle". Is Single Instance with WCF the best option or am I missing something simple?
Note: Examples in languages other than C# are fine, as long as its the native application calling the extension, and not the other way around.
Well I ended up going with a single instance application, and used code for a SingleInstance I found somewhere (sorry went through so many sites looking for simplest one)
Ended up using this main class
/// <summary>
/// Holds a list of arguments given to an application at startup.
/// </summary>
public class ArgumentsReceivedEventArgs : EventArgs
{
public string[] Args { get; set; }
}
public class SingleInstance : IDisposable
{
private Mutex _mutex;
private readonly bool _ownsMutex;
private Guid _identifier;
/// <summary>
/// Enforces single instance for an application.
/// </summary>
/// <param name="identifier">An _identifier unique to this application.</param>
public SingleInstance(Guid identifier)
{
this._identifier = identifier;
_mutex = new Mutex(true, identifier.ToString(), out _ownsMutex);
}
/// <summary>
/// Indicates whether this is the first instance of this application.
/// </summary>
public bool IsFirstInstance
{ get { return _ownsMutex; } }
/// <summary>
/// Passes the given arguments to the first running instance of the application.
/// </summary>
/// <param name="arguments">The arguments to pass.</param>
/// <returns>Return true if the operation succeded, false otherwise.</returns>
public bool PassArgumentsToFirstInstance(string[] arguments)
{
if (IsFirstInstance)
throw new InvalidOperationException("This is the first instance.");
try
{
using (var client = new NamedPipeClientStream(_identifier.ToString()))
using (var writer = new StreamWriter(client))
{
client.Connect(200);
foreach (var argument in arguments)
writer.WriteLine(argument);
}
return true;
}
catch (TimeoutException)
{ } //Couldn't connect to server
catch (IOException)
{ } //Pipe was broken
return false;
}
/// <summary>
/// Listens for arguments being passed from successive instances of the applicaiton.
/// </summary>
public void ListenForArgumentsFromSuccessiveInstances()
{
if (!IsFirstInstance)
throw new InvalidOperationException("This is not the first instance.");
ThreadPool.QueueUserWorkItem(ListenForArguments);
}
/// <summary>
/// Listens for arguments on a named pipe.
/// </summary>
/// <param name="state">State object required by WaitCallback delegate.</param>
private void ListenForArguments(object state)
{
try
{
using (var server = new NamedPipeServerStream(_identifier.ToString()))
using (var reader = new StreamReader(server))
{
server.WaitForConnection();
var arguments = new List<string>();
while (server.IsConnected)
arguments.Add(reader.ReadLine());
ThreadPool.QueueUserWorkItem(CallOnArgumentsReceived, arguments.ToArray());
}
}
catch (IOException)
{ } //Pipe was broken
finally
{
ListenForArguments(null);
}
}
/// <summary>
/// Calls the OnArgumentsReceived method casting the state Object to String[].
/// </summary>
/// <param name="state">The arguments to pass.</param>
private void CallOnArgumentsReceived(object state)
{
OnArgumentsReceived((string[])state);
}
/// <summary>
/// Event raised when arguments are received from successive instances.
/// </summary>
public event EventHandler<ArgumentsReceivedEventArgs> ArgumentsReceived;
/// <summary>
/// Fires the ArgumentsReceived event.
/// </summary>
/// <param name="arguments">The arguments to pass with the ArgumentsReceivedEventArgs.</param>
private void OnArgumentsReceived(string[] arguments)
{
if (ArgumentsReceived != null)
ArgumentsReceived(this, new ArgumentsReceivedEventArgs() { Args = arguments });
}
#region IDisposable
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (_mutex != null && _ownsMutex)
{
_mutex.ReleaseMutex();
_mutex = null;
}
disposed = true;
}
}
~SingleInstance()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
And my C# application mostly taken from (C# native host with Chrome Native Messaging):
class Program
{
const string MutexId = "ENTER YOUR GUID HERE, OR READ FROM APP";
public static void Main(string[] args)
{
using (var instance = new SingleInstance(new Guid(MutexId)))
{
if (instance.IsFirstInstance)
{
instance.ArgumentsReceived += Instance_ArgumentsReceived;
instance.ListenForArgumentsFromSuccessiveInstances();
DoMain(args);
}
else
{
instance.PassArgumentsToFirstInstance(args);
}
}
}
private static void Instance_ArgumentsReceived(object sender, ArgumentsReceivedEventArgs e)
{
TryProcessAccount(e.Args);
}
// This is the main part of the program I use, so I can call my exe with program.exe 123 42424 to have it open that specific account in chrome. Replace with whatever code you want to happen when you have multiple instances.
private static void TryProcessAccount(string[] args)
{
if (args == null || args.Length < 2 || args[0] == null || args[1] == null || args[0].Length != 3) { return; }
var openAccountString = GetOpenAccountString(args[0], args[1]);
Write(openAccountString);
}
private static void DoMain(string[] args)
{
TryProcessAccount(args);
JObject data = Read();
while ((data = Read()) != null)
{
if (data != null)
{
var processed = ProcessMessage(data);
Write(processed);
if (processed == "exit")
{
return;
}
}
}
}
public static string GetOpenAccountString(string id, string secondary)
{
return JsonConvert.SerializeObject(new
{
action = "open",
id = id,
secondary = secondary
});
}
public static string ProcessMessage(JObject data)
{
var message = data["message"].Value<string>();
switch (message)
{
case "test":
return "testing!";
case "exit":
return "exit";
case "open":
return GetOpenAccountString("123", "423232");
default:
return message;
}
}
public static JObject Read()
{
var stdin = Console.OpenStandardInput();
var length = 0;
var lengthBytes = new byte[4];
stdin.Read(lengthBytes, 0, 4);
length = BitConverter.ToInt32(lengthBytes, 0);
var buffer = new char[length];
using (var reader = new StreamReader(stdin))
{
while (reader.Peek() >= 0)
{
reader.Read(buffer, 0, buffer.Length);
}
}
return (JObject)JsonConvert.DeserializeObject<JObject>(new string(buffer))["data"];
}
public static void Write(JToken data)
{
var json = new JObject
{
["data"] = data
};
var bytes = System.Text.Encoding.UTF8.GetBytes(json.ToString(Formatting.None));
var stdout = Console.OpenStandardOutput();
stdout.WriteByte((byte)((bytes.Length >> 0) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 8) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 16) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 24) & 0xFF));
stdout.Write(bytes, 0, bytes.Length);
stdout.Flush();
}
}
You're not missing anything simple: Native Messaging works only by launching a new process, it cannot attach to an existing one.
However, you can spin up an instance and keep it around with connectNative instead of sendNativeMessage for a single exchange. Then, that instance will have to listen to some external event happening.
At a very high level, this can indeed be achieved by a single-instance application. I do not have more concrete recommendations for C# though.
What is the most efficient way in Quickfix/n 1.4 to extract the message type as defined here: http://www.fixprotocol.org/FIXimate3.0/en/FIX.5.0SP2/messages_sorted_by_type.html
I currently use var msgType = Message.GetMsgType(message.ToString()); which results in "A" for a Logon message. Is there a better way? I try to determine the message type within ToAdmin(...) in order to catch an outgoing Logon request message so I can add the username and password.
I would love to do it through MessageCracker but so far I have not found a way to implement a catch-all-remaining message types in case I have not implemented all OnMessage overloads. (Please see related question: Quickfix, Is there a "catch-all" method OnMessage to handle incoming messages not handled by overloaded methods?).
Thanks
Not your title question, but a key part of it:
I try to determine the message type within ToAdmin(...) in order to catch an outgoing Logon request message so I can add the username and password.
Here's a blob of code that pretty much nails it (taken from this post to the QF/n mailing list):
public void ToAdmin(Message message, SessionID sessionID)
{
// Check message type
if (message.Header.GetField(Tags.MsgType) == MsgType.LOGON)
{
// Yes it is logon message
// Check if local variables YourUserName and YourPassword are set
if (!string.IsNullOrEmpty(YourUserName) && !string.IsNullOrEmpty(YourPassword))
{
// Add Username and Password fields to logon message
((Logon) message).Set(new Username(YourUserName));
((Logon) message).Set(new Password(YourPassword));
}
}
}
Here is another approach using the idea I've mentioned in the other post. It's actually very simple to split the Crack method in two methods and have OnMessageTo and OnMessageFrom handlers. The modified implementation of the MessageCracker helper class above is aware about the message direction, though certainly can be improved.
In your Application, implement like this (not complete code):
public class MyFixApplication: DirectedMessageCracker, Application
{
...
public void FromAdmin(Message msg, SessionID sessionId)
{
CrackFrom(msg, sessionId);
}
public void ToAdmin(Message msg, SessionID sessionId)
{
CrackTo(msg, sessionId);
}
public void OnMessageTo(Logon msg, SessionID sessionId)
{
//Treat the outgoing message, set user, password, etc
}
public void OnMessageFrom(Allocation msg, SessionID sessionId)
{
//Treat the incoming Allocation message
}
...and so on
And the modified MessageCracker:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace QuickFix
{
/// <summary>
/// Helper class for delegating message types for various FIX versions to
/// type-safe OnMessage methods, supports handling of incoming and outgoing messages separatelly
/// </summary>
public abstract class DirectedMessageCracker
{
private readonly Dictionary<Type, MethodInfo> _toHandlerMethods = new Dictionary<Type, MethodInfo>();
private readonly Dictionary<Type, MethodInfo> _fromHandlerMethods = new Dictionary<Type, MethodInfo>();
protected DirectedMessageCracker()
{
Initialize(this);
}
private void Initialize(Object messageHandler)
{
var handlerType = messageHandler.GetType();
var methods = handlerType.GetMethods();
foreach (var m in methods)
{
if (IsToHandlerMethod(m))
_toHandlerMethods[m.GetParameters()[0].ParameterType] = m;
else if (IsFromHandlerMethod(m))
_fromHandlerMethods[m.GetParameters()[0].ParameterType] = m;
}
}
static public bool IsToHandlerMethod(MethodInfo m)
{
return IsHandlerMethod("OnMessageTo", m);
}
static public bool IsFromHandlerMethod(MethodInfo m)
{
return IsHandlerMethod("OnMessageFrom", m);
}
static public bool IsHandlerMethod(string searchMethodName, MethodInfo m)
{
return (m.IsPublic
&& m.Name.StartsWith(searchMethodName)
&& m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType.IsSubclassOf(typeof(Message))
&& typeof(SessionID).IsAssignableFrom(m.GetParameters()[1].ParameterType)
&& m.ReturnType == typeof(void));
}
/// <summary>
/// Process ("crack") a FIX message and call the registered handlers for that type, if any
/// </summary>
/// <param name="handlerMethods"></param>
/// <param name="message"></param>
/// <param name="sessionID"></param>
private void Crack(IDictionary<Type, MethodInfo> handlerMethods, Message message, SessionID sessionID)
{
var messageType = message.GetType();
MethodInfo handler;
if (handlerMethods.TryGetValue(messageType, out handler))
handler.Invoke(this, new object[] { message, sessionID });
else
throw new UnsupportedMessageType();
}
/// <summary>
/// Process ("crack") an INCOMING FIX message and call the registered handlers for that type, if any
/// </summary>
/// <param name="message"></param>
/// <param name="sessionID"></param>
public void CrackFrom(Message message, SessionID sessionID)
{
Crack(_fromHandlerMethods, message, sessionID);
}
/// <summary>
/// Process ("crack") an OUTGOING FIX message and call the registered handlers for that type, if any
/// </summary>
/// <param name="message"></param>
/// <param name="sessionID"></param>
public void CrackTo(Message message, SessionID sessionID)
{
Crack(_toHandlerMethods, message, sessionID);
}
}
}
You can also skip the crack instead of throwing an exception in case of you don't want to implement all possible message handlers by just removing the throw new UnsupportedMessageType(); from the crack method.
Another idea is to split cracking Admin/App messages.
In this case you could just do this inside ToAdmin:
var logonMessage = msg as Logon;
if (logonMessage != null)
{
//Treat the logon message as you want
}
Or use the MessageCracker as explained in the other answer that you mentioned.
Hope it helps.
Consider the sample code below consisting of a Class Library design and an executable Program using the library.
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
m_StageApp = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
// Question: How to add actor to stage?
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
Question
Stage and Actor have circular dependency and seems bad to me.
For example, how should we add actors to stage?
If I let user to create new Actor() themselves,
then they must keep on supplying the Stage.
If I give Actor() an internal constructor and make Stage a factory,
then I lose some of the flexibility for users to do making inherited Actors.
If I make Stage a singleton, then I can only have one set of SharedSetting.
In case the user wants more than one Stage in his AppExe, then it cannot be done.
Is there anyway to redesign the architecture so as to avoid the problems above?
If your functionality is not limited by sharing the StageApp settings between actors, but also will be some other logic. For example when you need to know parent StageApp from Actor and vice versa. I preffer to implement it in this way:
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public int TotalActorsCount
{
get
{
return m_actors.Count;
}
}
public void AddActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (m_actors.Contains(actor))
return; // or throw an exception
m_actors.Add(actor);
if (actor.Stage != this)
{
actor.Stage = this;
}
}
// we are hiding this method, to avoid because we can change Stage only to another non null value
// so calling this method directly is not allowed
internal void RemoveActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (!m_actors.Contains(actor))
return; // or throuw exception
m_actors.Remove(actor);
}
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
public StageApp Stage
{
get
{
return m_StageApp;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (m_StageApp != value)
{
if (m_StageApp != null) // not a call from ctor
{
m_StageApp.RemoveActor(this);
}
m_StageApp = value;
m_StageApp.AddActor(this);
}
}
}
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
Stage = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
StageApp anotherApp = new StageApp();
anotherApp.SharedSetting = 6;
// actor is added to the stage automatically after instantiation
Actor a1 = new Actor(app);
Actor a2 = new Actor(app);
Actor a3 = new Actor(anotherApp);
Console.WriteLine("Actors in anotherApp before moving actor:");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by calling method from StageApp class
anotherApp.AddActor(a1);
Console.WriteLine("Actors in anotherApp after calling method (should be 2):");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by setting Stage through property
a2.Stage = anotherApp;
Console.WriteLine("Actors in anotherApp after setting property of Actor instance (should be 3):");
Console.WriteLine(anotherApp.TotalActorsCount);
Console.WriteLine("Actors count in app (should be empty):");
Console.WriteLine(app.TotalActorsCount);
}
}
}
It allows to you to manipulate with object relationships transparently, but requires a little bit mor code to implement.
How about adding a new class "ActorRole" that defines the behaviour of the actor in each Stage. It lets you decouple Actor and Stage from each other, so you can instantiate both independently (through a factory for example) and then combine them creating ActorRole objects that configure your stages. This combinations can be made using a Builder pattern if it is needed.
If you need to dynamically change your actor behaviour, you can use a Strategy pattern based on the ActorRole class, so depending on the Stage, you can assign to the actor different concrete implementations of its behaviour.
I would solve it by using Func instead of passing in the Stage to the Actor. Like this:
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.CreateActor();
app.SharedSetting = 5;
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
namespace AppLib
{
class StageApp
{
public int SharedSetting { get; set; }
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public void CreateActor()
{
m_actors.Add(new Actor(Executed));
}
private int Executed(int arg)
{
return SharedSetting * arg;
}
}
class Actor
{
private int m_Property;
private Func<int, int> m_executed;
public Actor(Func<int, int> executed)
{
m_executed = executed;
m_Property = new Random().Next();
}
public int Execute()
{
return m_executed(m_Property);
}
}
}
I totally agree with you that circular references is not fun :).
You could also solve this using events, but I like passing functions like callback.
Here's the situation:
/// <summary>
/// A business logic class.
/// </summary>
public class BusinessClassWithInterceptor : BusinessClass, IBusinessClass
{
/// <summary>
/// Initializes a new instance of the <see cref="BusinessClassWithoutInterceptor"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public BusinessClassWithInterceptor(Logger logger)
: base(logger)
{
}
/// <summary>
/// Displays all cows.
/// </summary>
public void DisplayAllCows()
{
this.Logger.Write("Displaying all cows:");
var repository = new CowRepository();
foreach (CowEntity cow in repository.GetAllCows())
{
this.Logger.Write(" " + cow);
}
}
/// <summary>
/// Inserts a normande.
/// </summary>
public void InsertNormande(int id, string name)
{
this.DisplayAllCows();
var repository = new CowRepository();
repository.InsertCow(new CowEntity { Id = id, Name = name, Origin = CowOrigin.Normandie });
}
}
With castle windsor, this class is configured to be intercepted with this interceptor:
/// <summary>
/// Interceptor for logging business methods.
/// </summary>
public class BusinessLogInterceptor : IInterceptor
{
/// <summary>
/// Intercepts the specified invocation.
/// </summary>
/// <param name="invocation">The invocation.</param>
public void Intercept(IInvocation invocation)
{
Logger logger = ((IBusinessClass)invocation.InvocationTarget).Logger;
var parameters = new StringBuilder();
ParameterInfo[] methodParameters = invocation.Method.GetParameters();
for (int index = 0; index < methodParameters.Length; index++)
{
parameters.AppendFormat("{0} = {1}", methodParameters[index].Name, invocation.Arguments[index]);
if (index < methodParameters.Length - 1)
{
parameters.Append(", ");
}
}
logger.Format("Calling {0}( {1} )", invocation.Method.Name, parameters.ToString());
invocation.Proceed();
logger.Format("Exiting {0}", invocation.Method.Name);
}
}
The issue takes place during the call to InsertNormande.
The call to InsertNormande is well intercepted, but the call to DisplayAllCows in InsertNormande is not intercepted...
It really bothers me.
Is there a way to achieve interception in this scenario ?
I don't think there's an easy way of doing it... method calls that are internal to the class can't be intercepted, since they don't go through the proxy.
You could achieve logging of all methods by other means, such as an AOP framework like PostSharp