Last active
January 9, 2020 02:33
-
-
Save rdavisau/09d57eed64aa89ea6222637b84128bc9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DryIoCZeroWithFallbackContainerExtension : IContainerExtension<Container> | |
{ | |
public DryIoc.Container Fallback { get; set; } | |
public Container Instance { get; } | |
public DryIoCZeroWithFallbackContainerExtension() | |
{ | |
Instance = new Container(); | |
} | |
private object ResolveFromStaticContainer(Type type, string key = null) | |
{ | |
Debug.WriteLine($"Resolving {type} ({key}) from static container"); | |
return Instance.Resolve(type, key); | |
} | |
private object ResolveFromFallback(Type type, string key = null) | |
{ | |
Debug.WriteLine($"Resolving {type} ({key}) from fallback container"); | |
return Fallback.Resolve(type, key); | |
} | |
private object ResolveFromStaticContainerWithParameters(Type type, object[] parameters, string key = null) | |
{ | |
Debug.WriteLine($"Resolving {type} ({key}) from static container with parameters: {String.Join(", ", parameters)}"); | |
return Instance.Resolve(type, | |
key, | |
args: parameters); | |
} | |
private object ResolveFromFallbackWithParameters(Type type, object[] parameters, string key = null) | |
{ | |
Debug.WriteLine($"Resolving {type} ({key}) from fallback container with parameters: {String.Join(", ", parameters)}"); | |
return Fallback.Resolve(type, | |
parameters, | |
IfUnresolved.Throw, | |
null, | |
key | |
); | |
} | |
private bool IsRegisteredInFallBack(Type type, string key = null) | |
{ | |
return Fallback != null && Fallback.IsRegistered(type, key); | |
} | |
private bool IsRegisteredInStatic(Type type, string key = null) | |
{ | |
return Instance.IsRegistered(type, key); | |
} | |
public object Resolve(Type type) | |
{ | |
if (IsRegisteredInFallBack(type) || !IsRegisteredInStatic(type)) | |
return ResolveFromFallback(type); | |
return ResolveFromStaticContainer(type); | |
} | |
public object Resolve(Type type, string name) | |
{ | |
if (IsRegisteredInFallBack(type, name) || !IsRegisteredInStatic(type, name)) | |
return ResolveFromFallback(type, name); | |
return ResolveFromStaticContainer(type, name); | |
} | |
public object Resolve(Type type, params (Type Type, object Instance)[] parameters) | |
{ | |
var ps = parameters.Select(x => x.Instance).ToArray(); | |
if (IsRegisteredInFallBack(type) || !IsRegisteredInStatic(type)) | |
return ResolveFromFallbackWithParameters(type, ps); | |
return ResolveFromStaticContainerWithParameters(type, ps); | |
} | |
public object Resolve(Type type, string name, params (Type Type, object Instance)[] parameters) | |
{ | |
var ps = parameters.Select(x => x.Instance).ToArray(); | |
if (IsRegisteredInFallBack(type, name) || !IsRegisteredInStatic(type, name)) | |
return ResolveFromFallbackWithParameters(type, ps, name); | |
return ResolveFromStaticContainerWithParameters(type, ps, name); | |
} | |
private bool IsPlaceholder(Type type, string key = null) | |
{ | |
return true; | |
} | |
private void RegisterInstanceInFallback(Type type, object instance, string key = null) | |
{ | |
CreateFallbackIfRequired(); | |
Debug.WriteLine($"Registering {instance} as {type} ({key}) into fallback container"); | |
Fallback.RegisterInstance(type, instance, IfAlreadyRegistered.Replace, serviceKey: key); | |
} | |
private void RegisterInstanceInStaticPlaceholder(Type type, object instance, string key = null) | |
{ | |
Debug.WriteLine($"Registering {instance} as {type} ({key}) into static placeholder"); | |
Instance.RegisterDelegate(type, _ => instance, serviceKey: key); | |
} | |
private void RegisterTypeInFallback(Type from, Type to, IReuse reuse, string key = null) | |
{ | |
CreateFallbackIfRequired(); | |
Debug.WriteLine($"Registering {to} as {from} ({key}) with reuse {reuse} into fallback container"); | |
Fallback.Register(from, to, reuse: reuse, serviceKey: key); | |
} | |
private void CreateFallbackIfRequired() | |
{ | |
if (Fallback != null) | |
return; | |
Debug.WriteLine("Creating fallback container."); | |
Factory UnknownResolver(Request request) | |
{ | |
object FactoryDelegate(IResolverContext x) => Instance.Resolve(request.ServiceType, serviceKey: request.ServiceKey); | |
return new DelegateFactory(FactoryDelegate); | |
} | |
Fallback = new DryIoc.Container( | |
Rules.Default.WithAutoConcreteTypeResolution() | |
.With(Made.Of(FactoryMethod.ConstructorWithResolvableArguments)) | |
.WithoutThrowOnRegisteringDisposableTransient() | |
.WithFuncAndLazyWithoutRegistration() | |
.WithDefaultIfAlreadyRegistered(IfAlreadyRegistered.Replace) | |
.WithoutFastExpressionCompiler() | |
.WithUnknownServiceResolvers(UnknownResolver)); | |
} | |
public IContainerRegistry RegisterInstance(Type type, object instance) | |
{ | |
if (IsPlaceholder(type)) | |
RegisterInstanceInStaticPlaceholder(type, instance); | |
else | |
RegisterInstanceInFallback(type, instance); | |
return this; | |
} | |
public IContainerRegistry RegisterInstance(Type type, object instance, string name) | |
{ | |
if (IsPlaceholder(type, name)) | |
RegisterInstanceInStaticPlaceholder(type, instance); | |
else | |
RegisterInstanceInFallback(type, instance); | |
return this; | |
} | |
public IContainerRegistry RegisterSingleton(Type from, Type to) | |
{ | |
RegisterTypeInFallback(from, to, Reuse.Singleton); | |
return this; | |
} | |
public IContainerRegistry RegisterSingleton(Type from, Type to, string name) | |
{ | |
RegisterTypeInFallback(from, to, Reuse.Singleton, name); | |
return this; | |
} | |
public IContainerRegistry Register(Type from, Type to) | |
{ | |
RegisterTypeInFallback(from, to, Reuse.Transient); | |
return this; | |
} | |
public IContainerRegistry Register(Type from, Type to, string name) | |
{ | |
RegisterTypeInFallback(from, to, Reuse.Transient, name); | |
return this; | |
} | |
public bool IsRegistered(Type type) | |
{ | |
var ret = IsRegisteredInFallBack(type) || Instance.IsRegistered(type); | |
Debug.WriteLine($"Returning {ret} for IsRegistered({type})"); | |
return ret; | |
} | |
public bool IsRegistered(Type type, string name) | |
{ | |
var ret = IsRegisteredInFallBack(type, name) || Instance.IsRegistered(type, name); | |
Debug.WriteLine($"Returning {ret} for IsRegistered({type}, {name})"); | |
return ret; | |
} | |
public void FinalizeExtension() | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this isn't well tested so don't use it for anything important | |
// it definitely won't load non-nuget dependencies | |
public System.Reflection.Assembly LoadAssemblyWithDependencies(string assemblyPath) | |
{ | |
var coreLibPath = assemblyPath; | |
var nuget = System.Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\.nuget\packages"); | |
var dependencyContext = | |
Microsoft.Extensions.DependencyModel.DependencyContextLoader | |
.Default.Load(System.Reflection.Assembly.LoadFrom(coreLibPath)); | |
var libs = | |
dependencyContext | |
.RuntimeLibraries | |
.SelectMany(r => r.RuntimeAssemblyGroups.SelectMany(bb => bb.RuntimeFiles), | |
(r, bb) => new { r.Name, r.Version, bb.Path }) | |
.Where(r => !r.Name.StartsWith("runtime.")) | |
.Skip(1) // the dll comes first | |
.ToList(); | |
foreach (var l in libs) | |
{ | |
try | |
{ | |
System.Reflection.Assembly.LoadFrom(System.IO.Path.Combine(nuget, l.Name, l.Version, l.Path)); | |
} | |
catch (Exception ex) | |
{ | |
// break here to make sure nothing important is failing | |
// non-package assemblies will definitely fail | |
} | |
} | |
var coreLib = System.Reflection.Assembly.LoadFrom(coreLibPath); | |
return coreLib; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void RegisterPrismTypes(Assembly asm, IContainer container) | |
{ | |
var types = new Dictionary<Type, Type> | |
{ | |
[FindType("Prism.Navigation.INavigationService")] = FindType("Prism.Navigation.PageNavigationService"), | |
[FindType("Prism.Behaviors.IPageBehaviorFactory")] = FindType("Prism.Behaviors.PageBehaviorFactory"), | |
[FindType("Prism.Common.IApplicationProvider")] = FindType("Prism.Common.ApplicationProvider"), | |
[FindType("Prism.Logging.ILoggerFacade")] = FindType("Prism.Logging.EmptyLogger"), | |
[FindType("Prism.AppModel.IApplicationStore")] = FindType("Prism.AppModel.ApplicationStore"), | |
[FindType("Prism.Events.IEventAggregator")] = FindType("Prism.Events.EventAggregator"), | |
[FindType("Prism.Services.IPageDialogService")] = FindType("Prism.Services.PageDialogService"), | |
[FindType("Prism.Services.Dialogs.IDialogService")] = FindType("Prism.Services.Dialogs.DialogService"), | |
[FindType("Prism.Services.IDeviceService")] = FindType("Prism.Services.DeviceService"), | |
[FindType("Prism.Modularity.IModuleCatalog")] = FindType("Prism.Modularity.ModuleCatalog"), | |
[FindType("Prism.Modularity.IModuleManager")] = FindType("Prism.Modularity.ModuleManager"), | |
[FindType("Prism.Modularity.IModuleInitializer")] = FindType("Prism.Modularity.ModuleInitializer") | |
}; | |
foreach (var t in types) | |
container.Register(t.Key, t.Value); | |
// nav service needs to be registered with a service key too | |
container.Register( | |
FindType("Prism.Navigation.INavigationService"), | |
FindType("Prism.Navigation.PageNavigationService"), | |
serviceKey: "PageNavigationService"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void RegisterViews(Assembly asm, IContainer container) | |
{ | |
var pageTypes = GetTypesFromAssembly(asm, t => t.IsSubclassOf(typeof(BasePage))).ToArray(); | |
// register nav page | |
container.Register(typeof(object), FindType("Xamarin.Forms.NavigationPage"), serviceKey: "NavigationPage"); | |
// register all our pages and matching vm | |
// assumes matching vm exists, 1->1 relationship, ignores namespaces, etc. | |
// this might not be valid for you, in which case this will blow up | |
foreach(var pageType in pageTypes) | |
{ | |
var vmType = GetTypesFromAssembly(asm, t => t.Name == pageType.Name + "ViewModel").First(); | |
// register page type | |
container.Register(pageType); | |
// prism wants it as a named registration against object, so maybe the above is unneccessary | |
container.Register(typeof(object), pageType, serviceKey: pageType.Name); | |
// register the vm | |
container.Register(vmType); | |
// keep track of the pair of types so we can generate our "register pages" method later | |
PageTypes.Add(($"{pageType.Namespace}.{pageType.Name}", $"{vmType.Namespace}.{vmType.Name}")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment