internal ServiceReferenceInfo(PluginInfo owner, string propertyName, ServiceRefInfo reference, RunningRequirement requires) { Owner = owner; _propertyName = propertyName; _reference = reference.Reference; _isIServiceWrapped = reference.IsIServiceWrapped; _requirements = requires; }
internal ServiceReferenceInfo(PluginInfo owner, string propertyName, ServiceRefInfo reference, IList <CustomAttributeNamedArgument> attrArgs) : this(owner, propertyName, reference, RunningRequirement.Optional) { foreach (CustomAttributeNamedArgument a in attrArgs) { if (a.MemberInfo.Name == "Requires") { _requirements = (RunningRequirement)a.TypedValue.Value; } } }
/// <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; }