Today, I am going to share a sophisticated composition provider which can be used in any enterprise application with MEF, and will handle all complication involved with different object creations.
Lets start with a definition of ICompositionProvider interface, it defines contract for a composition provider. A sophisticated composition provider should atleast following combination of methods and events.
Lets start with a definition of ICompositionProvider interface, it defines contract for a composition provider. A sophisticated composition provider should atleast following combination of methods and events.
public interface ICompositionProvider { IEnumerable<Lazy<T>> GetExports<T>(string contractName); IEnumerable<Lazy<T>> GetExports<T>(); IEnumerable<Lazy<T,TMetadata>> GetExports<T,TMetadata>(); IEnumerable<Lazy<T>> GetExports<T>(string contractName, bool enableWildCards); IEnumerable<T> GetExportedValues<T>(); IEnumerable<T> GetExportedValues<T>(string contractName); IEnumerable<T> GetExportedValues<T>(string contractName, bool enableWildCards); IEnumerable<T> GetEntitledExportedValues<T>(string contractName, bool enableWildCards); Lazy<T> GetExport<T>(string contractName); Lazy<T> GetExport<T>(); void SatisfyImports(object attributedPart); void Compose(object attributedPart); event EventHandler FullyComposed; event EventHandler CompositionFailed; }
Lets look at a CompositionProvider class, CompositionProvider class implementation looks like
public class CompositionProvider : ICompositionProvider { #region Private constants private const string CLASS_NAME = "CompositionProvider."; private const int MAX_TICKS = 100; private const string ENTITLEMENT_ASSEMBLY_NAME = "EntitlementModule.dll"; private const string INFRASTRUCTURE_ASSEMBLY_NAME = "Infrastructure.dll"; private const string AUTHENTICATION_ASSEMBLY_NAME = "AuthenticationModule.dll"; private const string FAILED_COMPOSITION_MESSAGE = "Failed to compose part {0}"; #endregion #region Variables public static CompositionProvider _Singleton; private readonly AggregateCatalog _aggergate = new AggregateCatalog(); internal CompositionContainer Container { get; private set; } public event EventHandler FullyComposed; public event EventHandler CompositionFailed; #endregion #region Static Properies /// <summary> /// It indicates current instance. /// </summary> internal static CompositionProvider Singleton { get { return _Singleton; } } #endregion #region Static Constructor /// <summary> /// Its a static constructor for CompositionProvider class. /// </summary> static CompositionProvider() { try { _Singleton = new CompositionProvider(); } catch (Exception e) { ErrorHandler.HandleError(e, ErrorTypes.CriticalError); } } #endregion #region Constructor /// <summary> /// Its a constructor for CompositionProvider class. /// </summary> public CompositionProvider() { _aggergate.Catalogs.Add(new AssemblyCatalog(typeof(CompositionProvider).Assembly)); Container = new CompositionContainer(_aggergate); Compose(this); } #endregion #region Methods public static void Start() { } /// <summary> /// It returns a lazy collection of passed type. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public IEnumerable<T> GetExportedValues<T>() { IEnumerable<T> value = GetExportedValues<T>(null, true); return value; } /// <summary> /// It returns a collection of passed contract name. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <returns></returns> public IEnumerable<T> GetExportedValues<T>(string contractName) { IEnumerable<T> value = GetExportedValues<T>(contractName, false); return value; } /// <summary> /// It returns a collection of passed contract name with wild cards. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <param name="enableWildCards"></param> /// <returns></returns> public IEnumerable<T> GetExportedValues<T>(string contractName, bool enableWildCards) { var value = new List<T>(); try { if (contractName == null) { value = Container.GetExportedValues<T>().ToList(); } else { if (enableWildCards) { Container.GetExportedValues<T>(contractName).ToList().ForEach(e => value.Add(e)); Container.GetExportedValues<T>(SystemConstants.SYSTEM_WILDCARD).ToList().ForEach( e => value.Add(e)); } else { value = Container.GetExportedValues<T>(contractName).ToList(); } } } catch (ImportCardinalityMismatchException importCardinalityMismatchException) { ErrorHandler.HandleError(importCardinalityMismatchException, ErrorTypes.CriticalError); } catch (CompositionException compositionException) { ErrorHandler.HandleError(compositionException, ErrorTypes.CriticalError); }
return value; } /// <summary> /// It returns a collection of passed contract name with wildcards. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <param name="enableWildCards"></param> /// <returns></returns> public IEnumerable<Lazy<T>> GetExports<T>(string contractName, bool enableWildCards) { FrontEndTracing.Singleton.LogEntry(CLASS_NAME + " GetExports<T>(string contractName, bool enableWildCards)"); List<Lazy<T>> value = default(List<Lazy<T>>); try { if (contractName == null) { value = Container.GetExports<T>().ToList(); } else { if (enableWildCards) { Container.GetExports<T>(contractName).ToList().ForEach(e => value.Add(e)); Container.GetExports<T>(SystemConstants.SYSTEM_WILDCARD).ToList().ForEach(e => value.Add(e)); } else { value = Container.GetExports<T>(contractName).ToList(); } } } catch (ImportCardinalityMismatchException e) { ErrorHandler.HandleError(e, ErrorTypes.CriticalError); } return value; } /// <summary> /// this will work with the entitlements provider to return a list of values for the type provided /// using an entitlement attribute check for each value returned /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <param name="enableWildCards"></param> /// <returns></returns> public IEnumerable<T> GetEntitledExportedValues<T>(string contractName, bool enableWildCards) { var itemsToReturn = new List<T>(); if (EntitlementProvider == null) { throw new NullReferenceException("The EntitlementsProvider is null so this can't work"); }
List<T> items = GetExportedValues<T>(contractName, enableWildCards).ToList(); IEnumerable<Type> types = items.Select(v => v.GetType()); foreach (T item in items) { object[] attributes = item.GetType().GetCustomAttributes(typeof (RequiresEntitlementAttribute), true); IEnumerable<RequiresEntitlementAttribute> requiresEntitlementAttributes = attributes.Select(a => a as RequiresEntitlementAttribute); itemsToReturn.Add(item); } return itemsToReturn; } /// <summary> /// It returns lazy collection of passed contract name. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <returns></returns> public IEnumerable<Lazy<T>> GetExports<T>(string contractName) { IEnumerable<Lazy<T>> value = GetExports<T>(contractName, false); return value; } /// <summary> /// It returns a object of passed type. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public IEnumerable<Lazy<T>> GetExports<T>() { IEnumerable<Lazy<T>> value = GetExports<T>(null, true); return value; } /// <summary> /// It returns a object of passed contract name. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contractName"></param> /// <returns></returns> public Lazy<T> GetExport<T>(string contractName) { Lazy<T> value = default(Lazy<T>); try { value = Container.GetExport<T>(contractName); } catch (ImportCardinalityMismatchException e) { ErrorHandler.HandleError(e, ErrorTypes.CriticalError); } return value; } /// <summary> /// It returns an object of passed type. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public Lazy<T> GetExport<T>() { Lazy<T> value = default(Lazy<T>); try { value = Container.GetExport<T>(); } catch (ImportCardinalityMismatchException e) { ErrorHandler.HandleError(e, ErrorTypes.CriticalError); } return value; } public IEnumerable<Lazy<T,TMetadata>> GetExports<T,TMetadata>() { return this.Container.GetExports<T, TMetadata>(); } /// <summary> /// It composes passed object. /// </summary> /// <param name="attributedPart"></param> public void Compose(object attributedPart) { if (attributedPart != null) { try { var batch = new CompositionBatch(); batch.AddPart(attributedPart); Container.Compose(batch); } catch (CompositionException compositionException) { ErrorHandelr.HandeError(compositionException); } } } /// <summary> /// This method is called when imports are satisfied. /// </summary> /// <param name="attributedPart"></param> public void SatisfyImports(object attributedPart) { if (attributedPart != null) { try { var batch = new CompositionBatch(); batch.AddPart(attributedPart); Container.SatisfyImportsOnce(batch); } catch (CompositionException compositionException) { ErrorHandler.HandleError(compositionException, ErrorTypes.CriticalError); } } } /// <summary> /// It authenticate current user. /// </summary> public void Authenticate() { Assembly infraAssm = Assembly.LoadFrom(Constants.CompositionPath + INFRASTRUCTURE_ASSEMBLY_NAME); if (infraAssm != null) { _aggergate.Catalogs.Add(new AssemblyCatalog(infraAssm)); } Assembly authAssm = Assembly.LoadFrom(Constants.CompositionPath + AUTHENTICATION_ASSEMBLY_NAME); if (authAssm != null) { _aggergate.Catalogs.Add(new AssemblyCatalog(authAssm)); LoginManager.LoginCompleted += OnLoginCompleted; LoginManager.Login(); } else { MessageBox.Show("Can't find the Authentication Module"); SendFail(); } } /// <summary> /// It sends fail method for logging. /// </summary> private void SendFail() { if (CompositionFailed != null) { CompositionFailed(this, EventArgs.Empty); } } public void OnLoginCompleted(object sender, LoginCompletedEventArgs e) { if (e.Message == "Cancel") { SendFail(); } else if (e.ClientInformation.IsAuthenticated) { Current.SetClientContext(e.ClientInformation); Entitle(); } } /// <summary> /// It calls entitlement provider for required keys. /// </summary> public void Entitle() { Assembly entitleAssm = Assembly.LoadFrom(Constants.CompositionPath + ENTITLEMENT_ASSEMBLY_NAME); if (entitleAssm != null) { _aggergate.Catalogs.Add(new AssemblyCatalog(entitleAssm)); EntitlementProvider.EntitlementsLoaded += OnEntitlementsLoaded; EntitlementProvider.GetEntitlements(); if (XamlUtility.IsInDesignMode()) return; } else { MessageBox.Show("Can't find the Entitlements Module"); SendFail(); } } /// <summary> /// Its called when entitlements are satisfied. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> internal void OnEntitlementsLoaded(object sender, EventArgs e) { //this._HasEntitlements = true; List<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); _aggergate.Catalogs.Clear(); var directoryDlls = new DirectoryCatalog(Constants.CompositionPath, "*.dll"); var directoryExes = new DirectoryCatalog(Constants.CompositionPath, "*.exe"); foreach (string loadedFile in directoryDlls.LoadedFiles) { Assembly assm = Assembly.LoadFrom(loadedFile); assemblies.Remove(assm); _aggergate.Catalogs.Add(new AssemblyCatalog(assm)); } foreach (string loadedFile in directoryExes.LoadedFiles) { Assembly assm = Assembly.LoadFrom(loadedFile); assemblies.Remove(assm); _aggergate.Catalogs.Add(new AssemblyCatalog(assm)); } assemblies.ForEach(a => _aggergate.Catalogs.Add(new AssemblyCatalog(a))); if (FullyComposed == null) { SendFail(); return; } FullyComposed(this, EventArgs.Empty); } #endregion }
No comments:
Post a Comment