void LaunchDiscover(IEnumerable <FileInfo> files) { _discoverCount--; if (_discoverCount == 0) { _currentVersion++; if (DiscoverBegin != null) { DiscoverBegin(this, EventArgs.Empty); } Merger merger = new Merger(this); AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation; AppDomain discoverDomain = AppDomain.CreateDomain("CKDiscovererDomain", null, ads); Runner.PluginDiscoverer runnerDiscoverer = (Runner.PluginDiscoverer)discoverDomain.CreateInstanceAndUnwrap( Assembly.GetAssembly(typeof(Runner.PluginDiscoverer)).FullName, "CK.Plugin.Discoverer.Runner.PluginDiscoverer"); merger.Merge(runnerDiscoverer.Discover(files)); AppDomain.Unload(discoverDomain); if (DiscoverDone != null) { DiscoverDone(this, new DiscoverDoneEventArgs(merger.NewAssemblies, merger.ChangedAssemblies, merger.DeletedAssemblies, merger.NewPlugins, merger.ChangedPlugins, merger.DeletedPlugins, merger.NewEditors, merger.ChangedEditors, merger.DeletedEditors, merger.NewServices, merger.ChangedServices, merger.DeletedServices, merger.NewOldPlugins, merger.DeletedOldPlugins, merger.NewMissingAssemblies, merger.DeletedMissingAssemblies)); } } }
internal ServiceInfo(PluginAssemblyInfo a, Type t) { _assembly = a; _assemblyQualifiedName = t.AssemblyQualifiedName; _serviceFullName = t.FullName; _isDynamicService = PluginDiscoverer.IsIDynamicService(t); _impl = new List <PluginInfo>(); _eventsInfoCollection = new List <SimpleEventInfo>(); _methodsInfoCollection = new List <SimpleMethodInfo>(); _propertiesInfoCollection = new List <SimplePropertyInfo>(); }
/// <summary> /// Read all Type in the assembly. /// </summary> /// <param name="RegisterServiceInfo">Will be called for each discovered service interface.</param> /// <param name="RegisterUseServiceInfo">Will be called for each discovered service reference.</param> internal void ReadAllTypes(Func <PluginAssemblyInfo, Type, ServiceInfo> RegisterServiceInfo, Func <Type, bool, ServiceRefInfo> RegisterUseServiceInfo) { Debug.Assert(_assembly != null); List <PluginInfo> plug = new List <PluginInfo>(); List <ServiceInfo> serv = new List <ServiceInfo>(); // We loop on each type we can find into the assembly. foreach (Type t in _assembly.GetExportedTypes()) { // If it implements the IPlugin interface. if (t.GetInterface(typeof(IPlugin).FullName) != null) { PluginInfo info = null; try { // And if it have the PluginAttribute. foreach (CustomAttributeData attr in CustomAttributeData.GetCustomAttributes(t)) { if (attr.Constructor.DeclaringType.FullName == "CK.Plugin.PluginAttribute") { info = new PluginInfo(attr) { AssemblyInfo = this, PluginFullName = t.FullName }; break; } } if (info == null) { info = new PluginInfo("Unable to find Plugin attribute."); } } catch (Exception ex) { info = new PluginInfo(ex.Message); } Debug.Assert(info != null, "At this point, info can not be null."); if (info.ErrorMessage == null) // If there are no errors { // Discover implemented Services. try { ServiceInfo result = null; foreach (Type i in t.GetInterfaces()) { if (i.IsGenericType && i.GetGenericTypeDefinition().AssemblyQualifiedName == typeof(IService <>).AssemblyQualifiedName) { // Implementing the IService marker interface is an error. info.AddErrorLine(R.PluginImplementIService); break; } if (PluginDiscoverer.IsIDynamicService(i)) { if (result != null) { // Only one IService can be implemented at a time. info.AddErrorLine(R.MultipleServiceImplementation); result = null; break; } else { // We are on a IDynamicService, not a IService<>. ServiceRefInfo r = RegisterUseServiceInfo(i, false); Debug.Assert(!r.IsIServiceWrapped && !r.IsUnknownGenericInterface, "We tested this above."); Debug.Assert(r.Reference != null, "Since we are on a IDynamicService (tested above)."); result = r.Reference; } } } if (result != null) { result.Implementations.Add(info); } info.Service = result; } catch (Exception ex) { info.AddErrorLine(ex.Message); } // Discover referenced Services and edited configuration. try { // Process public properties to discover service references and edited configurations. List <ServiceReferenceInfo> refs = info.ServiceReferences = new List <ServiceReferenceInfo>(); foreach (PropertyInfo p in t.GetProperties()) { try { bool serviceRefHandled = false; bool editedConfHandled = false; foreach (CustomAttributeData attr in CustomAttributeData.GetCustomAttributes(p)) { #region The [DynamicServiceAttribute] has the priority. if (attr.Constructor.DeclaringType.FullName == typeof(DynamicServiceAttribute).FullName) { serviceRefHandled = true; ServiceReferenceInfo dep; // Since we are in a [DynamicServiceAttribute], we expect a IDynamicService and reject any other generic interface than IService<>, // but we accept other (not IDynamicService) interfaces in order to capture the reference (hence the registerOnlyIDynamicService = false parameter below). ServiceRefInfo r = RegisterUseServiceInfo(p.PropertyType, false); dep = new ServiceReferenceInfo(info, p.Name, r, attr.NamedArguments); Debug.Assert((r.Reference == null) == (r.IsUnknownGenericInterface)); // Handle errors. if (!p.CanWrite) { dep.AddErrorLine(R.NotWritableServiceType); } if (r.IsUnknownGenericInterface) { dep.AddErrorLine(R.GenericServiceOtherThanIServiceNotSupported); } if (!r.IsIDynamicService) { Debug.Assert(!PluginDiscoverer.IsIDynamicService(p.PropertyType)); dep.AddErrorLine(R.DynamicServiceAttributeRequiresIDynamicService); } refs.Add(dep); break; } #endregion #region The [RequiredService] can reference non IDynamicService service. if (attr.Constructor.DeclaringType.FullName == typeof(RequiredServiceAttribute).FullName) { RunningRequirement req = RunningRequirement.MustExistAndRun; // Since [RequiredServiceAttribute] can have Requires = false parameter. if (attr.NamedArguments.Count == 1 && (bool)attr.NamedArguments[0].TypedValue.Value == false) { // If Requires == false, we consider it to be optional. req = RunningRequirement.Optional; } serviceRefHandled = true; ServiceRefInfo r = RegisterUseServiceInfo(p.PropertyType, false); ServiceReferenceInfo dep = new ServiceReferenceInfo(info, p.Name, r, req); if (!p.CanWrite) { dep.AddErrorLine(R.NotWritableServiceType); } else if (r.IsUnknownGenericInterface) { dep.AddErrorLine(R.GenericServiceOtherThanIServiceNotSupported); } refs.Add(dep); break; } #endregion #region The [EditedConfiguration] comes last... if (attr.Constructor.DeclaringType.FullName == typeof(ConfigurationAccessorAttribute).FullName) { editedConfHandled = true; try { info.EditorsInfo.Add(new PluginConfigAccessorInfo(attr, info, false) { ConfigurationPropertyName = p.Name }); } catch (Exception ex) { info.AddErrorLine(ex.Message); } } #endregion } // If the property has not been handled through its attributes, we detect potential services references: any public read/write // property that expose a IDynamicService or a IService<> is transformed into an optional ServiceReferenceInfo. if (!serviceRefHandled && !editedConfHandled && p.CanWrite && p.CanRead) { if (p.PropertyType.IsInterface) { if (p.PropertyType.Name == "IPluginConfigAccessor") { info.EditorsInfo.Add(new PluginConfigAccessorInfo(null, info, true) { ConfigurationPropertyName = p.Name }); } else { // Here we only register services if they are IDynamicService. ServiceRefInfo r = RegisterUseServiceInfo(p.PropertyType, true); if (r.Reference != null) { Debug.Assert(r.IsIDynamicService); ServiceReferenceInfo dep; dep = new ServiceReferenceInfo(info, p.Name, r, RunningRequirement.Optional); } } } } } catch (Exception ex) { info.AddErrorLine(ex.Message); } } } catch (Exception ex) { info.AddErrorLine(ex.Message); } plug.Add(info); } } // Discover just a service else if (t.IsInterface && PluginDiscoverer.IsIDynamicService(t)) { ServiceInfo service = RegisterServiceInfo(this, t); service.AssemblyQualifiedName = t.AssemblyQualifiedName; // Get the Events that the service exposes foreach (EventInfo e in CK.Reflection.ReflectionHelper.GetFlattenEvents(t)) { service.EventsInfoCollection.Add(new SimpleEventInfo(e.Name)); } // Get the Properties that the service exposes foreach (PropertyInfo p in CK.Reflection.ReflectionHelper.GetFlattenProperties(t)) { service.PropertiesInfoCollection.Add(new SimplePropertyInfo(p.Name, p.PropertyType.ToString())); } // Get the Methods that the service exposes foreach (MethodInfo m in CK.Reflection.ReflectionHelper.GetFlattenMethods(t)) { if (!m.IsSpecialName) { Type tR = m.ReturnType; SimpleMethodInfo s = new SimpleMethodInfo(m.Name, tR.ToString()); foreach (ParameterInfo p in m.GetParameters()) { s.Parameters.Add(new SimpleParameterInfo(p.Name, p.ParameterType.ToString())); } service.MethodsInfoCollection.Add(s); } } serv.Add(service); } } // Fills _plugins and _services collections (properties Plugin and Services of this PluginAssemblyInfo) // with local collections (Plugin = _plugins = plug & Services = _services = serv). _plugins = plug; _services = serv; }