简单的注入器WPF无效的uri

时间:2015-06-08 22:03:56

标签: wpf simple-injector mahapps.metro

我在尝试验证容器时遇到错误。

  

配置无效。为类型创建实例   SettingModel失败。已注册的类型为SettingModel的委托   抛出一个例外。无效的URI:指定的端口无效。

它似乎是由ThemeManager引起的,它属于mahapps.metro dll我似乎无法与Simple Injector很好地配合。

public SettingModel()
{
    ThemeColor = ThemeManager.AppThemes.Select(t => t.Name).ToList();
    AccentColor = ThemeManager.Accents.Select(a => a.Name).ToList();

    var currentSetting = ThemeManager.DetectAppStyle(Application.Current);
    CurrentTheme = currentSetting.Item1.Name;
    CurrentAccent = currentSetting.Item2.Name;
}

我慢慢地删除了东西,它已经到了我使用主题管理器的每个地方它都打破了。所以我开始取出碎片,直到我在编译时不断得到xamlparseexception,这很奇怪,因为我的代码在放入简单的进样器之前就已经编译了。

我遵循WPF集成教程,除非它已过时。我真的想尝试简单的喷油器,但它没有很好地集成。

更新:完全例外

    System.InvalidOperationException was unhandled
      HResult=-2146233079
      Message=The configuration is invalid. Creating the instance for type MainWindow failed. The registered delegate for type MainWindow threw an exception. Invalid URI: Invalid port specified.
      Source=SimpleInjector
      StackTrace:
           at SimpleInjector.InstanceProducer.VerifyInstanceCreation()
           at SimpleInjector.Container.VerifyInstanceCreation(InstanceProducer[] producersToVerify)
           at SimpleInjector.Container.VerifyThatAllRootObjectsCanBeCreated()
           at SimpleInjector.Container.VerifyInternal()
           at SimpleInjector.Container.Verify(VerificationOption option)
           at SimpleInjector.Container.Verify()
           at Program.Bootstrap() in c:\Users\Work\Documents\Visual Studio 2012\Projects\AzurePeek\AzurePeek\Program.cs:line 35
           at Program.Main() in c:\Users\Work\Documents\Visual Studio 2012\Projects\AzurePeek\AzurePeek\Program.cs:line 14
           at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException: SimpleInjector.ActivationException
           HResult=-2146233088
           Message=The registered delegate for type MainWindow threw an exception. Invalid URI: Invalid port specified.
           Source=SimpleInjector
           StackTrace:
                at SimpleInjector.InstanceProducer.GetInstance()
                at SimpleInjector.InstanceProducer.VerifyInstanceCreation()
           InnerException: System.UriFormatException
                HResult=-2146233033
                Message=Invalid URI: Invalid port specified.
                Source=System
                StackTrace:
                     at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
                     at System.Uri..ctor(String uriString)
                     at MahApps.Metro.ThemeManager.get_AppThemes()
                     at AzurePeek.M

odel.SettingModel..ctor() in c:\Users\Work\Documents\Visual Studio 2012\Projects\AzurePeek\AzurePeek\Model\SettingModel.cs:line 24
                 at lambda_method(Closure )
                 at SimpleInjector.InstanceProducer.GetInstance()
            InnerException: 

1 个答案:

答案 0 :(得分:4)

<强>更新

与@ punker76(MahApps.Metro库的合作者之一)讨论后,我们得出结论,发生此异常是因为您在WPF应用程序范围之外运行该代码。很可能是因为您在单元测试中测试了配置。

你可以在这做两件事。您需要欺骗测试套件以将其作为WPF应用程序运行,或者您必须将MyApps的代码移出SettingModel的构造函数。

正如@ punker76所讨论的那样,在启动WPF应用程序时,对new FrameworkElement()的调用会以某种方式确保内部UriParser能够解析pack:// uris(谈论奇怪隐藏的丑陋可怕依赖关系)。

另一个选择是我的偏好,就是制作constructor's simple and resilient to failure。这意味着任何与构建对象图无关的代码都应该移出构造函数,并且应该在运行时完成。

有很多方法可以做到这一点,但一种简单的方法是通过推迟SettingsModel属性的初始化或推迟创建SettingsModel本身,因为它没有看起来像是一个应该由你的DI容器维护的服务。

通过引入一个允许在运行时访问设置的抽象来推迟创建SettingsModel

public interface ISettingsProvider {
    SettingsModel CurrentSettings { get; }
}

通过以下实施:

public class SettingsProvider : ISettingsProvider {
    private readonly Lazy<SettingsModel> model = new Lazy<SettingsModel>(
        () => new SettingsModel());

    public SettingsModel CurrentSettings {
        get { return this.model.Value; }
    }
}

这可以注册如下:

container.RegisterSingle<ISettingsProvider>(new SettingsProvider());

原始回答

问题不太可能由Simple Injector引起。 Simple Injector的Verify()方法没有什么特别之处。如果您将Verify()的来电替换为new SettingModel();,则很可能会看到相同的异常。

事实上,如果你查看MahApps.Metro.ThemeManager.AppThemes属性的the source code,你会看到以下代码:

var themes = new[] { "BaseLight", "BaseDark" };

_appThemes = new List<AppTheme>(themes.Length);

foreach (var color in themes)
{
    var appTheme = new AppTheme(color, new Uri(string.Format("pack://application:,,,/MahApps.Metro;component/Styles/Accents/{0}.xaml", color)));

    _appThemes.Add(appTheme);
}

return _appThemes;

如果查看提供给Uri构造函数的url,您就可以理解为什么它会抛出“无效的URI:指定的无效端口”异常。如果在控制台应用程序中运行以下代码,则会出现相同的错误:

new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml");

所以我必须得出结论,MahApps.Metro.ThemeManager.AppThemes属性中存在导致此问题的错误。我想知道你以前是如何设法让这个工作的,因为我没有办法解决这个bug。您是否曾在介绍Simple Injector的同时升级到较新版本的MahApps.Metro?