I´m using Autofac in my WPF application for dependency injection and can´t resolve this problem.
I have created this abstract class ListItemViewModelBase from which two classes PasswordItemViewModel and CardItemViewModel inherits.
ListItemViewModelBase.cs
public abstract class ListItemViewModelBase
{
protected readonly IMessenger _messenger;
public string Id { get; }
public string Name { get; }
public string Notes { get; }
protected ListItemViewModelBase(IMessenger messenger, string id, string name, string notes)
{
_messenger = messenger;
Id = id;
Name = name;
Notes = notes;
}
public abstract void SeeDetails();
}
PasswordItemViewModel.cs
public partial class PasswordItemViewModel : ListItemViewModelBase
{
public string UserName { get; }
public string Password { get; }
public string Website { get; }
public PasswordItemViewModel(IMessenger messenger, string id, string name, string userName, string password, string website, string notes) : base(messenger, id, name, notes)
{
UserName = userName;
Password = password;
Website = website;
}
[RelayCommand]
public override void SeeDetails()
{
_messenger.Send(new PasswordDetailMessage(this));
}
}
CardItemViewModel.cs
public partial class CardItemViewModel : ListItemViewModelBase
{
public string CardNumber { get; }
public int ExpMonth { get; }
public int ExpYear { get; }
public CardItemViewModel(IMessenger messenger, string id, string name, string cardNumber, int expMonth, int expYear, string notes) : base(messenger, id, name, notes)
{
CardNumber = cardNumber;
ExpMonth = expMonth;
ExpYear = expYear;
}
[RelayCommand]
public override void SeeDetails()
{
_messenger.Send(new CardDetailMessage(this));
}
}
My App.xaml.cs where the Autofac is configured looks like this:
App.xaml.cs
public partial class App : Application
{
public static IServiceProvider ServiceProvider { get; private set; }
[STAThread]
public static void Main(string[] args)
{
using IHost host = CreateHostBuilder(args).Build();
CreateGenericHost(host);
InitAppAndRun();
}
private static void InitAppAndRun()
{
var app = new App();
app.InitializeComponent();
app.MainWindow = ServiceProvider.GetRequiredService();
app.MainWindow!.Visibility = Visibility.Visible;
app.Run();
}
#region Host builder
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureServices(ConfigureServices)
.ConfigureContainer(ConfigureAutofacBuilder);
}
private static void ConfigureAutofacBuilder(HostBuilderContext ctx, ContainerBuilder builder)
{
builder.RegisterModule>();
builder.RegisterModule>();
var config = new ConfigurationBuilder();
config.AddJsonFile("autofac.json");
var module = new ConfigurationModule(config.Build());
builder.RegisterModule(module);
}
private static void CreateGenericHost(IHost host)
{
host.Start();
ServiceProvider = host.Services;
}
private static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
services.AddSingleton();
}
#endregion
}
When I try to start the application, program fails on using IHost host = CreateHostBuilder(args).Build(); and throws this error message:
Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 'No accessible constructors were found for the type 'TestApp.Bases.ListItemViewModelBase'.'
Seems like Autofac can´t resolve non-public constructor of ListItemViewModelBase class. Is there a way to make Autofac resolve these type of non-public constructors?
Thanks,
Tobias
Response to reply from Orenico:
Here is autofac.json which contains basically nothing.
{
"modules": [],
"components": []
}
There are some typos in the sample code, like builder.RegisterModule>(), which won't compile and indicates there are registrations and other stuff going on that you're not showing us.
However:
You can't directly instantiate an abstract class. Like, you can't do new ListItemViewModelBase. That means you can't register it. You can register derived classes As it, but even if Autofac could find the constructor you'd still hit a brick wall because it's not a concrete class.
If Autofac is resolving a type by reflection it doesn't go all the way down the chain looking at constructors, it only looks at the thing you're resolving. That's why it sounds like you probably tried to register that abstract class.
If I had to guess, you have some assembly scanning registrations in those modules you're not showing us where you try registering all the view models and you didn't exclude the base class from the registrations.
Related
I have a custom module MyModule with a custom plugin MyPlugin in this plugin I want to send and receive data via a BinaryConnection.
Here is a simplified version of my code
[ServerModule(ModuleName)]
public class ModuleController : ServerModuleBase<ModuleConfig>
{
protected override void OnInitialize()
{
Container.LoadComponents<IMyPlugin>();
}
protected override void OnStart()
{
Container.Resolve<IBinaryConnectionFactory>();
Container.Resolve<IMyPlugin>().Start();
}
}
[Plugin(LifeCycle.Singleton, typeof(IMyPlugin), Name = PluginName)]
public class MyPlugin: IMyPlugin
{
private IBinaryConnection _connection;
public IBinaryConnectionFactory ConnectionFactory { get; set; }
public IBinaryConnectionConfig Config { get; set; }
public void Start()
{
_connection = ConnectionFactory.Create(Config, new MyMessageValidator());
_connection.Received += OnReceivedDoSomething;
_connection.Start();
}
}
When I start the Runtime I get a NullReferenceException because the ConnectionFactory is not injected. Where is my mistake here?
To use the binary connection in your module you can either instantiate TcpClientConnection and TcpListenerConnection manually or use your modules DI-Container, as you already tried and I would recommend.
To use it in your module, you need to register/load the classes into your container. Take a look at how the Resource Management registers them. In your OnInitialize you need:
Container.Register<IBinaryConnectionFactory>(); // Register as factory
Container.LoadComponents<IBinaryConnection>(); // Register implementations
Then you can add either a BinaryConnectionConfig entry to your config and decorate with [PluginConfigs(typeof(IBinaryConnection), false)] to select Socket as well as Client/Server from the MaintenanceWeb or use the derived type TcpClientConfig/TcpListenerConfig directly.
public class ModuleConfig : ConfigBase
{
[DataMember, PluginConfigs(typeof(IBinaryConnection), false)]
public BinaryConnectionConfig ConnectionConfig { get; set; }
}
In you plugin you can then inject IBinaryConnectionFactory and ModuleConfig to create the connection.
public class MyPlugin: IMyPlugin
{
private IBinaryConnection _connection;
public IBinaryConnectionFactory ConnectionFactory { get; set; }
public ModuleConfig Config { get; set; }
public void Start()
{
_connection = ConnectionFactory.Create(Config.ConnectionConfig, new MyMessageValidator());
_connection.Received += OnReceivedDoSomething;
_connection.Start();
}
}
PS: Resolving the factory in OnStart returns an instance, which you don't use and is unnecessary. Don't confuse Resolve(Find registered implementation and create instance) with Register.
First of all sorry for so much code but i belive it will be easier to find an issue here. I am using SimpleInjector and getting error inside Program class on container.Verify(); line, it says as below. I was trying to investigate throug docs website but still cannot figoure out how to fix that.
SimpleInjector.DiagnosticVerificationException: 'The configuration is
invalid. The following diagnostic warnings were reported:
-[Disposable Transient Component] FrmLogin is registered as transient, but implements IDisposable. See the Error property for detailed
information about the warnings. Please see
https://simpleinjector.org/diagnostics how to fix problems and how to
suppress individual warnings.'
Full code:
static class Program
{
private static Container container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.GetInstance<FrmLogin>());
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
container.Register<IRepositoryDal<User>, UserRepositoryDal>();
container.Register<IRepositoryDal<Order>, OrderRepositoryDal>();
container.Register<IDbManager>(() => new DbManager("sqlserver"));
container.Register<IGenericBal<User>, UserBal>();
container.Register<IGenericBal<Order>, OrderBal>();
container.Register<FrmLogin>();
container.Verify();
}
}
public partial class FrmLogin : Form
{
private readonly IGenericBal<User> _userBal;
private readonly IGenericBal<Order> _orderBal;
public FrmLogin(IGenericBal<User> userBal, IGenericBal<Order> orderBal)
{
InitializeComponent();
_userBal = userBal;
_orderBal = orderBal;
}
}
public interface IGenericBal<out T> where T : IEntity
{
IEnumerable<T> SearchByName(string name);
}
public class UserBal : IGenericBal<User>
{
private readonly IRepositoryDal<User> _userRepositoryDal;
public UserBal(IRepositoryDal<User> userRepositoryDal)
{
_userRepositoryDal = userRepositoryDal ?? throw new ArgumentNullException(nameof(userRepositoryDal));
}
public IEnumerable<User> SearchByName(string name)
{
return _userRepositoryDal.SearchByName(name);
}
}
public interface IEntity
{
int Id { get; set; }
int DoSomething(string one, int two);
}
public interface IRepositoryDal<T> where T : IEntity
{
IEnumerable<T> SearchByName(string username);
T SearchById(string id);
void Update(T entity);
void Remove(T entity);
void Add(T entity);
}
public class UserRepositoryDal: IRepositoryDal<User>
{
private readonly IDbManager _dbManager;
public UserRepositoryDal(IDbManager dbManager)
{
//read from either singleton or configuration file !!
_dbManager = dbManager;
}
public IEnumerable<User> SearchByName(string username)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#Name", 50, username, DbType.String),
};
username = "JUSTyou";
var userDataTable = _dbManager.GetDataTable("SELECT * FROM T_Marke WHERE Name=#Name", CommandType.Text, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Name"].ToString(),
};
yield return user;
}
}
public User SearchById(string id)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#Id", 50, id, DbType.Int32),
};
var userDataTable = _dbManager.GetDataTable("storedpr2", CommandType.StoredProcedure, parameters.ToArray());
return new User
{
Id = int.Parse(userDataTable.Rows[0]["Id"].ToString()),
Firstname = userDataTable.Rows[0]["Firstname"].ToString(),
Lastname = userDataTable.Rows[0]["LastName"].ToString(),
Email = userDataTable.Rows[0]["Email"].ToString()
};
}
public void Update(User entity)
{
throw new System.NotImplementedException();
}
public void Remove(User entity)
{
throw new System.NotImplementedException();
}
public void Add(User entity)
{
throw new System.NotImplementedException();
}
}
public class User : IEntity
{
public int Id { get; set; }
public int DoSomething(string one, int two)
{
throw new NotImplementedException();
}
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
The error is quite clear
A registration has been made with the Transient LifeStyle for a component that implements IDisposable.
A component that implements IDisposable would usually need deterministic clean-up but Simple Injector does not implicitly track and dispose components registered with the transient lifestyle.
One way to fix this is to make its Life Style Scoped
var container = new Container();
// Select the scoped lifestyle that is appropriate for the application
// you are building. For instance:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// DisposableService implements IDisposable
container.Register<FrmLogin>(Lifestyle.Scoped);
Since this is the main form you could probably ignore this warning
and dispose of it your self.
Registration registration = container.GetRegistration(typeof(FrmLogin)).Registration;
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"Reason of suppression");
Though in my personal opinion, you should probably just give it the right Life Style and let Simple Iinjector take care of things
Additional Resources
Diagnostic Warning - Disposable Transient Components
One of my interfaces has a string property that will depend on where the interface is being used. I want to avoid hardcoding the property every time the object is created. I can set the property in constructor, but the object is injected using a factory.
The interface as follows:
public interface IObjectStore
{
string StorageTableName { get; set;}
void UpdateObjectStore(string key, string value);
string ReadObjectStore(string key);
}
Which is used in a service
public class CategoryService<T> : ICategoryService<T> where T : Company
{
private readonly IObjectStore objectStore;
public CategoryService(IObjectStore objStore)
{
this.objectStore = objStore;
objectStore.StorageTableName = "CategoryTable"; // I want to avoid this hard coding
}
...
}
The service is created using service factory (Ninject.Extensions.Factory)
public interface IServiceFactory
{
ICategoryService<T> CreateCategoryService<T>() where T : class;
}
Which is then injected using Ninject at the controller level. Here are my bindings
bool storeInNoSql = true;
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
kernel.Bind<ICategoryService<Article>>().To<CategoryService<Article>>();
kernel.Bind<IObjectStore>().ToMethod(ctx => storeInNoSql ? ctx.Kernel.Get<ObjectStore>() : null);
So the question is: how do i tell Ninject to set the property StorageTableName to "CategoryTable" everytime the object is injected into CategoryService and to "ArticleTable" everytime it is inserted into ArticleService?
I think this is what you are looking for.
It's just a very small sample project I just did, but this should solve your problem.
public class Ninject_34091099
{
public static void Run()
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<IInterface<Generic1>>()
.To<Class<Generic1>>()
.WithConstructorArgument("name", "STRING ONE");
kernel.Bind<IInterface<Generic2>>()
.To<Class<Generic2>>()
.WithConstructorArgument("name", "The other string");
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
var factory = kernel.Get<IServiceFactory>();
var c1 = factory.CreateInterface<Generic1>();
var c2 = factory.CreateInterface<Generic2>();
Console.WriteLine(c1.Name);
Console.WriteLine(c2.Name);
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
public interface IInterface<T> where T : class
{
string Name { get; set; }
}
public class Generic1
{
}
public class Generic2
{
}
public class Class<T> : IInterface<T> where T : class
{
public string Name { get; set; }
public Class(string name)
{
Name = name;
}
}
public interface IServiceFactory
{
IInterface<T> CreateInterface<T>() where T : class;
}
Sorry that the names mean nothing :D
Hope it helps
I'm new to Unity and am trying to write some Unity logic which initialises and register/resolves a singleton instance of the Email object so that it can be used across several other objects, one example below being OperationEntity.
So when it's registered it populates the Email singleton with some values from a config file, then whenever an instance of OperationEntity is created (in my case it's being deserialized) it uses that same Email singleton. So all my client logic needs to do is deserialize OperationEntity and call PerformAction() - with the email instance taken care of by Unity.
public interface IEmail
{
string FromName { get; set; }
string FromEmailAddress { get; set; }
}
public class Email : IEmail
{
public string FromName { get; set; }
public string FromEmailAddress { get; set; }
public Email(string fromName, string fromEmailAddress)
{
FromName = fromName;
FromEmailAddress = fromEmailAddress;
}
}
public class OperationEntity
{
private readonly IEmail _email;
public int OperationId { get; set; }
public string OperationName { get; set; }
public string ToAddress { get; set; }
public OperationEntity(IEmail email)
{
_email = email;
}
public void PerformAction()
{
_email.ToAddress = ToAddress;
_email.Body = "Some email body";
_email.Deliver();
}
}
Any help would be appreciated in getting this Unity code to work
public static void Register(IUnityContainer container)
{
container
.RegisterType<IEmail, Email>(
new InjectionFactory(c => new Email(
"To Name",
"to#email.com")));
var email = container.Resolve<IEmail>();
container.RegisterType<OperationEntity>(
"email", new ContainerControlledLifetimeManager(),
new InjectionConstructor(email));
}
First, you need a proper lifetime manager the ContainerControlledLifetimeManager is for singletons.
For custom initialization, you could probably use InjectionFactory
This lets you write any code which initializes the entity.
Edit1: this should help
public static void Register(IUnityContainer container)
{
container
.RegisterType<IEmail, Email>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(c => new Email(
"To Name",
"to#email.com")));
}
and then
var opEntity = container.Resolve<OperationEntity>();
Edit2: To support serialization, you'd have to rebuild dependencies after you deserialize:
public class OperationEntity
{
// make it public and mark as dependency
[Dependency]
public IEmail _email { get; set;}
}
and then
OperationEntity entity = somehowdeserializeit;
// let unity rebuild your dependencies
container.BuildUp( entity );
You could use:
container.RegisterType<IEmail, Email>(new ContainerControlledLifetimeManager());
If IEmail is a singleton with no dependencies (just custom arguments), you can new it up yourself:
container.RegisterInstance<IEmail>(new Email("To Name", "to#email.com"));
That will register the supplied instance as a singleton for the container.
Then you just resolve the service:
container.Resolve<OperationEntity>();
And because you are resolving a concrete type, there is no registration required. Nevertheless, if you would like that service to also be a singleton, you can register it using ContainerControlledLifetimeManager and then all calls to resolve (or when injecting it as a dependency to another class) will return the same instance:
container.RegisterType<OperationEntity>(new ContainerControlledLifetimeManager());
You can, for example, use this code:
public class example : MonoBehaviour
{
public static example instance;
public void Start()
{
(!instance)
instance = this;
}
}
You could implement your own singleton class and extend any class form it.
public class MyClass : MonoBehaviour {
private static MyClass _instance;
public static MyClass Instance { get { return _instance; } }
private void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(this.gameObject);
} else {
_instance = this;
}
}
}
I have an interface for holding the connection configuration info for web service access:
public interface IServiceConnectionConfiguration
{
string Username { get; }
string Password { get; }
string ChannelEndpointUrl { get; }
string MediaEndpointUrl { get; }
string PlayerlEndpointUrl { get; }
string PlaylistEndpointUrl { get; }
}
I have a factory class that returns the service instance specific to the type of the service requested.
public static class ServiceClientFactory
{
public static void Configure(IServiceConnectionConfiguration config)
{
_config = config;
}
public static T GetService<T>() where T : class, IServiceClient
{
}
}
The factory is called as
Channel channelService = factory.GetService<Channel>();
What I am trying to figure out is an elegant way for the Factory code to resolve the endpoint urls for the passed in types itself based on the config object passed during initialization. eg. If the type parameter passed is channel, it should take the ChannelEndpointUrl while constructing the ChannelService.
I thought about using attributes on the config class to decorate the endpoint urls with the service type that they correspond to but it seems like a bad design.
Any ideas.
Well, one way to approach it would be to have the Factory have a private static Dictionary containing your initialization logic, indexed by "Type". Similar to a strategy pattern.
for example:
public static class ServiceClientFactory
{
private static IServiceConnectionConfiguration _config;
private static readonly Dictionary<Type, Func<IServiceClient>> Initializers = new Dictionary<Type, Func<IServiceClient>>();
static ServiceClientFactory()
{
Initializers.Add(typeof(Channel), () =>
{
return //create the service client based on the endpoint
});
}
public static void Configure(IServiceConnectionConfiguration config)
{
_config = config;
}
public static T GetService<T>() where T : class, IServiceClient
{
return (T)Initializers[typeof (T)]();
}
}
EDIT: Now, as you mentioned, you cannot instantiate explicitly in your factory since you'd cause a circular reference, maybe you can force a new() constraint, and construct the instance in the GetService method, and only use the dictionary for endpoint configuration, such as:
public static class ServiceClientFactory
{
private static IServiceConnectionConfiguration _config;
private static readonly Dictionary<Type, Action<IServiceClient>> Initializers = new Dictionary<Type, Action<IServiceClient>>();
static ServiceClientFactory()
{
Initializers.Add(typeof(Channel), t =>
{
t.Url = _config.ChannelEndpointUrl;
//configure t using the appropriate endpoint
});
}
public static void Configure(IServiceConnectionConfiguration config)
{
_config = config;
}
public static T GetService<T>() where T : class, IServiceClient, new()
{
var service = new T();
Initializers[typeof(T)](service);
return service;
}
}