Resolve named Dependencies with Dependency Resolver - asp.net-mvc

I've noticed that when I register my dependencies via named overrides Dependency Resolver struggles to resolve components properly. Seems like the first instance is provided. Everything is fine with ctor injection.
Example:
Registration
RegisterProvider<IAccountProvider, AccountProvider>();
RegisterProvider<IAccountProvider, CustomAccountProvider>("customAccountProvider");
Resolution
var instance = DependecyResolver.Current.GetService<IAccountProvider>();
Cannot retrieve customAccountProvider instance.
It always refers to the first registered component ignoring named constraints.

When you have multiple implementations of the same component you have to name them or mark them with marking interface. Here is a code example with naming the instances :
using System;
using System.Linq;
using System.Reflection;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace ResolvingNamedInctances
{
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<AccountProviderTypeSelector>());
container.Register(Component.For<IAccountProviderSelector>().AsFactory(typeof(AccountProviderTypeSelector)));
container.Register(Component.For<IAccountProvider>().ImplementedBy<DefaultAccountProvider>().Named("default"));
container.Register(Component.For<IAccountProvider>().ImplementedBy<CustomAccountProvider>().Named("custom"));
// uncomment this line in MVC app and use DependencyResolver instead of container
//DependencyResolver.SetResolver(new WindsorDependencyResolver(container.Kernel));
var accountProviderSelector = container.Resolve<IAccountProviderSelector>();
var defaultAccountProvider = accountProviderSelector.GetAccountProvider(); // default
defaultAccountProvider.Provide();
var customAccountProvider = accountProviderSelector.GetAccountProvider("custom");
customAccountProvider.Provide();
Console.ReadLine();
}
}
public class AccountProviderTypeSelector : ITypedFactoryComponentSelector
{
public Func<IKernelInternal, IReleasePolicy, object> SelectComponent(MethodInfo method, Type type, object[] arguments)
{
string providerName = arguments.Length > 0 ? (string)arguments[0] : "default";
return (k, r) => k.GetHandlers(typeof(IAccountProvider))
.Where(
h =>
{
return h.ComponentModel.Name == providerName;
})
.Select(h => (IAccountProvider)k.Resolve(
h.ComponentModel.Name,
typeof(IAccountProvider),
new Arguments { },
r))
.FirstOrDefault();
}
}
public interface IAccountProviderSelector
{
IAccountProvider GetAccountProvider();
IAccountProvider GetAccountProvider(string nameIdentifier);
}
public interface IAccountProvider
{
void Provide();
}
public class DefaultAccountProvider : IAccountProvider
{
public void Provide()
{
Console.WriteLine("Working in default AccountProvider");
}
}
public class CustomAccountProvider : IAccountProvider
{
public void Provide()
{
Console.WriteLine("Working in standart CustomAccountProvider");
}
}
}

Related

Interface with more implementation and Dependency Injection

I created a project with .net Core 2.
Now I have a List of classes from the same interface which I needed at runtime.
My problem is, I can't add this classes to the servicecollection (only one interface). So I don't have access to the other services in those classes. Also I think it wouldn't solve it.
I could create a singleton/static class with my servicecollection and use the IServiceProvider to get those other services from there, but I think that isn't the best practice.
Here is an example of my problem:
public class Manager : IManager
{
private IList<IMyService> _myService;
public Manager()
{
IList<Type> types = GetIMyServiceTypes();
foreach (Type type in types)
{
var instance = (IMyService)Activator.CreateInstance(type);
_myService.Add(instance)
}
}
public IList<bool> IsTrue()
{
return _myService
.Select(se => se.IsTrue())
.ToList();
}
public IList<Type> GetIMyServiceTypes()
{
var type = typeof(IMyService);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p))
.ToList();
return types;
}
}
public class ServiceType1: IMyService
{
public bool IsTrue()
{
//Need Access to IServiceCollection Services
}
}
public interface IMyService
{
bool IsTrue();
}
public class MyController : Controller
{
private IManager _amanager;
public MyController(IManager manager)
{
_manager = manager
}
public IActionResult IsTrue()
{
IList<bool> isTrue =_manager.IsTrue();
return new ObjectResult(isTrue);
}
}
Is there a pattern, which I could use to solve my problem? Is there a best practice to have access to the services without using them in the constructor?
I found the solution on another post in stackoverflow https://stackoverflow.com/a/44177920/5835745
But I will post my changes for other people with the same problem. I loaded the list of classes from the configuration, but it's also possible to add all classes.
public class Manager : IManager
{
private IList<IMyService> _myService;
private readonly Func<string, IService> _serviceAccessor;
public Manager (Func<string, IService> serviceAccessor)
{
IList<string> authentications = new List<string> {"value1", "value2"}
foreach (string authentication in authentications)
{
AddAuthentication(_serviceAccessor(authentication));
}
}
public IList<bool> IsTrue()
{
return _myService
.Select(se => se.IsTrue())
.ToList();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<Value1>();
services.AddTransient<Value2>();
services.AddTransient(factory =>
{
Func<string, IService> accesor = key =>
{
switch (key)
{
case "value1":
return factory.GetService<Value1>();
case "value2":
return factory.GetService<Value2>();
default:
throw new KeyNotFoundException();
}
};
return accesor;
});
}
}

Web API, Light Inject and Passing a Static Dictionary to the data layer

We have a multi-database solution and are passing the connection string to a factory function like so:
container.Register<IDbContextFactory>(
f => new DynamicDbContextFactory(ClientConfig.GetConnectionString()),
new PerScopeLifetime());
ClientConfig contains a static dictionary that gets populated on app start that maps a sub domain to a connection string. It seems that this approach is causing a memory leak (not 100% sure about this causing the leak but there is a leak).
public class ClientConfig
{
private static ConcurrentDictionary<string, string> ConnectionStringManager
{
get;
set;
}
// etc.
}
My question is in MVC what is the best way to hold a list of connection strings that can be easily looked up on each request in order to pass that down the chain.
Edit : The question was initially tagged with Autofac
With Autofac you don't have to use a dictionary and something like that to do what you want. You can use a custom parameter :
public class ConnectionStringParameter : Parameter
{
public override Boolean CanSupplyValue(ParameterInfo pi,
IComponentContext context,
out Func<Object> valueProvider)
{
valueProvider = null;
if (pi.ParameterType == typeof(String)
&& String.Equals(pi.Name, "connectionString",
StringComparison.OrdinalIgnoreCase))
{
valueProvider = () =>
{
// get connectionstring based on HttpContext.Current.Request.Url.Host
return String.Empty;
};
}
return valueProvider != null;
}
}
Then register your Parameter using a Module
public class ConnectionStringModule : Autofac.Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += registration_Preparing;
}
private void registration_Preparing(Object sender, PreparingEventArgs e)
{
Parameter[] parameters = new Parameter[] { new ConnectionStringParameter() };
e.Parameters = e.Parameters.Concat(parameters);
}
}
Module you have to register inside your container using
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
Each time Autofac have to resolve a parameter of type String named connectionString it will used the custom parameter and get your connectionstring based on what you want.
By the way this code sample use HttpContext.Current. In case of a multithreaded process it may return null. I don't recommend using HttpContext.Current for such things. You can use an intermediate class instead of accessing it, for example a IConnectionstringProvider interface.
public interface IConnectionstringProvider
{
String ConnectionString { get; }
}
public class ConnectionStringProvider : IConnectionstringProvider
{
public ConnectionStringProvider(Strong host)
{
// get connectionstring based on host
this._connectionString = String.Empty;
}
private readonly String _connectionString;
public String ConnectionString
{
get { return this._connectionString; }
}
}
Inside your Parameter you will have to change the valueProvider by
valueProvider = () =>
{
return context.Resolve<IConnectionstringProvider>().ConnectionString;
};
And finally you will have to register your IConnectionstringProvider at the beginning of the request lifetimescope :
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
IContainer container = builder.Build();
container.ChildLifetimeScopeBeginning += container_ChildLifetimeScopeBeginning;
}
private static void container_ChildLifetimeScopeBeginning(
Object sender, LifetimeScopeBeginningEventArgs e)
{
String host = HttpContext.Current.Request.Url.Host;
ContainerBuilder childLifetimeScopeBuilder = new ContainerBuilder();
childLifetimeScopeBuilder.RegisterInstance(new ConnectionStringProvider(host))
.As<IConnectionstringProvider>()
.SingleInstance();
childLifetimeScopeBuilder.Update(e.LifetimeScope.ComponentRegistry);
}
}
Of course there is many way to do it but you have the idea

Long-running Seed method with Entity Framework code-first

My Seed() method is getting rather long-running. Is there a way to write to the console whilst running the update-database command?
So far, Console.WriteLine() and Debug.WriteLine() have not written output to the Package Manager Console.
You can avoid run-on seed methods by extending the base DbContext class with a method that accepts an interface and returns the context instance to keep things fluent.
Though it doesn't solve the issue of not being able to write console/debug output in the package manager console, it will tell you which entity that you failed on while keeping things tidy.
Configuration.cs
using System.Configuration;
using MySolution.Data.Migrations.Seedings;
namespace MySolution.Data.Migrations
{
using System.Data.Entity.Migrations;
internal sealed class Configuration : DbMigrationsConfiguration<MySolution.Data.MySolutionContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(MySolution.Data.MySolutionContext context)
{
context
.AppendSeeding<AddressSeeding>(true)
.AppendSeeding<CustomerSeeding>(true)
.AppendSeeding<OrderSeeding>(true)
.AppendSeeding<ShipmentSeeding>(true)
.AppendSeeding<ApplicationSettingsSeeding>();
}
}
}
DbContextExtensions.cs
using System;
using System.Data.Entity;
namespace MySolution.Data.Migrations {
public static class DbContextExtensions {
public static DbContext AppendSeeding<T>(
this DbContext context, bool saveChanges = false)
where T : ISeeding, new() {
var seeding = new T();
try {
seeding.Seed(context);
if (saveChanges) {
context.SaveChanges();
}
}
catch (Exception ex) {
throw new Exception(
$"Unhandled exception while appending seed data via {seeding.GetType().Name}",
ex);
}
return context;
}
}
}
ISeeding.cs
using System.Data.Entity;
namespace MySolution.Data.Migrations {
public interface ISeeding {
void Seed(DbContext context);
}
}
AddressSeeding.cs (Example implementation of ISeeding)
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using MySolution.Data.Models;
namespace MySolution.Data.Migrations.Seedings {
public class AddressSeeding : ISeeding {
public void Seed(DbContext context) {
((MySolutionContext)context).Address.AddOrUpdate(
address => new { address.Address1},
new Address {
Address1 = "111 Fake St.",
City = "Nowhereland",
County = "Countyville",
State = "ST",
Zip = "12345",
AddressType = new AddressType {
Name = "Home"
},
}
);
}
}
}

Autofac, multiple interfaces to same implementation per HTTP request in ASP.NET MVC

My DbContext implementation implements two interfaces.
I'm trying to follow best practices and instantiate one DbContext instance per HTTP request.
However, I have a controller action where I need to instantiate two classes, each of which takes different interface in constructor.
I am worried if in that scenario, for that specific action, two DbContext instances would be raised.
I've setup my ContainerBuilder like this:
builder.RegisterType<MyDbContext>()
.As<IWorkflowPersistenceStore>()
.As<IDocumentPersistenceStore>()
.InstancePerHttpRequest();
builder.RegisterType<WorkflowManager>().As<IWorkflowManager>().InstancePerHttpRequest();
builder.RegisterType<DocumentManager>().As<IDocumentManager>().InstancePerHttpRequest();
public class OperationController : Controller
{
private IWorkflowManager _workflowManager;
private IDocumentManager _documentManager;
public OperationController(IWorkflowManager workflowManager, IDocumentManager documentManager)
{
_workflowManager = workflowManager;
_documentManager = documentManager;
}
public ActionResult SaveWorkflowDocument(...)
{
// will my managers point to same DbContext?
_workflowManager.DoSomething(...);
_documentManager.DoSomethingElse(...);
return View();
}
}
public class WorkflowManager : IWorkflowManager
{
private IWorkflowPersistenceStore _store;
public WorkflowManager(IWorkflowPersistenceStore store)
{
_store = store;
}
}
public class DocumentManager : IDocumentManager
{
private IDocumentPersistenceStore _store;
public DocumentManager (IDocumentPersistenceStore store)
{
_store = store;
}
}
Is this good enough?
Do I have to add .SingleInstance()? I'm worried that it might create singleton for whole application.
I think you're ok with what you have. Test passes:
using Autofac;
using NUnit.Framework;
namespace AutofacTest
{
[TestFixture]
public class ScopeTest
{
[Test]
public void Test()
{
var builder = new ContainerBuilder();
builder.RegisterType<Component>()
.As<IServiceA>()
.As<IServiceB>()
.InstancePerLifetimeScope();
using (var container = builder.Build())
using (var scope = container.BeginLifetimeScope())
{
var a = scope.Resolve<IServiceA>();
var b = scope.Resolve<IServiceB>();
Assert.AreEqual(a, b);
}
}
}
public interface IServiceA { }
public interface IServiceB { }
public class Component : IServiceA, IServiceB { }
}

Structure Map configuration

Consider the following class
public class SchemaExecutor: ISchemaExecutor
{
public SchemaExecutor(SqlPlusSettings sqlPlusSettings)
{
_sqlPlusSettings = sqlPlusSettings;
}
...
And container configuration
ObjectFactory.Initialize( x =>
{
SqlPlusSettings sqlPlusSettings = GetSqlPlusSettings();
x.ForRequestedType<ISchemaExecutor>().TheDefaultIsConcreteType<SchemaExecutor>()
.WithCtorArg("sqlPlusSettings").EqualT(sqlPlusSettings);
});
But .WithCtorArg works only for primitives and so the initialization above doesn't work.
Is there any way to configure constructor with non primitive parameter?
You need to just let the IoC do what it does and inject your dependencies for you...
ObjectFactory.Initialize( x =>
{
x.ForRequestedType<SqlPlusSettings>().TheDefaultIsConcreteType<SqlPlusSettings>().AsSingletons;
x.ForRequestedType<ISchemaExecutor>().TheDefaultIsConcreteType<SchemaExecutor>();
});
SqlPlusSettings sqlPlusSettings = GetSqlPlusSettings();
ObjectFactory.Inject<SqlPlusSettings>(sqlPlusSettings);
The way you have it here with none of the AutoWiring, I think the redundant line for SqlPlusSettings is needed to let StructureMap know about it. But essentially SM knows about both the SchemaExecutor and the SqlPlusSettings and when instantiating the SchemaExecutor it looks for the parameters, see's that the SqlPlusSettings is a singleton and it already has one and passes it to instantiate the SchemaExecutor.
If you wish to control exactly what instance of the settings object your class will receive you can accomplish this by either configuring the concrete class or per plugin by configuring its dependency.
Note: I am using the trunk but I believe that everything here is available in 2.5.3.
public class MySettings
{
}
public interface IMyClass
{
MySettings Settings { get; }
}
public class MyClass : IMyClass
{
public MySettings Settings { get; private set; }
public MyClass(MySettings settings)
{
Settings = settings;
}
}
[TestFixture]
public class registry_test
{
[Test]
public void configure_concrete_class()
{
var mySettings = new MySettings();
var container = new Container(config =>
{
config.For<MySettings>().Use(mySettings);
config.For<IMyClass>().TheDefaultIsConcreteType<MyClass>();
});
container.GetInstance<IMyClass>().Settings.ShouldBeTheSameAs(mySettings);
}
[Test]
public void configure_concrete_ctor_dependency()
{
var mySettings = new MySettings();
var container = new Container(config =>
{
config.For<IMyClass>().TheDefault.Is.OfConcreteType<MyClass>()
.CtorDependency<MySettings>().Is(mySettings);
});
container.GetInstance<IMyClass>().Settings.ShouldBeTheSameAs(mySettings);
}
}

Resources