private async Task InitRouteTable() { var apps = AdditionalAssemblies == null ? new[] { Assembly.GetEntryAssembly() } : new[] { Assembly.GetEntryAssembly() }.Concat(AdditionalAssemblies).Where(a => a != null); var componentTypes = apps.SelectMany(a => a !.ExportedTypes.Where(t => typeof(IComponent).IsAssignableFrom(t))); foreach (var componentType in componentTypes) { var routeAttributes = componentType.GetCustomAttributes <RouteAttribute>(false); foreach (var template in routeAttributes.Select(t => t.Template)) { RouteTable.TryAdd(template.Trim('/'), componentType); } } Navigator.LocationChanged += Navigator_LocationChanged; await InvokeAsync(() => AddTabByUrl(Navigator.ToBaseRelativePath(Navigator.Uri))); }
/// <summary> /// Compose an object: all properties of the object decorated with an /// Import or ImportMany attribute, will be instantiated accordingly. /// Alternatively, if a Type if provided, it will be scanned for public /// static properties marked for import. /// </summary> /// <param name="root">The object to compose, or a type if composing must be done for static properties of a class</param> public static void Compose(object root) { if (root == null) { return; } PropertyInfo[] infos; object obj; if (root is Type rootType) { obj = null; infos = rootType.GetProperties( BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); } else { obj = root; infos = root.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); } foreach (var prop in infos) { var browsable = prop.GetCustomAttribute <BrowsableAttribute>(); if (browsable != null && !browsable.Browsable) { continue; } var attribs = prop.GetCustomAttributes().ToArray(); if (attribs.Length == 0 && !prop.PropertyType.IsValueType && prop.PropertyType != typeof(string)) { // Recursive composition is only allowed for generic types for now if (prop.PropertyType.IsGenericType) { Compose(prop.GetValue(root)); } } foreach (var attrib in attribs) { ExportedType[] exportedTypes; switch (attrib) { case ImportAttribute ia: exportedTypes = ExportedTypes.Where(x => x.ExposedType == prop.PropertyType).ToArray(); if (exportedTypes.Length == 0) { throw new Exception($"No exported type matched imported type {prop.PropertyType.FullName}"); } if (exportedTypes.Length > 1) { throw new AmbiguousMatchException($"More than one exported types match imported type {prop.PropertyType.FullName}"); } object instance; switch (exportedTypes[0].Many) { case true: instance = CreateAndCompose(exportedTypes[0].ActualType); break; default: instance = GetSingleton(exportedTypes[0].ActualType); break; } prop.SetValue(obj, instance); break; case ImportManyAttribute ima: if (!prop.PropertyType.IsGenericType) { throw new Exception("ImportMany can only be applied on generic types"); } exportedTypes = ExportedTypes.Where(x => x.ExposedType == ima.ImportedType).ToArray(); var constructedListType = typeof(List <>).MakeGenericType(ima.ImportedType); var instanceList = (IList)Activator.CreateInstance(constructedListType); foreach (var t in exportedTypes) { var listItem = instance = CreateAndCompose(t.ActualType); instanceList.Add(listItem); } try { prop.SetValue(obj, instanceList); } catch (ArgumentException) { throw new Exception("No setter found for property " + prop.Name + ", or wrong type"); } break; } } } }