Multiple registration configuration based on string info Autofac - autofac

Finally I found the answer, thanks #yeah-buddy
Autofac Resolve constructor instance from Container?
public class Car
{
public Car(IEngine engine) { }
}
public interface IEngine { }
public interface IRepository { }
public class Engine : IEngine
{
public Engine(IRepository repository) { }
}
public class GenericRepository : IRepository
{
public GenericRepository(string carName) { } // !!! Generic Repository write information to carName table, this dependency is keypoint)
}
I want to register:
"Ferrari": Use Engine with GenericRepository("Ferrari")
"Volvo": Use Engine with GenericRepository("Volvo")
I want to resolve:
Get "Ferrari" Car
Get "Ferrari" Repository
How can I achieve this requirement by Autofac?

Related

Why Dependency Injection doesn't know about my repo?

I have a weird situation. I need to use Entity Framework 6.2 for my .net core app.
An ordinary Controller
public class SampleApiController : BaseController
{
// use _repo and other stuff
}
Base Controller
public class BaseController : Controller
{
protected IRepo_repository;
public BaseController(IRepo repository)
{
_repository = repository;
}
public BaseController() : this(null)
{
}
}
App DBContext
public class SampleContext : DbContext
{
public SampleContext(string connectionString)
:base(connectionString)
{
try
{
this.Database.Log = (s) => System.Diagnostics.Debug.Write(s);
}
catch (Exception e)
{
//CurrentLogger.Log.Error(e);
}
}
public DbSet<Test1> Test1s { get; set; }
public DbSet<Test2> Test2s { get; set; }
}
Repository interface
public interface IRepo
{
// methods definition
}
Repository class
public interface Repo : IRepo
{
// methods implementation
}
Startup.cs -> ConfigureServices method
services.AddScoped<SampleContext>((s) => new SampleContext(configuration["ConnectionStrings:SampleApp"]));
services.AddScoped<IRepo, Repo>();
In this picture you could see that repository param is empty... not initialized with Repo instance... (!!! In this picture IRepo is IRepositoryBase)
Solution !
As CodeNotFound and Riscie said in comments, the problem was that BaseController was initialized with null... Thanks guys!
Try this:
Repository interface
public interface IRepo
{
// methods definition
}
Repository class
I have changed this from interface to class and made it implement the IRepo Interface
public class Repo : IRepo
{
// methods implementation
}
Edit: Also remove the second constructor
public class BaseController : Controller
{
protected IRepo_repository;
public BaseController(IRepo repository)
{
_repository = repository;
}
//second constructor most likely introduces the problem
}
You normally pass IRepo from SampleApiController to BaseController.
Base on my understanding, you do not need no argument constructor in BaseController. If so, you might want to remove it to prevent _repository being null.
public class SampleApiController : BaseController
{
public SampleApiController(IRepo repository)
: base(repository)
{
}
}
public class BaseController : Controller
{
protected IRepo _repository;
public BaseController(IRepo repository)
{
_repository = repository;
}
/*public BaseController() : this(null)
{
}*/
}
public interface IRepo
{
// methods definition
}

Set provider name manually in DbContext constructor

I need to store the connection string somewhere else other than web.config. Currency I am using a .json file to store it and a static class to read from it.
Here is my data context -
public partial class MyDatabaseContext : DbContext
{
public MyDatabaseContext() : base()
{
Database.Connection.ConnectionString = GlobalConfig.ConnectionString;
}
}
This is GlobalConfig class
public static class GlobalConfig
{
public static string ConnectionString
{
get
{
return "Server=MyServer; Database=MyDb; Integrated Security=SSPI;";
}
}
}
I need to assign provider name System.Data.SqlClient to the context. How can I do that here?
Its possible to load DbConfiguration class at the DbContext Constructor
Define a class that implement DbConfiguration (Oracle in this case)
public class AppDbConfiguration : DbConfiguration
{
public AppDbConfiguration()
{
// use code based configuration
SetDefaultConnectionFactory(new OracleConnectionFactory());
SetProviderServices("Oracle.ManagedDataAccess.Client",EFOracleProviderServices.Instance);
SetProviderFactory("Oracle.ManagedDataAccess.Client", new OracleClientFactory());
}
}
Use it in your context
public AppDbContext(string connString) : base(connString)
{
DbConfiguration.SetConfiguration(new AppDbConfiguration());
}
Don't forget to install the currect Package for your provider (in this example its ODP.net from nuget package manager)

How to Register a conventional Interface in Autofac

I have an autofac DI in my project.
I want to expose an interface by conventional which all other interfaces of my project will inherit from. Is it possible to automatically register the components of the inherited interfaces at start up level? For example:
Public interface IConvetionInterface {}
public interface IImplementationA:IConvetionInterface
{
public void DoSomethingA();
}
public interface IImplementationB:IConvetionInterface
{
public void DoSomethingB();
}
Injecting through constructor;
public class ConsumerA
{
private readonly IImplementationA _a;
public DealerRepository(IImplementationA A)
{
_a= A;
}
public Act()
{
_a.DoSomethingA();
}
}
How do I register IConvetionInterface to make all its dependencies resolve in Autofac.
I have been able to come up with this solution by using autofac Assembly Scanning Configuration as provided in their documentation page Autofac Documentation Page
I have an open generic interface
public interface IRepository<TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey>
{ }
Implemented by
public class Repository<TEntity, TPrimaryKey> : RepositoryBase<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>{}
Then, I created an empty interface
public interface IConventionDependency
{
}
This method was called to register my components at startup level:
public static void RegisterAPSComponents(ContainerBuilder builder)
{
builder.RegisterType<APSContext>().InstancePerRequest();
builder.RegisterGeneric(typeof(Repository<,>)).As(typeof(IRepository<,>)).InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(IConventionDependency).Assembly).AssignableTo<IConventionDependency>().As<IConventionDependency>().AsImplementedInterfaces().AsSelf().InstancePerLifetimeScope();
}
By the above registration, any interface that inherits from IConventionDependency will be registered automatically in the container.
example:
create an interface:
public interface IDealerRepository : IConventionDependency
{
List<Dealers> GetDealers();
}
then Implement the interface :
public class DealerRepository : IDealerRepository
{
private readonly IRepository<VTBDealer, int> _repository;
public DealerRepository(IRepository<VTBDealer, int> repository)
{
_repository = repository;
}
public List<Dealers> GetDealers()
{
return _repository.GetAllList().MapTo<List<Dealers>>();
}
}
in conclusion, without explicitly registering IDealerRepository, it gets resolved in MVC Controller constructor.

MvvmCross: IoC with Decorator pattern, two implementations of the same interface

I'd like to implement the Decorator pattern in one of my Mvx projects. That is, I'd like to have two implementations of the same interface: one implementation that is available to all of the calling code, and another implementation that is injected into the first implementation.
public interface IExample
{
void DoStuff();
}
public class DecoratorImplementation : IExample
{
private IExample _innerExample;
public Implementation1(IExample innerExample)
{
_innerExample = innerExample;
}
public void DoStuff()
{
// Do other stuff...
_innerExample.DoStuff();
}
}
public class RegularImplementation : IExample
{
public void DoStuff()
{
// Do some stuff...
}
}
Is it possible to wire up the MvvmCross IoC container to register IExample with a DecoratorImplementation containing a RegularImplementation?
It depends.
If DecoratorImplementation is a Singleton, then you could do something like:
Mvx.RegisterSingleton<IExample>(new DecoratorImplementation(new RegularImplementation()));
Then calls to Mvx.Resolve<IExample>() will return the instance of DecoratorImplementation.
However, if you need a new instance, unfortunately the MvvmCross IoC Container doesn't support that. It would be nice if you could do something like:
Mvx.RegisterType<IExample>(() => new DecoratorImplementation(new RegularImplementation()));
Where you'd pass in a lambda expression to create a new instance, similar to StructureMap's ConstructedBy.
Anyway, you may need to create a Factory class to return an instance.
public interface IExampleFactory
{
IExample CreateExample();
}
public class ExampleFactory : IExampleFactory
{
public IExample CreateExample()
{
return new DecoratorImplementation(new RegularImplementation());
}
}
Mvx.RegisterSingleton<IExampleFactory>(new ExampleFactory());
public class SomeClass
{
private IExample _example;
public SomeClass(IExampleFactory factory)
{
_example = factory.CreateExample();
}
}

Picking Up Repositories With Structuremap

I am not sure how to use StructureMap to scan for all repositories in a particular namespace. Most repositories take the form:
namespace CPOP.Infrastructure.Repositories
{
public class PatientRepository : LinqRepository<Patient>, IPatientRepository
{
}
}
namespace CPOP.Infrastructure.Repositories
{
public class LinqRepository<T> : Repository<T>, ILinqRepository<T>
{
}
}
namespace CPOP.Domain.Contracts.Repositories
{
public interface IPatientRepository : ILinqRepository<Patient>
{
}
}
I tried:
x.Scan(scanner =>
{
scanner.Assembly(Assembly.GetExecutingAssembly());
scanner.ConnectImplementationsToTypesClosing(typeof(ILinqRepository<>));
})
But, it only picks up the LinqRepository class. What's the best way to pick up the various repositories I'll be dumping in there?
And, as per Joshua's reuest, here's an example of use:
namespace CPOP.ApplicationServices
{
public class PatientTasks : IPatientTasks
{
private readonly IPatientRepository _patientRepository;
public PatientTasks(IPatientRepository patientRepository)
{
_patientRepository = patientRepository;
}
public Patient GetPatientById(int patientId)
{
int userId; // get userId from authentication mechanism
return _patientRepository.FindOne(new PatientByIdSpecification(patientId));
}
public IEnumerable<Patient> GetAll()
{
int userId; // get userId from authentication mechanism
return _patientRepository.FindAll();
}
}
}
This can be done with just one line of code in your configuration. Assuming you have this:
Entities:
- Customer
- Order
And have a generic repository model like this:
Repository : IRepository
And have a app services that look like:
public AppService(IRepository<Customer> custRepo, IRepository<Order> orderRepo)
You would have something like this. Notice the bit about using the scanner to hook up your custom repositories.
public class SmRegistry : Registry
{
public SmRegistry()
{
For(typeof (IRepository<>))
.Use(typeof (Repository<>));
//using this will find any custom repos, like CustomerRepository : Repository<Customer>
//Scan(scanner =>
// {
// scanner.TheCallingAssembly();
// scanner.ConnectImplementationsToTypesClosing(typeof (IRepository<>));
// });
}
}
Assuming your Repositories are defined in some other assembly from your application, you can use Registries to hook it all together. Check out this post:
http://blog.coreycoogan.com/2010/05/24/using-structuremap-to-configure-applications-and-components/
Something like:
Assembly ass = Assembly.GetCallingAssembly();
Container.Configure(x => x.Scan(scan =>
{
scan.Assembly(ass);
scan.LookForRegistries();
}));
Then the Registry class:
public sealed class MyRegistry : Registry
{
...