I'd like to use an Autofac delegate factory to resolve an object graph where some of the nested objects need to be passed parameters. E.g. If the QuoteService in the Autofac delegate factory example required a url to retrieve data from, or the QuoteService itself had a dependency that required a parameter.
public class WebQuoteService : IQuoteService
{
public WebQuoteService(Uri source)
{
}
}
public class Shareholding
{
public Shareholding(string symbol, uint holding, IQuoteService quoteService)
{
}
}
I'd like to be able to declare and register a delegate like so:
public delegate Owned<Shareholding> ShareholdingFactory(string symbol, uint holding,
Uri source);
builder.RegisterGeneratedFactory<ShareholdingFactory>();
The problem I run into is that Autofac can't resolve the uri parameter of the WebQuoteService.
I've seen a few similar questions & solutions, but nothing particularly neat. Autofac-passing-parameter-to-nested-types suggests registering a lambda to explicitly implement the factory and resolve the nested dependency. I'm sure that would work, but it becomes very messy if the parameter is needed at a deeper level or when there are more dependencies.
The temporary solution I'm using is an improvement on that, resolving the IQuoteService in Shareholding OnPreparing, and forwarding the parameters created by the Autofac generated factory.
builder.RegisterType<Shareholding>().OnPreparing(e =>
{
e.Parameters = e.Parameters.Union(new[]
{
new TypedParameter(typeof (IQuoteService), e.Context.Resolve<IQuoteService>(e.Parameters))
});
});
That works ok and avoids manually resolving other parameters, but I actually need to do it twice to forward the parameters to a second nested level.
I've considered, but not tried to use BeginLifetimeScope(Action<ContainerBuilder>) as suggested by can-components-be-temporarily-registered-in-an-autofac-container. I think I'd have to implement the factory manually, but I could then register the uri so it would work at any nesting level.
What I'd actually like to be able to do is attach to WebQuoteService OnPreparing and access the delegate factory's parameters. Something like this can be made to work with reflection but that's obviously not ideal.
builder.RegisterType<WebQuoteService>().OnPreparing(e =>
{
var parameters = e.Context._context._activationStack.Last().Parameters;
e.Parameters = e.Parameters.Concat(parameters);
});
Can anyone suggest a cleaner alternative to pass parameters to objects nested two levels deep?
Sorry to self-answer, but failing a better suggestion I thought I should document the best solution I have.
In OnPreparing, you can use reflection to access the Autofac activation stack and the parameters passed to the delegate factory. These can then be added to the parameters of the nested component being resolved. This works with any level of nesting (it only needs to be added to OnPreparing for the component that requires parameters.)
Register like so:
builder.RegisterType<WebQuoteService>()
.OnPreparing(AutofacExtensions.ForwardFactoryParameters);
Using this helper class:
public static class AutofacExtensions
{
private static readonly FieldInfo ContextFieldInfo;
private static readonly FieldInfo ActivationStackFieldInfo;
static AutofacExtensions()
{
var autofacAssembly = typeof(IInstanceLookup).Assembly;
Type instanceLookupType = autofacAssembly.GetType("Autofac.Core.Resolving.InstanceLookup");
ContextFieldInfo = instanceLookupType.GetField("_context", BindingFlags.Instance | BindingFlags.NonPublic);
Type resolveOperationType = autofacAssembly.GetType("Autofac.Core.Resolving.ResolveOperation");
ActivationStackFieldInfo = resolveOperationType.GetField("_activationStack", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static IResolveOperation Context(this IInstanceLookup instanceLookup)
{
return (IResolveOperation)ContextFieldInfo.GetValue(instanceLookup);
}
public static IEnumerable<IInstanceLookup> ActivationStack(this IResolveOperation resolveOperation)
{
return (IEnumerable<IInstanceLookup>)ActivationStackFieldInfo.GetValue(resolveOperation);
}
/// <summary>
/// Pass parameters from the top level resolve operation (typically a delegate factory call)
/// to a nested component activation.
/// </summary>
public static void ForwardFactoryParameters(PreparingEventArgs e)
{
var delegateFactoryActivation = ((IInstanceLookup) e.Context).Context().ActivationStack().Last();
e.Parameters = e.Parameters.Concat(delegateFactoryActivation.Parameters);
}
}
From version 6, Matt's answer no longer functions. Below is correct.
public static void ForwardFactoryParameters(PreparingEventArgs e)
{
var ctx = e.Context;
var oper = ctx.GetType().GetProperty("Operation").GetValue(ctx);
var requestStack = oper.GetType().GetProperty("InProgressRequests").GetValue(oper) as SegmentedStack<ResolveRequestContext>;
if (requestStack.Count == 1)
{
//Nothing to do; we are on the first level of the call stack.
return;
}
var entryRequest = requestStack.Last();
e.Parameters = entryRequest.Parameters;
}
Related
I have a custom ILogger implementation along with an ILoggerProvider and I've noticed that the categoryName parameter in ILoggerProvider.CreateLogger seems to be Type.FullName:
Gets the fully qualified name of the type, including its namespace but not its assembly.
However, my production code is obfuscated, and while not all consumers within the codebase are obfuscated, most are and their names become something insignificant (e.g. ╠), but alas, this is the nature of obfuscation.
Answering #madreflection's comment
I took some time to create a setup to test out #madreflection's curiosity surrounding the nameof expression:
public class SampleAttribute : Attribute {
public string Name { get; set; }
public SampleAttribute(string name) =>
Name = name;
}
...
[Sample(nameof(InvoiceService))]
[Obfuscation(Exclude = false)]
public class TestClass {
public TestClass(ILogger<TestClass> logger) {
var attribute = GetType().GetCustomAttribute<SampleAttribute>();
logger.LogInformation($"inline: {nameof(TestClass)}");
logger.LogInformation($"attribute: {attribute.Name}");
}
}
The output shows that the nameof expression is not obfuscated:
inline: TestClass
attribute: TestClass
Now, I'm curious as to where they're going with it! 🤔
With this in mind, is there a documented way to change the category name to a constant value?
A "simple" solution would be to inject ILoggerFactory and call CreateLogger. The category name is a parameter so it can be provided directly.
However, injecting ILogger<T> is often the preferred pattern, and switching to injecting ILoggerFactory could be a non-trivial undertaking. This solution helps avoid that.
There are 3 parts to this solution:
A custom attribute that can be used to mark a class or struct with a category name.
A custom ILoggerFactory implementation that replaces an obfuscated type name with the attribute value, if present.
An extension method for registering the custom ILoggerFactory implementation.
Thanks to #Taco タコス's testing, we know that the obfuscator in question isn't trying to find the type name in string literals and obfuscate it there. That means that nameof can provide meaningful values for the category name in the attribute.
The Attribute
First, we need an attribute. It's nothing special, but here it is.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class LoggerCategoryAttribute : Attribute
{
public LoggerCategoryAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
This attribute can be applied to each class or struct that's used as the T in ILogger<T>. It doesn't even have to be injected into that T's constructor; it could be used anywhere.
The Custom Logger Factory
Next, we'll create a custom ILoggerFactory implementation that wraps a real one. The real logger factory could be the default LoggerFactory or it could be an implementation provided by another logging framework.
The CreateLogger method receives a categoryName parameter which might be a fully qualified type name, but it could be anything. If categoryName is a type name and Type.GetType is able to find its Type instance, CreateLogger looks for the LoggerCategory attribute to get the name and assigns it to categoryName if it's not null/empty. Otherwise, it leaves categoryName alone.
The other methods simply forward to the wrapped ILoggerFactory implementation.
public sealed class RecategorizingLoggerFactory : ILoggerFactory
{
private readonly ILoggerFactory _originalLoggerFactory;
public RecategorizingLoggerFactory(ILoggerFactory originalLoggerFactory)
{
_originalLoggerFactory = originalLoggerFactory;
}
public void AddProvider(ILoggerProvider provider) => _originalLoggerFactory.AddProvider(provider);
public ILogger CreateLogger(string categoryName)
{
Type? type = Type.GetType(categoryName);
if (type is not null)
{
var attribute = type.GetCustomAttribute<LoggerCategoryAttribute>();
if (!string.IsNullOrEmpty(attribute?.Name))
categoryName = attribute.Name;
}
return _originalLoggerFactory.CreateLogger(categoryName);
}
public void Dispose() => _originalLoggerFactory.Dispose();
}
Note: This class is sealed to avoid analysis messages about calling GC.SuppressFinalize in Dispose.
DI Registration
Finally, we need to register the custom logger factory for dependency injection.
If there's already a registration for ILoggerFactory, we can't use Add or TryAdd because the former would throw an exception and the latter would be a no-op. Instead, we need to find the existing registration and replace it in the list. Since IServiceCollection inherits IList<ServiceDescriptor>, it's easy to replace the service descriptor directly.
If there's no registration for ILoggerFactory, we add a new one, and create a new LoggerFactory to wrap, because our custom logger factory still needs to wrap something that can actually create loggers.
public static IServiceCollection InjectRecategorizingLoggerFactory(this IServiceCollection services)
{
if (services is null)
throw new ArgumentNullException(nameof(services));
// List<T> has FindIndex(), but IList<T> does not, so it's inline as a local function here.
static int FindIndex(IList<ServiceDescriptor> list, Func<ServiceDescriptor, bool> predicate)
{
for (int i = 0; i < list.Count; ++i)
{
if (predicate(list[i]))
return i;
}
return -1;
}
int loggerFactoryIndex = FindIndex(services, sd => sd.ServiceType == typeof(ILoggerFactory));
// These two variables will be assigned eventually. Initializing them here prevents definite
// assignment analysis from detecting that all branches of execution below have assigned
// them, and with such large blocks, that can be a real concern, so they are intentionally
// not initialized.
Func<IServiceProvider, object> serviceFactory;
ServiceLifetime lifetime;
if (loggerFactoryIndex >= 0)
{
var oldServiceDescriptor = services[loggerFactoryIndex];
lifetime = oldServiceDescriptor.Lifetime;
// The service could be registered in one of three ways. The first two are easy to support,
// but the third can be fragile. See the notes below the code for details.
if (oldServiceDescriptor.ImplementationFactory is not null)
{
serviceFactory = oldServiceDescriptor.ImplementationFactory;
}
else if (oldServiceDescriptor.ImplementationInstance is ILoggerFactory oldLoggerFactory)
{
serviceFactory = sp => oldLoggerFactory;
}
else if (oldServiceDescriptor.ImplementationType is Type implementationType)
{
serviceFactory = sp =>
{
var loggerProviders = sp.GetServices<ILoggerProvider>();
var filterOption = sp.GetRequiredService<IOptionsMonitor<LoggerFilterOptions>>();
var options = sp.GetService<IOptions<LoggerFactoryOptions>>();
try
{
// BANG: ActivatorUtilities.CreateInstance is not annotated to accept null
// elements in the 'arguments' parameter, but the constructor we want
// to use takes a nullable IOptions<LoggerFactoryOptions>. The method
// signature is too restrictive, and passing null works where null is
// allowed by the constructor.
return ActivatorUtilities.CreateInstance(
sp,
implementationType,
new object[] { loggerProviders, filterOption, options! });
}
catch
{
return new LoggerFactory(loggerProviders, filterOption, options);
}
};
}
else
{
throw new InvalidOperationException("Invalid service descriptor encountered for ILoggerFactory.");
}
}
else
{
lifetime = ServiceLifetime.Singleton;
// No ILoggerFactory was registered. Default to wrapping LoggerFactory.
serviceFactory = sp => new LoggerFactory(
sp.GetServices<ILoggerProvider>(),
sp.GetRequiredService<IOptionsMonitor<LoggerFilterOptions>>(),
sp.GetService<IOptions<LoggerFactoryOptions>>());
}
var newServiceDescriptor = new ServiceDescriptor(
typeof(ILoggerFactory),
sp => new RecategorizingLoggerFactory((ILoggerFactory)serviceFactory(sp)),
lifetime);
if (loggerFactoryIndex >= 0)
{
services[loggerFactoryIndex] = newServiceDescriptor;
}
else
{
services.Add(newServiceDescriptor);
}
return services;
}
Some points of note about the above code:
Although the loggerFactoryIndex >= 0 test could be done once with things moved around a bit, I did it twice because I only wanted one place where newServiceDescriptor is instantiated, since it's rather important and everything was intended to lead to that point.
If an ILoggerFactory implementation other than the default LoggerFactory was already registered, and only if it was registered with implementationType rather than implementationInstance or implementationFactory (these are AddSingleton parameter names), ActivatorUtilities.CreateInstance could fail. This code contains a modest attempt not to hard-code LoggerFactory. A lot more could be done to provide better support for wrapping other logger factories. I'm leaving that as an exercise to the reader.
I've used the "BANG:" comment to justify the use of the null-forgiving operator. I've found that in code reviews, this has led to improvements in various ways once other eyes are drawn to it, often to the point of not needing to use the operator at all. When it can't be rewritten away, it can help point out potential reasons for NullReferenceExceptions when the justification has ceased to be valid.
There should be no reason to get an exception for an "invalid service descriptor" and ServiceDescriptor ensures proper construction, unless reflection were used to null out all the private fields. It's primarily there for definite assignment analysis, as noted in one of the comments.
For completeness, and perhaps a bit of levity, here are some examples of how you might apply the attribute to a HomeController class.
// Confirmed, nameof works.
[LoggerCategory(nameof(HomeController))]
// But you don't have to use nameof if you don't wnat to.
[LoggerCategory("HomeController")]
// Who needs "Controller" anyway? The *Name* of the controller is "Home", after all!
[LoggerCategory("Home")]
// You can include a hard-coded namespace so it looks like the original,
// unobfuscated type name.
[LoggerCategory($"MyApplication.Controllers.{nameof(HomeController)}")]
// A more robust version of the former. As long as the depth of namespace
// doesn't change, this will capture renaming of *any* of the parts.
[LoggerCategory($"{nameof(MyApplication)}.{nameof(MyApplication.Controllers)}.{nameof(HomeController)}")]
I'm presently working on a project that includes tests with RhinoMocks mocked objects. Since upgrading to RhinoMocks 3.6.1 from 3.6.0 previously working project code is failing during testing. The issue seems to be caused by changed behavior of mock objects between versions. The generated Mock objects are now Castle Proxy objects that don't appear to be reflectable. Previously it was possible to gather MethodInfo from a mocked object via reflection, which no longer seems to be the case. Should I be setting up my mocks in a different way?
A greatly simplified example follows:
Given an interface to be mocked
public interface IValidator<in T>
{
bool Validate(T obj);
}
in testing code the mock is created with an expectation:
var validator = MockRepository.GenerateMock<IValidator<string>>();
validator.Expect(v => v.Validate(Arg<string>.Is.Equal("input")))
.Return(true);
...
// the validator object is then passed into a consumer and assertions
// are checked to be sure the consumer and validator appropriately
// behave (outside scope of question)
Within the consumer class reflection is done to get the "Validate" method from the interface in order to be invoked during standard execution:
var method = validator.GetType()
.GetMethod("Validate", BindingFlags.Public | BindingFlags.Instance);
The crux of the issue is method is now null when using the update version of RhinoMocks as reflection no longer seems to work.
The root of my issue is the inability to reflect on the proxy object generated by Rhino / Castle when all I have are instances an no ability to do explicit casting.
I know this might get me punched in the face.
But if you are in a generic class you could quite easily do something like
var method = typeof(IValidator<T>).GetType()
.GetMethod("Validate", BindingFlags.Public | BindingFlags.Instance);
Also if the project is very large and there are alot of tests and mocks, this may be a huge amount of rework :(
EDIT:
Ok round 2 :)
The problem seems to be in the fact that the mock is a dynamic class and does not actually seem to have that method.
How about instead of using GetMethod you create an interface (ITypeHelper) that has a number of wrapper methods for getting types and methods.
Normally these would just call the methods directly (so as to not cause any perfomance penalties), but during testing you could swap out your implementation of ITypeHelper for a MockTypeHelper (by changing the registration in the container or some other mechanisim).
public class RhinoMocks_33901386
{
//public static ITypeHelper TypeHelper = new TypeHelper();
//use when testing
public static ITypeHelper TypeHelper = new MockTypeHelper();
public static void Run()
{
var validator = MockRepository.GenerateMock<IValidator<string>>();
validator.Expect(v => v.Validate(Arg<string>.Is.Equal("input"))).Return(true);
var method = TypeHelper.GetMethod(validator.GetType(), "Validate");
var result = (bool) method.Invoke(validator, new object[] {"input"});
Console.WriteLine(result);
Console.WriteLine("Done");
Console.ReadLine();
}
}
public interface IValidator<in T>
{
bool Validate(T obj);
}
public interface ITypeHelper
{
MethodInfo GetMethod(Type self, string name);
}
public class TypeHelper : ITypeHelper
{
public virtual MethodInfo GetMethod(Type self, string name)
{
return self.GetMethod(name);
}
}
public class MockTypeHelper : ITypeHelper
{
public virtual MethodInfo GetMethod(Type self, string name)
{
if (typeof(IMockedObject).IsAssignableFrom(self) && self.BaseType == typeof(object))
{
self = self.GetInterfaces()
.First(x => x != typeof(IMockedObject) && x != typeof(ISerializable) && x != typeof(IProxyTargetAccessor));
}
return self.GetMethod(name);
}
}
Hope I'm getting warmer ;p
It seems like RihnoMocks or Castle DynamicProxy has changed how it works internally. As #sQuir3l pointed out, it seems to be using dynamic objects internally.
In this particular case you can work around the change by accessing the underlying interface type like this:
var method = ((IMockedObject)validator).ImplementedTypes
.Single(type => type == typeof(IValidator<string>))
.GetMethod("Validate", BindingFlags.Public | BindingFlags.Instance);
I have create an object using this syntax:
var newMessage = Activator.CreateInstance(client.Key);
It appears to create an object of the correct type and allows the object properties to be set. However when I pass the object to a method with signature:
public void Publish<T>(T messageBody)
The Type defined by T is object.
How do I get around this? I can't change the method signature - its from a library - and I need to be able to create objects at runtime without knowing their type beforehand.
UPDATED
The function I am trying to perform relates to sending(Publishing) messages. Ordinarily I would register a message Handler like:
RegisterHandler<MyMessage> (m => do something with message );
and could then call
Publish<MyMessage> (message)
which would eventually end up at the handler. This is cool and works fine.
What I am trying to do is insert an intermediary to act as an exchange and publish the message to multiple handlers. I know there are other things I could use to do this for me such as RabbitMQ, but I was hoping to be able to achieve it with just a small modification to the current code.
So I have a method that registers subscriptions:
public virtual void registerSubscription<T1,T2>()
{
if (handlerMap.ContainsKey(typeof(T2)))
{
throw new ArgumentException("Message handler has already been registered for type: " +typeof(T2).Name);
}
if (!handlerMap.ContainsValue(typeof(T1)))
{
mqHost.RegisterHandler<T1> (m => distributeMessage(m) );
}
handlerMap[typeof(T2)] = typeof(T1);
}
I call the method with two classes, a base class and a class that inherits the base class:
public class MyMessage
{
public string name {get;set;}
}
public class MyMessage2:MyMessage{}
This bit works well and I get a map of handlers built up. The problem comes when I do the next bit, the distributeMessage method.
var match = handlerMap.Where(i => i.Value == message.Body.GetType());
foreach (var client in match)
{
var newMessage = Activator.CreateInstance(client.Key);
newMessage.PopulateWith(message.Body);
messageProducer.Publish(createMessage(newMessage));
}
The messageProducer.publish has the signature:
public void Publish<T>(T messageBody)
I can't (easily) modify this - it is part of a library. There is another method I could call:
public void Publish<T>(IMessage<T> message)
But I can't see that this would be any easier as I would have to create a Message which still requires .
You can use some reflection to try to create a generic method of Publish given the type information you knew when calling the Activator. If I have misunderstood what you are trying to do, please ask and I can modify this code.
object newObject = Activator.CreateInstance(myType);
var publishMethod = typeof(MessageProducer).GetMethod("Publish");
var publishMethodWithCorrectType = publishMethod.MakeGenericMethod(new Type[] { myType });
publishMethodWithCorrectType.Invoke(messageProducer, new object[]{newObject});
I hope this helps.
Try do this:
var newMessage = (MyType)Activator.CreateInstance(client.Key);
p.s. MyType is an base type or interface...
You would need to invoke the Publish<T> method via reflection as well to continue along this route.
Another suggestion would be to make the class object's class generic based on the client.Key type, then implement a Publish method within that class - the implementation will know what T is.
Found this answer to another question
and implemented this:
typeof(MessageExchange)
.GetMethod("createMessage",BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(newMessage.GetType())
.Invoke(null, new object[] { newMessage });
I'm now getting the correct type being passed through.
I'm creating a framework that contains a wrapper around a library (specifically SharpBrake) that performs all interaction with SharpBrake via reflection so there's no hard dependency on the library to 3rd parties of my framework.
If 3rd parties of my framework wants to use SharpBrake, they can just stuff the SharpBrake.dll into the bin folder, but if they don't, they can just forget about it. If my framework had explicit references to SharpBrake types, users of my framework would get exceptions during runtime of SharpBrake.dll missing, which I don't want.
So, my wrapper first loads SharpBrake.dll from disk, finds the AirbrakeClient type, and stores a delegate pointing to the AirbrakeClient.Send(AirbrakeNotice) method in a private field. My problem, however, is that since the Send() method takes an AirbrakeNotice object and I can't reference the AirbrakeNotice object directly, I need to somehow convert the Send() method to an Action<object>.
I have a strong feeling this isn't possible, but I want to explore all options before settling on exposing Delegate and using DynamicInvoke(), which I assume is far from optimal, performance-wise. What I would love to do is the following:
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
Type noticeType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeNotice");
MethodInfo sendMethod = clientType.GetMethod("Send", new[] { noticeType });
object client = Activator.CreateInstance(clientType);
Type actionType = Expression.GetActionType(noticeType);
Delegate sendMethodDelegate = Delegate.CreateDelegate(actionType, client, sendMethod);
// This fails with an InvalidCastException:
Action<object> sendAction = (Action<object>)sendMethodDelegate;
However, this fails with the following exception:
System.InvalidCastException: Unable to cast object of type 'System.Action`1[SharpBrake.Serialization.AirbrakeNotice]' to type 'System.Action`1[System.Object]'.
Obviously, because sendMethodDelegate is an Action<AirbrakeNotice> and not an Action<object>. Since I can't mention AirbrakeNotice in my code, I'm forced to do this:
Action<object> sendAction = x => sendMethodDelegate.DynamicInvoke(x);
or just exposing the Delegate sendMethodDelegate directly. Is this possible? I know that there's chance of getting into situations where the object can be of a different type than AirbrakeNotice which would be bad, but seeing how much you can mess up with reflection anyway, I'm hoping there's a loophole somewhere.
If you're happy to use expression trees, it's reasonably simple:
ConstantExpression target = Expression.Constant(client, clientType);
ParameterExpression parameter = Expression.Parameter(typeof(object), "x");
Expression converted = Expression.Convert(parameter, noticeType);
Expression call = Expression.Call(target, sendMethod, converted);
Action<object> action = Expression.Lambda<Action<object>>(call, parameter)
.Compile();
I think that's what you want...
If you don't need below C# 4 support you can get much greater performance using the dynamic vs DynamicInvoke.
Action<dynamic> sendAction = x => sendMethodDelegate(x);
Actually I guess you wouldn't even need the above if you can use dynamic, because it would increase performance and simplify everything if you just did:
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
dynamic client = Activator.CreateInstance(clientType);
...
client.Send(anAirbrakeNotice);
But if you need to support .net 3.5 jon skeets answer with expression trees is definitely the way to go.
From my comment on the OP:
I'd avoid extended use of reflections if you are concerned about performance. If you can come up with an interface for the class(es) you are using, then I'd create one. Then write a wrapper that implements the interface by calling into the SharpBreak code, and stuff it in a separate DLL. Then dynamically load just your wrapper assembly and concrete wrapper type(s), and call into that interface. Then you don't have to do reflections at a method level.
I'm not sure all the classes you'd need, but here's a simple example of how you can hook into that library with loose coupling based on interfaces.
In your program's assembly:
public IExtensions
{
void SendToAirbrake(Exception exception);
}
public static AirbreakExtensions
{
private static IExtensions _impl;
static()
{
impl = new NullExtensions();
// Todo: Load if available here
}
public static void SendToAirbrake(this Exception exception)
{
_impl.SendToAirbrake(exception);
}
}
internal class NullExtensions : IExtensions // no-op fake
{
void SendToAirbrake(Exception exception)
{
}
}
In a load-if-available (via reflections) assembly
public ExtensionsAdapter : IExtensions
{
void SendToAirbrake(Exception exception)
{
SharpBrake.Extensions.SendToAirbrake(exception);
}
}
The advantage of this approach is that you only use reflections once (on load), and never touch it again. It is also simple to modify to use dependency injection, or mock objects (for testing).
Edit:
For other types it will take a bit more work.
You might need to use the Abstract Factory pattern to instantiate an AirbrakeNoticeBuilder, since you need to deal directly with the interface, and can't put constructors in interfaces.
public interface IAirbrakeNoticeBuilderFactory
{
IAirbrakeNoticeBuilder Create();
IAirbrakeNoticeBuilder Create(AirbrakeConfiguration configuration);
}
If you're dealing with custom Airbreak structures, you'll have even more work.
E.g. for the AirbrakeNoticeBuilder you will have to create duplicate POCO types for any related classes that you use.
public interface IAirbrakeNoticeBuilder
{
AirbrakeNotice Notice(Exception exception);
}
Since you're returning AirbrakeNotice, you might have to pull in nearly every POCO under the Serialization folder, depending on how much you use, and how much you pass back to the framework.
If you decide to copy the POCO code, including the whole object tree, you could look into using AutoMapper to convert to and from your POCO copies.
Alternately, if you don't use the values in the classes you're getting back, and just pass them back to the SharpBreak code, you could come up with some sort of opaque reference scheme that will use a dictionary of your opaque reference type to the actual POCO type. Then you don't have to copy the whole POCO object tree into your code, and you don't need to take as much runtime overhead to map the object trees back and forth:
public class AirbrakeNotice
{
// Note there is no implementation
}
internal class AirbreakNoticeMap
{
static AirbreakNoticeMap()
{
Map = new Dictionary<AirbreakNotice, SharpBreak.AirbreakNotice>();
}
public static Dictionary<AirbreakNotice, SharpBreak.AirbreakNotice> Map { get; }
}
public interface IAirbrakeClient
{
void Send(AirbrakeNotice notice);
// ...
}
internal class AirbrakeClientWrapper : IAirbrakeClient
{
private AirbrakeClient _airbrakeClient;
public void Send(AirbrakeNotice notice)
{
SharpBreak.AirbrakeNotice actualNotice = AirbreakNoticeMap.Map[notice];
_airbrakeClient.Send(actualNotice);
}
// ...
}
internal class AirbrakeNoticeBuilderWrapper : IAirbrakeNoticeBuilder
{
AirbrakeNoticeBuilder _airbrakeNoticeBuilder;
public AirbrakeNotice Notice(Exception exception)
{
SharpBreak.AirbrakeNotice actualNotice =
_airbrakeNoticeBuilder.Notice(exception);
AirbrakeNotice result = new AirbrakeNotice();
AirbreakNoticeMap.Map[result] = actualNotice;
return result;
}
// ...
}
Keep in mind that you only need to wrap the classes and parts of the public interface that you're going to use. The object will still behave the same internally, even if you don't wrap its entire public interface. This might mean you have to do less work, so think hard and try to wrap only what you need now, and what you know you're going to need in the future. Keep YAGNI in mind.
The programming style I have come to really like for problems like this is to write as much strongly-typed code as possible, and then hand off the logic from the dynamically-typed code to the strongly-typed code. So I would write your code like this:
//your code which gets types
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
Type noticeType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeNotice");
//construct my helper object
var makeDelegateHelperType=typeof(MakeDelegateHelper<,>).MakeGenericType(clientType, noticeType);
var makeDelegateHelper=(MakeDelegateHelper)Activator.CreateInstance(makeDelegateHelperType);
//now I am in strongly-typed world again
var sendAction=makeDelegateHelper.MakeSendAction();
And this is the definition of the helper object, which is able to get away with fewer reflectiony calls.
public abstract class MakeDelegateHelper {
public abstract Action<object> MakeSendAction();
}
public class MakeDelegateHelper<TClient,TNotice> : MakeDelegateHelper where TClient : new() {
public override Action<object> MakeSendAction() {
var sendMethod = typeof(TClient).GetMethod("Send", new[] { typeof(TNotice) });
var client=new TClient();
var action=(Action<TNotice>)Delegate.CreateDelegate(typeof(Action<TNotice>), client, sendMethod);
return o => action((TNotice)o);
}
}
I asked a question yesterday regarding using either reflection or Strategy Pattern for dynamically calling methods.
However, since then I have decided to change the methods into individual classes that implement a common interface. The reason being, each class, whilst bearing some similarities also perform certain methods unique to that class.
I had been using a strategy as such:
switch (method)
{
case "Pivot":
return new Pivot(originalData);
case "GroupBy":
return new GroupBy(originalData);
case "Standard deviation":
return new StandardDeviation(originalData);
case "% phospho PRAS Protein":
return new PhosphoPRASPercentage(originalData);
case "AveragePPPperTreatment":
return new AveragePPPperTreatment(originalData);
case "AvgPPPNControl":
return new AvgPPPNControl(originalData);
case "PercentageInhibition":
return new PercentageInhibition(originalData);
default:
throw new Exception("ERROR: Method " + method + " does not exist.");
}
However, as the number of potential classes grow, I will need to keep adding new ones, thus breaking the closed for modification rule.
Instead, I have used a solution as such:
var test = Activator.CreateInstance(null, "MBDDXDataViews."+ _class);
ICalculation instance = (ICalculation)test.Unwrap();
return instance;
Effectively, the _class parameter is the name of the class passed in at runtime.
Is this a common way to do this, will there be any performance issues with this?
I am fairly new to reflection, so your advice would be welcome.
When using reflection you should ask yourself a couple of questions first, because you may end up in an over-the-top complex solution that's hard to maintain:
Is there a way to solve the problem using genericity or class/interface inheritance?
Can I solve the problem using dynamic invocations (only .NET 4.0 and above)?
Is performance important, i.e. will my reflected method or instantiation call be called once, twice or a million times?
Can I combine technologies to get to a smart but workable/understandable solution?
Am I ok with losing compile time type safety?
Genericity / dynamic
From your description I assume you do not know the types at compile time, you only know they share the interface ICalculation. If this is correct, then number (1) and (2) above are likely not possible in your scenario.
Performance
This is an important question to ask. The overhead of using reflection can impede a more than 400-fold penalty: that slows down even a moderate amount of calls.
The resolution is relatively easy: instead of using Activator.CreateInstance, use a factory method (you already have that), look up the MethodInfo create a delegate, cache it and use the delegate from then on. This yields only a penalty on the first invocation, subsequent invocations have near-native performance.
Combine technologies
A lot is possible here, but I'd really need to know more of your situation to assist in this direction. Often, I end up combining dynamic with generics, with cached reflection. When using information hiding (as is normal in OOP), you may end up with a fast, stable and still well-extensible solution.
Losing compile time type safety
Of the five questions, this is perhaps the most important one to worry about. It is very important to create your own exceptions that give clear information about reflection mistakes. That means: every call to a method, constructor or property based on an input string or otherwise unchecked information must be wrapped in a try/catch. Catch only specific exceptions (as always, I mean: never catch Exception itself).
Focus on TargetException (method does not exist), TargetInvocationException (method exists, but rose an exc. when invoked), TargetParameterCountException, MethodAccessException (not the right privileges, happens a lot in ASP.NET), InvalidOperationException (happens with generic types). You don't always need to try to catch all of them, it depends on the expected input and expected target objects.
To sum it up
Get rid of your Activator.CreateInstance and use MethodInfo to find the factory-create method, and use Delegate.CreateDelegate to create and cache the delegate. Simply store it in a static Dictionary where the key is equal to the class-string in your example code. Below is a quick but not-so-dirty way of doing this safely and without losing too much type safety.
Sample code
public class TestDynamicFactory
{
// static storage
private static Dictionary<string, Func<ICalculate>> InstanceCreateCache = new Dictionary<string, Func<ICalculate>>();
// how to invoke it
static int Main()
{
// invoke it, this is lightning fast and the first-time cache will be arranged
// also, no need to give the full method anymore, just the classname, as we
// use an interface for the rest. Almost full type safety!
ICalculate instanceOfCalculator = this.CreateCachableICalculate("RandomNumber");
int result = instanceOfCalculator.ExecuteCalculation();
}
// searches for the class, initiates it (calls factory method) and returns the instance
// TODO: add a lot of error handling!
ICalculate CreateCachableICalculate(string className)
{
if(!InstanceCreateCache.ContainsKey(className))
{
// get the type (several ways exist, this is an eays one)
Type type = TypeDelegator.GetType("TestDynamicFactory." + className);
// NOTE: this can be tempting, but do NOT use the following, because you cannot
// create a delegate from a ctor and will loose many performance benefits
//ConstructorInfo constructorInfo = type.GetConstructor(Type.EmptyTypes);
// works with public instance/static methods
MethodInfo mi = type.GetMethod("Create");
// the "magic", turn it into a delegate
var createInstanceDelegate = (Func<ICalculate>) Delegate.CreateDelegate(typeof (Func<ICalculate>), mi);
// store for future reference
InstanceCreateCache.Add(className, createInstanceDelegate);
}
return InstanceCreateCache[className].Invoke();
}
}
// example of your ICalculate interface
public interface ICalculate
{
void Initialize();
int ExecuteCalculation();
}
// example of an ICalculate class
public class RandomNumber : ICalculate
{
private static Random _random;
public static RandomNumber Create()
{
var random = new RandomNumber();
random.Initialize();
return random;
}
public void Initialize()
{
_random = new Random(DateTime.Now.Millisecond);
}
public int ExecuteCalculation()
{
return _random.Next();
}
}
I suggest you give your factory implementation a method RegisterImplementation. So every new class is just a call to that method and you are not changing your factories code.
UPDATE:
What I mean is something like this:
Create an interface that defines a calculation. According to your code, you already did this. For the sake of being complete, I am going to use the following interface in the rest of my answer:
public interface ICalculation
{
void Initialize(string originalData);
void DoWork();
}
Your factory will look something like this:
public class CalculationFactory
{
private readonly Dictionary<string, Func<string, ICalculation>> _calculations =
new Dictionary<string, Func<string, ICalculation>>();
public void RegisterCalculation<T>(string method)
where T : ICalculation, new()
{
_calculations.Add(method, originalData =>
{
var calculation = new T();
calculation.Initialize(originalData);
return calculation;
});
}
public ICalculation CreateInstance(string method, string originalData)
{
return _calculations[method](originalData);
}
}
This simple factory class is lacking error checking for the reason of simplicity.
UPDATE 2:
You would initialize it like this somewhere in your applications initialization routine:
CalculationFactory _factory = new CalculationFactory();
public void RegisterCalculations()
{
_factory.RegisterCalculation<Pivot>("Pivot");
_factory.RegisterCalculation<GroupBy>("GroupBy");
_factory.RegisterCalculation<StandardDeviation>("Standard deviation");
_factory.RegisterCalculation<PhosphoPRASPercentage>("% phospho PRAS Protein");
_factory.RegisterCalculation<AveragePPPperTreatment>("AveragePPPperTreatment");
_factory.RegisterCalculation<AvgPPPNControl>("AvgPPPNControl");
_factory.RegisterCalculation<PercentageInhibition>("PercentageInhibition");
}
Just as an example how to add initialization in the constructor:
Something similar to: Activator.CreateInstance(Type.GetType("ConsoleApplication1.Operation1"), initializationData);
but written with Linq Expression, part of code is taken here:
public class Operation1
{
public Operation1(object data)
{
}
}
public class Operation2
{
public Operation2(object data)
{
}
}
public class ActivatorsStorage
{
public delegate object ObjectActivator(params object[] args);
private readonly Dictionary<string, ObjectActivator> activators = new Dictionary<string,ObjectActivator>();
private ObjectActivator CreateActivator(ConstructorInfo ctor)
{
Type type = ctor.DeclaringType;
ParameterInfo[] paramsInfo = ctor.GetParameters();
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
Expression[] argsExp = new Expression[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
NewExpression newExp = Expression.New(ctor, argsExp);
LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param);
return (ObjectActivator)lambda.Compile();
}
private ObjectActivator CreateActivator(string className)
{
Type type = Type.GetType(className);
if (type == null)
throw new ArgumentException("Incorrect class name", "className");
// Get contructor with one parameter
ConstructorInfo ctor = type.GetConstructors()
.SingleOrDefault(w => w.GetParameters().Length == 1
&& w.GetParameters()[0].ParameterType == typeof(object));
if (ctor == null)
throw new Exception("There is no any constructor with 1 object parameter.");
return CreateActivator(ctor);
}
public ObjectActivator GetActivator(string className)
{
ObjectActivator activator;
if (activators.TryGetValue(className, out activator))
{
return activator;
}
activator = CreateActivator(className);
activators[className] = activator;
return activator;
}
}
The usage is following:
ActivatorsStorage ast = new ActivatorsStorage();
var a = ast.GetActivator("ConsoleApplication1.Operation1")(initializationData);
var b = ast.GetActivator("ConsoleApplication1.Operation2")(initializationData);
The same can be implemented with DynamicMethods.
Also, the classes are not required to be inherited from the same interface or base class.
Thanks, Vitaliy
One strategy that I use in cases like this is to flag my various implementations with a special attribute to indicate its key, and scan the active assemblies for types with that key:
[AttributeUsage(AttributeTargets.Class)]
public class OperationAttribute : System.Attribute
{
public OperationAttribute(string opKey)
{
_opKey = opKey;
}
private string _opKey;
public string OpKey {get {return _opKey;}}
}
[Operation("Standard deviation")]
public class StandardDeviation : IOperation
{
public void Initialize(object originalData)
{
//...
}
}
public interface IOperation
{
void Initialize(object originalData);
}
public class OperationFactory
{
static OperationFactory()
{
_opTypesByKey =
(from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetTypes()
let att = t.GetCustomAttributes(typeof(OperationAttribute), false).FirstOrDefault()
where att != null
select new { ((OperationAttribute)att).OpKey, t})
.ToDictionary(e => e.OpKey, e => e.t);
}
private static IDictionary<string, Type> _opTypesByKey;
public IOperation GetOperation(string opKey, object originalData)
{
var op = (IOperation)Activator.CreateInstance(_opTypesByKey[opKey]);
op.Initialize(originalData);
return op;
}
}
That way, just by creating a new class with a new key string, you can automatically "plug in" to the factory, without having to modify the factory code at all.
You'll also notice that rather than depending on each implementation to provide a specific constructor, I've created an Initialize method on the interface I expect the classes to implement. As long as they implement the interface, I'll be able to send the "originalData" to them without any reflection weirdness.
I'd also suggest using a dependency injection framework like Ninject instead of using Activator.CreateInstance. That way, your operation implementations can use constructor injection for their various dependencies.
Essentially, it sounds like you want the factory pattern. In this situation, you define a mapping of input to output types and then instantiate the type at runtime like you are doing.
Example:
You have X number of classes, and they all share a common interface of IDoSomething.
public interface IDoSomething
{
void DoSomething();
}
public class Foo : IDoSomething
{
public void DoSomething()
{
// Does Something specific to Foo
}
}
public class Bar : IDoSomething
{
public void DoSomething()
{
// Does something specific to Bar
}
}
public class MyClassFactory
{
private static Dictionary<string, Type> _mapping = new Dictionary<string, Type>();
static MyClassFactory()
{
_mapping.Add("Foo", typeof(Foo));
_mapping.Add("Bar", typeof(Bar));
}
public static void AddMapping(string query, Type concreteType)
{
// Omitting key checking code, etc. Basically, you can register new types at runtime as well.
_mapping.Add(query, concreteType);
}
public IDoSomething GetMySomething(string desiredThing)
{
if(!_mapping.ContainsKey(desiredThing))
throw new ApplicationException("No mapping is defined for: " + desiredThing);
return Activator.CreateInstance(_mapping[desiredThing]) as IDoSomething;
}
}
There's no error checking here. Are you absolutely sure that _class will resolve to a valid class? Are you controlling all the possible values or does this string somehow get populated by an end-user?
Reflection is generally most costly than avoiding it. Performance issues are proportionate to the number of objects you plan to instantiate this way.
Before you run off and use a dependency injection framework read the criticisms of it. =)