Find class to instantiate by name without namespace or assembly? (.NET) - c#

I'd like to instantiate a class by name (a string) without specifying a namespace or assembly. Like this (Unity syntax):
var processor = container.Resolve<IProcessor>("SpecialProcessor");
would instantiate the first IProcessor it finds called SpecialProcessor. Maybe
MyNamespace.SpecialProcessor
I'd like to avoid having to create an entry in a config every time somebody adds a new processor. I'm fine with having an entry for all candidate assemblies though.
Can I use an IoC container for something like this or should I roll my own?

Here's a function that does something very similar to what you want. You can modify it to filter based on a specific class name pretty easily.
These functions have references to a few utilities we use for logging and exception handling. You'll need to replace them with whatever you normally do in these situations.
public static T FindAndCreate<T>(bool localOnly, bool exportedOnly)
{
Type[] types = FindAssignableClasses(typeof(T), localOnly, exportedOnly, false);
if (types.Length == 0)
{
return default(T);
}
if (types.Length != 1)
{
Log.Warn(typeof(ReflectionUtil),
"FindAndCreate found {0} instances of {1} whereas only 1 was expected. Using {2}. {3}",
types.Length,
typeof(T).FullName,
types[0].FullName,
String.Join("\r\n ", Array.ConvertAll<Type, String>(types, GetFullName)));
}
try
{
return (T)Activator.CreateInstance(types[0]);
}
catch (Exception ex)
{
throw ExceptionUtil.Rethrow(ex,
"Unable to create instance of {0} found for interface {1}.",
types[0].FullName,
typeof(T).FullName);
}
}
public static Type[] FindAssignableClasses(Type assignable, bool localOnly, bool exportedOnly, bool loadDll)
{
var list = new List<Type>();
string localDirectoryName = Path.GetDirectoryName(typeof(ReflectionUtil).Assembly.CodeBase);
if (loadDll && !_loadedAllDlls)
{
foreach (string dllPath in Directory.GetFiles(localDirectoryName.Substring(6), "*.dll"))
{
try
{
Assembly.LoadFrom(dllPath);
}
catch
{
// ignore
}
}
_loadedAllDlls = true;
}
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
if (localOnly && Path.GetDirectoryName(asm.CodeBase) != localDirectoryName)
{
continue;
}
Type[] typesInAssembly;
try
{
typesInAssembly = exportedOnly ? asm.GetExportedTypes() : asm.GetTypes();
}
catch
{
continue;
}
foreach (Type t in typesInAssembly)
{
try
{
if (assignable.IsAssignableFrom(t) && assignable != t)
{
list.Add(t);
}
}
catch (Exception ex)
{
Log.Debug(
typeof(ReflectionUtil),
String.Format(
"Error searching for types assignable to type {0} searching assembly {1} testing {2}{3}",
assignable.FullName,
asm.FullName,
t.FullName,
FlattenReflectionTypeLoadException(ex)),
ex);
}
}
}
catch (Exception ex)
{
// ignore dynamic module error, no way to check for this condition first
// http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/7b02223aefc6afba/c8f5bd05cc8b24b0
if (!(ex is NotSupportedException && ex.Message.Contains("not supported in a dynamic")))
{
Log.Debug(
typeof(ReflectionUtil),
String.Format(
"Error searching for types assignable to type {0} searching assembly {1} from {2}{3}",
assignable.FullName,
asm.FullName,
asm.CodeBase,
FlattenReflectionTypeLoadException(ex)),
ex);
}
}
}
return list.ToArray();
}

It sounds like you have a plugin architecture and you want to allow other components to provide implementations of IProcessor without having to update some master config file. If that's the case, then I think you are best suited by using MEF (managed extensibility framework) (Website).
This is a framework designed to allow such behavior. Once you establish a catalog of assemblies to load components from, importing the collection of IProcessor instances is as easy as the following
var processors = container.GetExportedValues<IProcessor>();
There are many tutorials online for MEF that should get you started.

Related

Is my understanding of PSPropertyAdapter correct?

I am writing a binary PowerShell module that, much like the ActiveDirectory module, will have a number of cmdlets and types that can potentially return more than the default set of properties - and those properties (100+) are dependent on what the user requests. Just like the AD module, I would like to return the type with the properties that were requested so that it is transparent to the user i.e. not one huge class with lots of empty properties that they haven't requested.
I was looking at the documentation for the ActiveDirectory module and I noticed that things like ADUser and ADComputer ultimately are inherited from ADPropertyCollection which I assume has the properties required in its InnerDictionary after whatever searches it does.
This did not really explain how PowerShell presents the AD types flexibly i.e.
(Get-ADUser -Identity some.user).GetType()
(Get-ADUser -Identity some.user -Properties *).GetType()
# Both return a type of ADUser, despite have drastically different amounts of properties.
This was until I looked at the Types ps1xml file for the AD module, which presents something like this:
<Types>
<!-- other types -->
<Type>
<Name>Microsoft.ActiveDirectory.Management.ADUser</Name>
<TypeAdapter>
<TypeName>Microsoft.ActiveDirectory.Management.ADEntityAdapter</TypeName>
</TypeAdapter>
</Type>
</Types>
So I guess the source of the "magic" properties is ADEntityAdapter which is inherited from the abstract class PSPropertyAdapter.
The issue I have is now I am not sure how to implement it and there are not any easily searchable examples of it being implemented. I appreciate its a real edge case. I have had a small attempt at a very rough implementation below, please ignore any code faux pas - I will of course not actually write the code like below. I just wanted to at least try and show I have thought about this.
using System.Collections.Generic;
namespace Sample
{
public class PropertyCollection
{
public string Id { get; set; }
public Dictionary<string, object> Attributes { get; set; }
public PropertyCollection()
{
this.Id = "SampleID";
this.Attributes = new Dictionary<string, object>();
for (var i = 0; i < 10; i++)
{
this.Attributes.Add("KeyAttribute" + i, i);
}
for (var i = 10; i < 100; i++)
{
this.Attributes.Add("OtherAttribute" + i, i);
}
}
}
}
namespace Sample
{
public class ReturnedClass : PropertyCollection
{
public string SomeName { get; set; }
public ReturnedClass() : base() { }
}
}
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
namespace Sample
{
public class PropertyEntityAdapter : PSPropertyAdapter
{
public override Collection<PSAdaptedProperty> GetProperties(object baseObject)
{
PropertyCollection pc = baseObject as PropertyCollection;
if (pc == null)
{
throw new Exception("Some Exception");
}
Collection<PSAdaptedProperty> collection = new Collection<PSAdaptedProperty>();
foreach (string name in pc.Attributes.Keys)
{
collection.Add(new PSAdaptedProperty(name, null));
}
return collection;
}
public override PSAdaptedProperty GetProperty(object baseObject, string propertyName)
{
PropertyCollection pc = baseObject as PropertyCollection;
if (pc.Attributes.TryGetValue(propertyName, out object pcValue))
{
return new PSAdaptedProperty(propertyName, pcValue);
}
throw new Exception("Prop not found");
}
public override string GetPropertyTypeName(PSAdaptedProperty adaptedProperty)
{
if (adaptedProperty == null)
{
throw new Exception("prop null");
}
PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
if (pc == null)
{
throw new Exception("not found");
}
if (pc.Attributes.TryGetValue(adaptedProperty.Name, out object pcValue))
{
return pcValue.GetType().FullName;
}
return pc.GetType().FullName;
}
public override object GetPropertyValue(PSAdaptedProperty adaptedProperty)
{
if (adaptedProperty?.BaseObject == null || adaptedProperty?.Name == null)
{
throw new Exception("prop null");
}
PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
if (pc == null)
{
throw new Exception("not found");
}
if (pc.Attributes.TryGetValue(adaptedProperty.Name, out object pcValue))
{
return pcValue;
}
return null;
}
public override bool IsGettable(PSAdaptedProperty adaptedProperty)
{
if (adaptedProperty == null)
{
throw new Exception("prop null");
}
PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
if (pc == null)
{
throw new Exception("not found");
}
if (pc.Attributes.ContainsKey(adaptedProperty.Name))
{
return true;
}
return false;
}
public override bool IsSettable(PSAdaptedProperty adaptedProperty)
{
return false;
}
public override void SetPropertyValue(PSAdaptedProperty adaptedProperty, object value)
{
throw new System.NotImplementedException();
}
}
}
** I have purposely not added any code for the Set* methods to reduce the code required here. If the above seems right, then I am sure I know what to do.
Has anyone done this before? Are there any very basic examples out there? Am I on the right path, or am I misunderstanding? Thanks in advance.
If anyone comes comes looking for this and was interested in doing something similar, then my question is actually more or less how it is done. I hope it is of use or interest to others working on binary modules.
One thing I did find were there were some additional properties that were passed through the GetProperty method that seemed to be from the PowerShell engine itself i.e. PSComputerName, so there was no need to throw an error here, just return a new PSAdaptedProperty with a null object.
public override PSAdaptedProperty GetProperty(object baseObject, string propertyName)
{
PropertyCollection pc = baseObject as PropertyCollection;
if (pc.Attributes.TryGetValue(propertyName, out object pcValue))
{
return new PSAdaptedProperty(propertyName, pcValue);
}
return new PSAdaptedProperty(propertyName, null);
}
You can then either load the Types data via your module manifest or in the console using Update-Typedata -PrependPath path_to_file\file_name.
All the properties in the dictionary are returned to give the appearance that they are full properties of the class.

Dynamically load dlls

I have following Main method. LocalCabelTV and LocalDishTV classes are in the main application program. The program works fine.
I want to keep LocalCabelTV and LocalDishTV in separate dll files. I wonder then how will I load those classes at runtime? I understand then we'll not use switch but for loop to look for all dll files that implements IVideoSource interface in a particular directory and load those...
Need to know how to dynamically load dlls and create objects and use their methods ?
foreach (string dll in Directory.GetFiles("C:\DLLs\*.dll"))
{
Assembly assemb = Assembly.LoadFrom(dll);
??
}
Following works fine:
static void Main(string[] args)
{
SmartTv myTv = new SmartTv();
Console.WriteLine("Select A source to get TV Guide and Play");
Console.WriteLine("1. Local Cable TV\n2. Local Dish TV");
ConsoleKeyInfo input = Console.ReadKey();
switch (input.KeyChar)
{
case '1':
myTv.VideoSource = new LocalCabelTv();
break;
case '2':
myTv.VideoSource = new LocalDishTv();
break;
}
Console.WriteLine();
myTv.ShowTvGuide();
myTv.PlayTV();
Console.ReadKey();
}
class SmartTv
{
IVideoSource currentVideoSource = null;
public IVideoSource VideoSource
{
get
{
return currentVideoSource;
}
set
{
currentVideoSource = value;
}
}
public void ShowTvGuide()
{
if (currentVideoSource != null)
{
Console.WriteLine(currentVideoSource.GetTvGuide());
}
else
{
Console.WriteLine("Please select a Video Source to get TV guide from");
}
}
public void PlayTV()
{
if (currentVideoSource != null)
{
Console.WriteLine(currentVideoSource.PlayVideo());
}
else
{
Console.WriteLine("Please select a Video Source to play");
}
}
class LocalCabelTv : IVideoSource
{
const string SOURCE_NAME = "Local Cabel TV";
string IVideoSource.GetTvGuide()
{
return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
}
string IVideoSource.PlayVideo()
{
return string.Format("Playing - {0}", SOURCE_NAME);
}
}
class LocalDishTv : IVideoSource
{
const string SOURCE_NAME = "Local DISH TV";
string IVideoSource.GetTvGuide()
{
return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
}
string IVideoSource.PlayVideo()
{
return string.Format("Playing - {0}", SOURCE_NAME);
}
}
To load this assembly at runtime and create an object:
Assembly MyDALL = Assembly.Load("DALL"); // DALL is name of my dll
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // LoadClass is my class
object obj = Activator.CreateInstance(Type.GetType("DALL.LoadClass, DALL", true));
For your dynamic Method you can also use Dynamic Method . Its faster than reflection (This method takes only 1/10th time needed by Activator.)
Here is a sample code for creating Object using Dynamic Method.
void CreateMethod(ConstructorInfo target)
{
DynamicMethod dynamic = new DynamicMethod(string.Empty,
typeof(object),
new Type[0],
target.DeclaringType);
methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}
Check out these link for more info: Load Assembly at runtime and create class instance
EDIT: As user #taffer mentioned the DynamicMethod.CreateDelegate is much more slower than reflection. So I would use this only if the created delegate is invoked hundreds or thousands of times. Using Activator with a cache is faster. Secondly, Activator is really fast for parameterless constructors, unless you instantiate so many types, which renders the inner small cache useless.
You need to load the DLLs with the desire classes and iterate over their types, than look for those that implement IVideoSource and activate them:
public static IEnumerable<IVideoSource> GetVideoSources(List<string> assemblyPathes)
{
IEnumerable<Assembly> yourAssembliesWithClasses = assemblyPathes.Select(x => Assembly.Load(x));
IEnumerable<Type> implementingTypes = yourAssembliesWithClasses
.GetTypes()
.Where(x => x.IsAssignableFrom(IVideoSource));
return implementingTypes.Select(x => Activator.CreateInstance(x));
}
Note that Activator.CreateInstance() requires the types to have an empty constructor, if they don't have one you can use, Type.GetUniGetUninitializedObject(Type type) from FormatterServices to initialize them.

How to check if something is an .net exception or the custom exception

Like in the question. I want to check if something on the collection of exceptions is my custom exception or is it the Exception class given by the .Net framework. Thnaks in advance for your help. \
Please note:
I don't know what is the class name of my custom exception it could be called exceptionA, exceptionB or for example xyzException
I have code like this:
public IEnumerable<Type> GetClassHierarchy(Type type)
{
if (type == null) yield break;
Type typeInHierarchy = type;
do
{
yield return typeInHierarchy;
typeInHierarchy = typeInHierarchy.BaseType;
}
while (typeInHierarchy != null && !typeInHierarchy.IsInterface);
}
public string GetException(System.Exception ex)
{
if (ex == null)
{
return null;
}
if (ex.InnerException == null)
{
return ex.Message;
}
var exceptionHerarchy = GetClassHierarchy(ex.GetType());
var isMyException = exceptionHerarchy.Any(t => t != typeof(System.Exception));
if (isMyException)
{
return string.Format("{0};{1}", ex.Message, GetException(ex.InnerException));
}
else
{
return GetException(ex.InnerException);
}
}
var isMyException = exceptionHerarchy.Any(t => t != typeof(System.Exception)); this is alays returning true because there is this type on the list probably
Very simple:
var t = myException.GetType().FullName;
bool isSystemException = (t.StartsWith("System."));
Exception types in the .NET Framework are all in System or one of its subnamespaces.
EDIT: To make this slightly prettier, create an extension function to the Exception class:
public static bool IsSystemException(this Exception exception)
{
return (exception.GetType().FullName.StartsWith("System."));
}
Double reconsider why do you want to do it. And then use one of the solutions below.
Better
Derive all custom exceptions from one base class exception provided by you and catch it in try-catch block.
Worse
Dynamically check some information about exception using Reflection, like its assembly:
ex.GetType().AssemblyQualifiedName
Make your Exception class extend from a custom base class.
class MyBaseEception : Exception
{
}
class MyCustomException : MyBaseException {}
try
{
}
catch (MyBaseException customException) {....}
catch (Exception e)
{
}
Although one wonders why you want to do this.
Heres my 2 pence...
try
{
}
catch (Exception e)
{
if (e.GetType().Assembly.GetName().Name != "My.Own.Namespace")
{
// this is a .net exception?
}
}
Why have custom exceptions if you're unsure when they would fire? IME, custom exceptions are typically used around business logic when you want to handle a specific case. Otherwise rely on the framework. In terms of the code, stack your custom exceptions first, then have a catch all in case the custom exception does not fire.
try
{
//do something
}
catch (MyCustomException ex)
{
//log, continue, throw, etc
}
catch (Exception e)
{
//log, continue, throw, etc
}

Instantiating windows form at runtime from database name C#

I am having trouble instantiating a form in c# whose name i retrieve from a database, i have eliminated namespaces completely just to be sure i am not getting the object name wrong but still every time the code runs, the object returns as null instead of being the appropriate form.
private static Object CreateObjectInstance(string strObjectName)
{
Object obj = null; // Temporary object
try
{
if (strObjectName.LastIndexOf(".") == -1) // If there is no '.' in the object name
strObjectName = Assembly.GetEntryAssembly().GetName().Name + "." + strObjectName;
obj = Assembly.GetEntryAssembly().CreateInstance(strObjectName);
}
catch (Exception ex)
{
clsAdmFunctions.RecordException(ex); // Record error to the database
MessageBox.Show("Error instantiating the object\n\nDescription : "+ex.Message, "Object Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
obj = null;
}
return obj;
}
public static Form CreateForm(string strFormName)
{
return (Form)CreateObjectInstance(strFormName);
}
The problem is with your idea that assembly name is a part of your class name. True you need access to your assembly, but ultimately a class name is just Namespace.Class name. If you provide your actual namespace along with the class, then it works. Change your method to this, perhaps:
private static T CreateInstance<T>(string fullyQualifiedClassName)
{
try
{
return (T)Activator.CreateInstance(Type.GetType(fullyQualifiedClassName));
}
catch (Exception ex)
{
clsAdmFunctions.RecordException(ex); // Record error to the database
MessageBox.Show("Error instantiating the object\n\nDescription : " + ex.Message, "Object Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return default(T);
}
}
In other words you need the namespace too if you're saving it in the database. Just save class.GetType() as such or class.GetType().ToString() after which you will see the namespace too saved. The reason is you can have classes with same name, namespace1.Person and namespace2.Person in the same assembly.
If you need to read all the namespaces in an assembly, you can do:
foreach(var type in Assembly.WhateverAssembly().GetTypes())
//print type.Namespace;
You're stuck if you dont know the exact namespace. May be you can assume it to be
var namespace = Assembly.WhateverAssembly().GetTypes()[0].Namespace;
You need to have namespaces for your classes, doing otherwise is against .NET's design. If you really really want to have no namespaces for your Forms, you just need to specify just the class name, exclude the assembly name. Just call:
CreateInstance<MyForm>("MyForm");
provided MyForm is global and the assembly is just the same. If forms are in different assembly, then load it first using Assembly.Load or Assembly.LoadFrom and then create instance.
Your key method CreateObjectInstance should work OK so I am guessing it is the parameter being passed in? In my example I've shown how to include full namespace and class name etc:
namespace Example.SubFolder
{
internal class frmAdmAbout
{
public string Name { get; set; }
}
}
namespace Example.ActualApp
{
using System;
using System.Reflection;
internal class Program
{
static void Main(string[] args)
{
var newItem = CreateObjectInstance("Example.SubFolder.frmAdmAbout");
if (newItem == null)
{
Console.WriteLine("Failed to create!");
}
else
{
Console.WriteLine("Successfully created!");
}
Console.ReadKey();
}
private static Object CreateObjectInstance(string strObjectName)
{
Object obj = null;
try
{
if (strObjectName.LastIndexOf(".") == -1)
strObjectName = Assembly.GetEntryAssembly().GetName().Name + "." + strObjectName;
obj = Assembly.GetEntryAssembly().CreateInstance(strObjectName);
}
catch (Exception ex)
{
Console.WriteLine("Error instantiating the object\n\nDescription : " + ex.Message);
obj = null;
}
return obj;
}
}
}

Multiple Implementation Attempts

I am developing a solution which will connect to a wide variety of servers to read data and perform operations. There are many variables which complicate reliable communications such as firewalls, stopped/failed services, authentication differences, and various software configurations. There are methods I can use to work around these issues, though at the time of execution it is not known which will prove successful.
My goal is to create an interface and implementations which can be used to perform operations. The first method call will be to the fastest implementation which works for the majority of devices followed by other calls which can deal with the issues listed earlier.
In a perfect world the process would be written to quickly identify which method would be successful, but in my tests that took as much processing time as simply catching an exception. While performance is always a consideration, in the end it is more important that the task completes successfully.
Below is an example I created which demonstrates a worst case scenario iterating over a list of implementations. While this works well for one method, it doesn't follow the DRY principle when used in 20 or more different operations. One possible solution is Unity and Interception but I found that the invoke method in the call handler uses a resolved implementation, not a list of possible implementations. Unless I am missing something, that doesn't appear to be an option. Also, I will need to follow this pattern for several interfaces, so it would be nice to create a generic handler which can iterate over a list of implementations.
Any advice on how to complete this task would be appreciated!
Interface
public interface IProcess
{
int ProcessItem(string workType);
}
Implementations
public class ProcessImplementation1 : IProcess
{
public int ProcessItem(string workType)
{
throw new TimeoutException("Took too long");
}
}
public class ProcessImplementation2 : IProcess
{
public int ProcessItem(string workType)
{
throw new Exception("Unexpected issue");
}
}
public class ProcessImplementation3 : IProcess
{
public int ProcessItem(string workType)
{
return 123;
}
}
Special Implementation loops through the other implementations until one succeeds without exception
public class ProcessImplementation : IProcess
{
public int ProcessItem(string workType)
{
List<IProcess> Implementations = new List<IProcess>();
Implementations.Add(new ProcessImplementation1());
Implementations.Add(new ProcessImplementation2());
Implementations.Add(new ProcessImplementation3());
int ProcessId = -1;
foreach (IProcess CurrentImplementation in Implementations)
{
Console.WriteLine("Attempt using {0} with workType '{1}'...",
CurrentImplementation.GetType().Name, workType);
try
{
ProcessId = CurrentImplementation.ProcessItem(workType);
break;
}
catch (Exception ex)
{
Console.WriteLine(" Failed: {0} - {1}.",
ex.GetType(), ex.Message);
}
Console.WriteLine();
if (ProcessId > -1)
{
Console.WriteLine(" Success: ProcessId {0}.", ProcessId);
}
else
{
Console.WriteLine("Failed!");
}
return ProcessId;
}
}
}
You could implement the processing operation as a generic extension method that you pass a method that does the processing for a single item:
public static int ProcessItems<T>(this IEnumerable<T> items, Func<T, int> processMethod)
{
foreach (var item in items)
{
try
{
return processMethod(item);
}
catch(Exception) {}
}
return -1;
}
Now you have factored out the actual type of the item and what method you use for processing. The only thing "fixed" is the result type of the generic method which is an integer.
For your current example you could call it like this then:
List<IProcess> implementations = ...;
int processResult = items.ProcessItems(x => x.ProcessItem(workType));
You could use the TryParse pattern in a second interface:
public interface IProcess
{
int ProcessItem(string workType);
}
internal interface ITryProcess
{
bool TryProcessItem(string workType, out int result);
}
public class ProcessImplementation1 : ITryProcess
{
public bool TryProcessItem(string workType, out int result)
{
result = -1;
return false;
}
}
public class ProcessImplementation : IProcess
{
public int ProcessItem(string workType)
{
var implementations = new List<ITryProcess>();
implementations.Add(new ProcessImplementation1());
// ...
int processId = -1;
foreach (ITryProcess implementation in implementations)
{
if (implementation.TryProcessItem(workType, out processId))
{
break;
}
}
if (processId < 0)
{
throw new InvalidOperationException("Unable to process.");
}
return processId;
}
}
Here's a solution similar to the one created by #BrokenGlass if you want something very simple and "generic."
public void TryAllImplementations<TService>(
IEnumerable<TService> services,
Action<TService> operation,
Action<Exception> exceptionHandler = null)
{
int dummy = 0;
TryAllImplementations(
services,
svc => { operation(svc); return dummy; },
exceptionHandler);
}
public TReturn TryAllImplementations<TService, TReturn>(
IEnumerable<TService> services,
Func<TService, TReturn> operation,
Action<Exception> exceptionHandler = null)
{
foreach (var svc in services)
{
try
{
return operation(svc);
}
catch (Exception ex)
{
if (exceptionHandler != null)
exceptionHandler(ex);
}
}
throw new ProgramException("All implementations have failed.");
}
Since I see a Unity tag, you could use ResolveAll<TService>() on your container using your service interface to get all implementations. Combining that with this code, you could do something like an extension method on IUnityContainer:
public static class UnityContainerExtensions
{
public static void TryAllImplementations<TService>(
this IUnityContainer container,
Action<TService> operation,
Action<Exception> exceptionHandler = null)
{
int dummy = 0;
container.TryAllImplementations<TService, int>(
svc => { operation(svc); return dummy; },
exceptionHandler);
}
public static TReturn TryAllImplementations<TService, TReturn>(
this IUnityContainer container,
Func<TService, TReturn> operation,
Action<Exception> exceptionHandler = null)
{
foreach (var svc in container.ResolveAll<TService>())
{
try
{
return operation(svc);
}
catch (Exception ex)
{
if (exceptionHandler != null)
exceptionHandler(ex);
}
}
throw new ProgramException("All implementations have failed.");
}
}
Here's how using it could work:
IUnityContainer container;
// ...
container.RegisterType<IProcess, ProcessImplementation1>();
container.RegisterType<IProcess, ProcessImplementation2>();
container.RegisterType<IProcess, ProcessImplementation3>();
// ...
container.TryAllImplementations(
(IProcess svc) => svc.ProcessItem(workType),
ex => Console.WriteLine(
" Failed: {0} - {1}.",
ex.GetType(),
ex.Message));

Categories

Resources