I did not managed to find any similar example, so I decided to ask the question.
I am using Autofac to register my service layer interfaces and I am wondering, can I inject one into App.xaml.cs?
I am having my own log service, that I want to run in case of fatal error in the application.
As far as I know similar way you can inject dependency to the window, can I do it the same in App.xaml.cs?
public partial class App : Application
{
private readonly ILogService _log;
public App()
{
}
public App(ILogService log) : this()
{
_log = log;
}
async Task App_DispatcherUnhandledExceptionAsync(object sender, DispatcherUnhandledExceptionEventArgs e)
{
_log.Error("App.xaml.cs exception: " + e.Exception.Message);
await _log.SaveAllLinesAsync();
e.Handled = true;
}
}
Autofac IoC:
public class BootStrapper
{
/// <summary>
/// IoC container
/// </summary>
/// <returns></returns>
public static IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<EventAggregator>()
.As<IEventAggregator>().SingleInstance();
builder.RegisterType<LogService>()
.As<ILogService>().SingleInstance();
builder.RegisterType<DeleteView>().AsSelf();
builder.RegisterType<DeleteViewModel>().AsSelf().SingleInstance();
builder.RegisterType<PhraseView>().AsSelf();
builder.RegisterType<PhraseViewModel>().AsSelf().SingleInstance().WithParameter(new NamedParameter("searchPhrase", ""));
builder.RegisterType<PopulateDictionaries>().AsSelf().SingleInstance();
return builder.Build();
}
}
IoC initializing in ViewModelLocator:
public class ViewModelLocator
{
IContainer _container;
public ViewModelLocator()
{
_container = BootStrapper.BootStrap();
}
//view models below
}
If you want to inject the App class with a dependency, you should define a custom Main method where you instantiate the App class:
public class Program
{
[STAThread]
public static void Main(string[] args)
{
ILogService logService = ...;
App app = new App(logService);
app.InitializeComponent();
app.Run();
}
}
If you do this, remember to change the Build Action of App.xaml from ApplicationDefinition to Page.
Related
I am using Simple Injector to register a concrete type in the container in a .NET Core console app (in Program.cs), but Simple Injector throws an exception on start up:
The constructor of type Application contains the parameter with name 'configUpdater' and type ConfigUpdater, but ConfigUpdater is not registered. For ConfigUpdater to be resolved, it must be registered in the container. An implicit registration could not be made because Container.Options.ResolveUnregisteredConcreteTypes is set to 'false', which is now the default setting in v5. This disallows the container to construct this unregistered concrete type. For more information on why resolving unregistered concrete types is now disallowed by default, and what possible fixes you can apply, see https://simpleinjector.org/ructd
EDIT:
Adding a MRE example which throws the exception:
using System.Threading.Tasks;
using NLog;
using SimpleInjector;
namespace MRE
{
public static class Program
{
private static Container container;
static Program()
{
container = new Container();
container.Register<IApplication, Application>(Lifestyle.Singleton);
var appSettings = new AppSettings();
container.Register(
typeof(AppSettings),
() => appSettings,
Lifestyle.Singleton
);
container.RegisterConditional(
typeof(ILog),
typeCtx => typeof(NLogProxy<>).MakeGenericType(typeCtx.Consumer.ImplementationType),
Lifestyle.Singleton,
predCtx => true
);
container.Register<IConfigUpdater, ConfigUpdater>(Lifestyle.Scoped);
}
public static void Main(string[] args)
{
var application = container.GetInstance<IApplication>();
application.RunAsync();
}
}
public class AppSettings
{
public string ConnectionString { get; set; } = "DataSource=data.db";
}
public interface ILog
{
void Info(string message);
}
public class NLogProxy<T> : ILog
{
private static readonly NLog.ILogger Logger = LogManager.GetLogger(typeof(T).FullName);
public void Info(string message) => Logger.Log(LogLevel.Info, message);
}
public interface IApplication
{
Task RunAsync();
}
public class Application : IApplication
{
private readonly ILog logger;
private readonly IConfigUpdater configUpdater;
public Application(
ILog logger,
IConfigUpdater configUpdater
)
{
this.logger = logger;
this.configUpdater = configUpdater;
}
public Task RunAsync()
{
logger.Info("Running");
configUpdater.DoTask();
return Task.CompletedTask;
}
}
public interface IConfigUpdater
{
Task DoTask();
}
public class ConfigUpdater : IConfigUpdater
{
private readonly AppSettings appSettings;
private readonly ILog logger;
public ConfigUpdater(
AppSettings appSettings,
ILog logger
)
{
this.appSettings = appSettings;
this.logger = logger;
}
public Task DoTask()
{
var connectionString = appSettings.ConnectionString;
logger.Info(connectionString);
return Task.CompletedTask;
}
}
}
EDIT #2:
With the help of the MRE, I discovered my issue was actually hiding behind the scenes. It was a issue with using Lifestyle.Scoped which for some reason was not the first exception thrown. Setting the default lifestyle to AsyncScopedLifestyle fixes it.
With the help of the MRE, I found that the actual error was to do with the default Lifestyle SimpleInjector was using. Adding the line:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
fixes the issue of this question.
As to why the Lifestyle exception wasn't thrown first, I don't know.
I am trying to use dependency injection for a .Net Core Console application using the built in DI.
I have 2 following Methods :
private static void RegisterServices()
{
var collection = new ServiceCollection();
//repositories
collection.AddScoped<IAccountDataRepository, AccountDataRepository>();
collection.AddScoped<IClientDataRepository, ClientDataRepository>();
collection.AddScoped<IAddressDataRepository, AddressDataRepository>();
collection.AddScoped<IClientAccountDataRepository, ClientAccountDataRepository>();
//services
collection.AddScoped<IAccountDataService, AccountDataService>();
collection.AddScoped<IClientDataService, ClientDataService>();
collection.AddScoped<IAddressDataService, AddressDataService>();
collection.AddScoped<IClientAccountDataService, ClientAccountDataService>();
_serviceProvider = collection.BuildServiceProvider();
}
private static void DisposeServices()
{
if (_serviceProvider == null)
{
return;
}
if (_serviceProvider is IDisposable)
{
((IDisposable)_serviceProvider).Dispose();
}
}
I can get this to work in the main method by using this:
private static IServiceProvider _serviceProvider;
private static IClientDataRepository _clientDataRepository;
static void Main(string[] args)
{
RegisterServices();
_clientDataRepository = _serviceProvider.GetService<IClientDataRepository>();
However I need to inject the repository to the service and the service to main but I can t use the following in the service class :
_clientDataRepository = _serviceProvider.GetService<IClientDataRepository>();
Here is service:
public class ClientDataService : IClientDataService
{
private readonly ILogger _logger;
private readonly IClientDataRepository _clientDataRepository;
public ClientDataService(ILogger logger, IClientDataRepository clientDataRepository)
{
_logger = logger;
_clientDataRepository = clientDataRepository;
}
If I use
_clientDataRepository = _serviceProvider.GetService<IClientDataRepository>();
will give an error
Just resolve the service and the service provider will inject the repository into the service when building the object graph of the requested object
Based on the provided ClientDataService you would also need to make sure that all dependencies are registered with the service collection.
As it is current shown, ClientDataService also depends on ILogger which does not appear to be registered with the service collection.
services.AddLogging();
The following example uses the originally provided code and refactors to run the main using dependency injection.
public class Program
private readoonly IClientDataService service;
public Program(IClientDataService service) {
this.service = service;
}
public void SomeMethod() {
//...
}
//entry
public static void Main(string[] args) {
IServiceProvider serviceProvider = RegisterServices();
Program program = serviceProvider.GetService<Program>();
program.SomeMethod();
DisposeServices(serviceProvider);
}
//Support
private static IServiceProvider RegisterServices() {
var services = new ServiceCollection();
//repositories
services.AddScoped<IAccountDataRepository, AccountDataRepository>();
services.AddScoped<IClientDataRepository, ClientDataRepository>();
services.AddScoped<IAddressDataRepository, AddressDataRepository>();
services.AddScoped<IClientAccountDataRepository, ClientAccountDataRepository>();
//services
services.AddScoped<IAccountDataService, AccountDataService>();
services.AddScoped<IClientDataService, ClientDataService>();
services.AddScoped<IAddressDataService, AddressDataService>();
services.AddScoped<IClientAccountDataService, ClientAccountDataService>();
services.AddLogging(); //<-- LOGGING
//main
services.AddScoped<Program>(); //<-- NOTE THIS
return services.BuildServiceProvider();
}
private static void DisposeServices(IServiceProvider serviceProvider) {
if (serviceProvider == null) {
return;
}
if (serviceProvider is IDisposable sp) {
sp.Dispose();
}
}
}
With SignalR 2.0 in a self-hosted application, from these instructions you have something like this:
class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR(new HubConfiguration { Resolver = ... });
}
}
class Program
{
static void Main(string[] args)
{
using (WebApp.Start("http://localhost:8080")) // constructs Startup instance internally
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
You will notice that the Startup class instance is created with some behind-the-scenes magic. I can't figure out how to fill in dependencies on it. Is there some way to override the construction of the Startup class so that I can inject dependencies into it?
Instead of replacing the IAppActivator, you can simply register Startup's constructor arguments with Katana's ServiceProvider.
The default IAppActivator will resolve any services matching the Startup constructor's argument types for you. The only downside is you can't use WebApp.Start, since that doesn't expose the ServiceProvider:
public class MyService : IMyService
{
private readonly IMyOtherService _myOtherService;
// Services will be recursively resolved by Katana's ServiceProvider
public MyService(IMyOtherService myOtherService)
{
_myOtherService = myOtherService;
}
// Implementation
}
public class Startup
{
private readonly IMyService _myService;
// Startup must have exactly one constructor.
public Startup(IMyService myService)
{
_myService = myService
}
public void Configuration(IAppBuilder app)
{
app.MapSignalR(new HubConfiguration { Resolver = ... });
}
}
using System;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.Hosting.Services;
using Microsoft.Owin.Hosting.Starter;
public class Program
{
static void Main(string[] args)
{
var url = "http://localhost:8080";
var services = (ServiceProvider)ServicesFactory.Create();
var options = new StartOptions(url);
services.Add<IMyOtherService, MyOtherService>();
services.Add<IMyService, MyService>();
var starter = services.GetService<IHostingStarter>();
using (starter.Start(options)) // constructs Startup instance internally
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
I copied the default implementation of WebApp.Start into Program.Main, but instead of calling IHostingStarter.Start immediately, I add custom services first: http://katanaproject.codeplex.com/SourceControl/changeset/view/c726b87e90c05677a256ca1821bac481f402d6bd#src/Microsoft.Owin.Hosting/WebApp.cs
There are a bunch of other overloads for ServiceProvider.Add if you need them: http://msdn.microsoft.com/en-us/library/microsoft.owin.hosting.services.serviceprovider(v=vs.111).aspx
This should be much simpler than replacing Katana's IAppActivator using StartOptions.Settings like I suggest in my previous answer.
I am leaving my previous answer up, however, as it does explain in more detail how the Startup class is constructed and how to replace default service implementations using the Settings dictionary.
Checkout the dependency injection information here: http://www.asp.net/signalr/overview/signalr-20/extensibility/dependency-injection
Should have everything you need to know :)
Hope this helps!
class Startup
{
private readonly IDependencyResolver _resolver;
public Startup(IDependencyResolver resolver)
{
_resolver = resolver;
}
public void Configuration(IAppBuilder app)
{
app.MapSignalR(new HubConfiguration { Resolver = _resolver; });
}
}
class Program
{
static void Main(string[] args)
{
Startup startup = new Statrtup(new MyResolver());
using (WebApp.Start("http://localhost:8080", startup.Configuration))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
In MVC 5 we get this account controller that looks like this.
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new DatePickerDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
}
I installed Ninject to handle my dependency injection. I have two repositories, that I want to use in my AccountController
and the code now looks like this
public class AccountController : Controller
{
private readonly ILicenserepository _licenserepository;
private readonly IUserRepository _userRepository;
public AccountController(ILicenserepository licenserepository, IUserRepository userRepository)
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new DatePickerDbContext())))
{
_licenserepository = licenserepository;
_userRepository = userRepository;
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
}
in ninject.web.common this is what i've done
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(typeof (ILicenserepository)).To(typeof (Licenserepository));
kernel.Bind(typeof (IUserRepository)).To(typeof (UserRepository));
}
but when I run the application i get the error on browser that says no parametereless constructor found. And if i create parameter less constructor my repositories doesn't get instantiated. So wherever i called the method from repository the value is null.
How can I solve this problem? Or make MVC or Ninject know which constructor to call?
You need a DependencyResolver registered in Global.asax.cs
Registration would look something like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
RegisterDependencyResolver();
}
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
// you may need to configure your container here?
RegisterServices(kernel);
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
And the DependencyResolver
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
{
this.kernel = kernel;
}
public object GetService(Type serviceType)
{
return this.kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return this.kernel.GetAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
}
This is an update:
If your are using MVC5 and WebAPI 2 then all you need to do is use NuGet Manager and add NinjectMVC5 and NinjectWebApi2 into your project. Then the error goes away. (Using Visual Studio 2013)
Cheers
I just got this working without issue using .NET MVC 5 and Ninject 3.3.4.
Steps Taken:
Install Ninject 3.3.4
Install Ninject.Web.Common 3.3.1
Install Ninject.Web.Common.WebHost 3.3.1
Install Ninject.MVC5 3.3.0 (for use with an MVC Controller)
(Optional) Api Controller Steps
Install Ninject.Web.WebApi 3.3.0 (for use with an api ApiController)
Install Ninject.Web.WebApi.WebHost (for use with an ApiController)
The important distinction here is whether your project uses Api Controllers or Mvc Controllers. If you are unfamiliar with the difference please check out the below post:
Difference between ApiController and Controller in ASP.NET MVC.
Note: I did not have to do any extra configuration to my Ninject.Web.Common.cs file. Below is my configuration omitting my bindings
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(YourProject.Web.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(YourProject.Web.App_Start.NinjectWebCommon), "Stop")]
namespace YourProject.Web.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.WebHost;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
// Common
// Repositories
// Services
// Factories
// Misc
}
}
}
Does anyone have any idea about what i doing wrong?
I have a such static class:
public static class ApplicationContainer
{
private static ContainerBuilder builder = null;
private static IContainer container = null;
public static void Create()
{
builder = new ContainerBuilder();
builder.RegisterInstance(new Repository<Log>(RepositoryType.Main))
.As<IRepository<Log>>().SingleInstance()
.Named("Log", typeof(Repository<Log>));
container = builder.Build();
}
public static IContainer Container()
{
if (container != null) return container;
throw new Exception("Container is not ready.");
}
}
In Global.asax.cs of my MVC application i have:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ApplicationContainer.Create();
RegisterRoutes(RouteTable.Routes);
}
And now about problem: how can i to resolve named instance from a container?
public class DefaultLogger : ILogger
{
ApplicationContainer.Container().Resolve("Log", typeof(Repository<Log>);// <--- does not work
}
But when ApplicationContainer class is not static, resolving from container works very good.
I use autofac 2.2.4.
I believe you cannot compile this code since you are missing a closing ')' for your .Resolve(...) call.
That said, have you looked at the Autofac ASP.Net integration modules?