Я пытаюсь получить доступ к моей MainPageViewModel непосредственно из моего XAML страницы определения:Доступ MainViewModel из XAML страницы при использовании Autofac и вводят услугу (ы)
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyApp"
mc:Ignorable="d"
Title="MyApp" Height="350" Width="650" ShowInTaskbar="True"
WindowState="Maximized"
DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}">
Мой локатор создан в моем app.xaml:
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</Application.Resources>
И мой ViewModelLocator определяется следующим образом:
public class ViewModelLocator
{
private static readonly IContainer Container;
static ViewModelLocator()
{
// load specific logger - Hardcoded for sample sake
string loggerAssembly = "Logger.Database.dll";
// register logger database by type i.e. ILogger
var builder = new ContainerBuilder();
Assembly assembly = Assembly.LoadFrom(loggerAssembly);
builder.RegisterAssemblyTypes(assembly).As<ILogger>();
// register MainViewModel and Inject ILogger
// Is this correct? Is this how you inject a service?
builder.RegisterType<MainViewModel>().As<ILogger>().InstancePerDependency();
Container = builder.Build();
}
public ILogger Logger => Container.Resolve<ILogger>();
// property to access MainViewModel in XAML
public MainViewModel MainViewModel => Container.Resolve<MainViewModel>();
}
Но когда я запускаю мое приложение, он генерирует ошибку из App.XAML в локаторе и пытается получить доступ к свойству MainViewModel, как определено выше. Ошибка я получаю:
Сообщение исключения:
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on
type 'MyCompany.Logger.Database.Logger' can be invoked with the
available services and parameters: Cannot resolve parameter
'System.String connectionString' of constructor 'Void .ctor(System.String)'.
Исключение StackTrace:
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance
(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
И мой MainPageViewModel определяется следующим образом:
Public class MainPageViewModel()
{
public MainViewModel(ILogger logger)
{
....
}
}
Любые идеи о том, как я могу это решить?
UPDATE 1:
Обратите внимание, что мое первоначальное определение:
builder.RegisterAssemblyTypes(assembly).As<ILogger>();
было, вероятно, хорошо, как и вся моя "КИ" сборка только реализовать интерфейс ILogger но я первоначально использовать AsImplementedInterfaces()
Я обновил свой код на основе предложений @HenkHolterman:
builder.RegisterType<MainViewModel>();
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
Но я не получаю следующее исключение:
None of the constructors found with 'Autofac.Core.Activators.Reflection.
DefaultConstructorFinder' on type 'MyCompany.Logger.Database.Logger' can be
invoked with the available services and parameters:
Cannot resolve parameter 'System.String connectionString' of constructor
'Void .ctor(System.String)'.
Теперь на основе последней части этого исключения, по-видимому, связано с параметром ConnectionString, и этот параметр был частью моей базы данных класса регистратора (MyCompany.Logger.Database.Logger
), поэтому я временно удалил его, чтобы проверить, что предложил @HenkHolterman, и теперь это работает, но у меня все еще есть проблема.
Мне нужно передать строку соединения, когда я использую регистратор базы данных. Мне нужно передать имя файла, когда я использую регистратор файлов и т. Д.
так как передать параметр конструктору журнала. Я пробовал:
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().
WithParameter("ConnectionString", connectionString);
, но он по-прежнему вызывает параметр меньше (т.е. Logger) в MyCompany.Logger.Database.Logger.
Если я добавлю параметр connectionString обратно в конструктор Logger, он отменяет исключение, упомянутое выше.
Я продолжу исследовать его завтра и обновит свой ответ, если найду что-нибудь, но если у кого-нибудь есть предложения, я бы очень благодарен за помощь.
Обновления 2
Как было отмечено @HenkHolterman, параметры чувствительны к регистру и должны соответствовать конвенциям, используемым в конструкторе.
Обратите внимание, что есть два способа передать параметры с помощью Autofac. При регистрации и при разрешении. Оба работают одинаково.
Таким образом, приведенный выше код, который генерируется сообщение об ошибке при передаче параметров должны быть определены как:
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().
WithParameter("connectionString", connectionString);
Возможно, вы должны использовать опцию лямбда-калькулятора. –
'.WithParameter (" ConnectionString ", connectionString)' - действительно ли параметр использует 'C', а не' c'? и connectionString должна быть константой (известной во время регистрации). –
@HenkHolterman, ты был прав. У меня был «C» вместо «c». – Thierry