I am learning about best practices in MVC2 and I am knocking off a copy of the "Who Can Help Me" project (http://whocanhelpme.codeplex.com/) off Codeplex. In it, they use Castle Windsor for their DI container. One "learning" task I am trying to do is convert this subsystem in this project to use StructureMap.
Basically, at Application_Start(), the code news up a Windsor container. Then, it goes through multiple assemblies, using MEF, in ComponentRegistrar.cs:
public static class ComponentRegistrar
{
public static void Register(IContainer container)
{
var catalog = new CatalogBuilder()
.ForAssembly(typeof(IComponentRegistrarMarker).Assembly)
.ForMvcAssembly(Assembly.GetExecutingAssembly())
.ForMvcAssembliesInDirectory(HttpRuntime.BinDirectory, "CPOP*.dll") // Won't work in Partial trust
.Build();
var compositionContainer = new CompositionContainer(catalog);
compositionContainer
.GetExports<IComponentRegistrar>()
.Each(e => e.Value.Register(container));
}
}
and any class in any assembly that has an IComponentRegistrar interface will get its Register() method run.
For example, the controller registrar's Register() method implementation basically is:
public void Register(IContainer container)
{
Assembly.GetAssembly(typeof(ControllersRegistrarMarker)).GetExportedTypes()
.Where(IsController)
.Each(type => container.AddComponentLifeStyle(
type.Name.ToLower(),
type,
LifestyleType.Transient ));
}
private static bool IsController(Type type)
{
return typeof(IController).IsAssignableFrom(type);
}
Hopefully, I am not butchering WCHM too much. I am wondering how does one do this with StructureMap? I'm assuming that I use Configure() since Initialize() resets the container on each call? Or, is tit a completely different approach? Do I need the MEF-based assembly scan, used to find all registrars and run each Register(), or is there something similar in StructureMap's Scan()?
Have a look at StructureMap's registries (http://structuremap.github.com/structuremap/RegistryDSL.htm). To control the lifecycle use something like:
For<ISomething>().Use<Something>().LifecycleIs(new SingletonLifecycle());
(Transient is the default).
When you bootstrap the container you can say:
ObjectFactory.Initialize(c => c.Scan(s => {
s.WithDefaultConventions();
s.LookForRegistries();
}
Feel dirty, answering my own question, but I did the following:
public class ControllerRegistrar : IComponentRegistrar
{
public void Register(IContainer container)
{
container.Configure(x =>
{
x.Scan(scanner =>
{
scanner.Assembly(Assembly.GetExecutingAssembly());
scanner.AddAllTypesOf<IController>().NameBy(type => type.Name.Replace("Controller", ""));
});
});
}
}
I am not 100% sure this is right, but it works. Pulled it primarily from the "Registering Types by Name" section of this StructureMap doc page.
Related
According to https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection the service provider should not be used until AFTER the startup has completed running. Indeed, if I try to get a registered service it will fail.
Example:
[assembly: FunctionsStartup(typeof(Startup))]
namespace Fx {
public sealed class Startup : FunctionsStartup {
public override void Configure(IFunctionsHostBuilder builder) {
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddEnvironmentVariables();
var configuration = configurationBuilder.Build();
builder.Services.AddInfrastructure(configuration);
builder.Services.AddApplication();
var serviceProvider = builder.Services.BuildServiceProvider();
DependencyInjection.AddDatabase(serviceProvider).GetAwaiter().GetResult();
}
}
}
public static class DependencyInjection {
public static async Task AddDatabase(IServiceProvider services) {
using var scope = services.CreateScope();
var serviceProvider = scope.ServiceProvider;
var context = serviceProvider.GetRequiredService<ApplicationDbContext>();
//Error generated here
if (context.Database.IsSqlServer()) {
await context.Database.MigrateAsync();
}
await ApplicationDbContextSeed.SeedSamplePersonnelDataAsync(context);
}
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration) {
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
return services;
}
}
This produces the following error
Microsoft.EntityFrameworkCore: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Is there a good option for migrating and seeding during startup?
The easiest way I found to run code after startup was by registering a custom IWebJobsStartup by using the WebJobsStartupAttribute (the FunctionsStartupAttribute actually also inherits from this attribute). In the WebJobsStartup class you'll need to register your extension using the AddExtension where you are able to use dependency injection and seed your database. My code:
[assembly: WebJobsStartup(typeof(DbInitializationService), "DbSeeder")]
namespace Our.Database.Seeder
{
public class DbInitializationService : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.AddExtension<DbSeedConfigProvider>();
}
}
[Extension("DbSeed")]
internal class DbSeedConfigProvider : IExtensionConfigProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public DbSeedConfigProvider(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void Initialize(ExtensionConfigContext context)
{
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetService<YourDbContext>();
dbContext.Database.EnsureCreated();
// Further DB seeding, etc.
}
}
}
According to your code, I assume that you're building something aligned to the CleanArchitecture Repository on Github. https://github.com/jasontaylordev/CleanArchitecture
The main difference between this repo and your apporach, is that you're obviously not using ASP.NET, which is not a problem at all, but requires a little bit more configuration work.
The article already mentioned (https://markheath.net/post/ef-core-di-azure-functions) refers another blogpost (https://dev.to/azure/using-entity-framework-with-azure-functions-50aa), which briefly explains that EntityFramework Migrations are not capable of auto-discovering your migrations in an Azure Function. Therefore, you need to implement an instance of IDesignTimeDbContextFactory. I also stumbled upon it in the microsoft docs:
https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-a-design-time-factory
You could for example place it inside your Infrastructure\Persistence\Configurations folder. (Once again, I'm only assuming that you're following the CleanArchitecture repo structure)
DI in AZURE Functions
Caveats
A series of registration steps run before and after the runtime processes the startup class. Therefore, keep in mind the following items:
The startup class is meant for only setup and registration. Avoid using services registered at startup during the startup process. For instance, don't try to log a message in a logger that is being registered during startup. This point of the registration process is too early for your services to be available for use. After the Configure method is run, the Functions runtime continues to register additional dependencies, which can affect how your services operate.
The dependency injection container only holds explicitly registered types. The only services available as injectable types are what are setup in the Configure method. As a result, Functions-specific types like BindingContext and ExecutionContext aren't available during setup or as injectable types
I have some code that registers types with strongly typed metadata. It looks something like this:
class Foo { }
public interface IFooMetadata
{
int Position { get; }
}
[TestFixture]
public class MyTestFixture
{
[Test]
public void Test()
{
var builder = new ContainerBuilder();
builder.RegisterType<Foo>()
.AsSelf()
.WithMetadata<IFooMetadata>(m => m.For(x => x.Position, 1));
using (var container = builder.Build())
{
var fooWithMeta = container.Resolve<Meta<Foo, IFooMetadata>>();
}
}
}
I've just updated my code to use the current version of Autofac (3.0.2) and it seems that any types that are registered this way cannot be resolved (ComponentNotRegisteredException).
I wrote the above test and it passes with Autofac 2.6.1.841, but throws a ComponentNotRegisteredException in 3.0.2.
Am I missing something? Is Meta<T, TMetadata> still the way to go, or is there a new way to do this?
There are a lots of breaking changes in Autofac 3.0.
So the Interface Based Metadata support was moved out from the Autofac core to the MEF integration package.
So you need to get the Autofac.Mef package and call the RegisterMetadataRegistrationSources() extension method on the builder as described in the documentation.
var builder = new ContainerBuilder();
builder.RegisterMetadataRegistrationSources()
builder.RegisterType<Foo>()
.AsSelf()
.WithMetadata<IFooMetadata>(m => m.For(x => x.Position, 1));
You can read about more this breaking change in this article: Autofac 3.0 Beta packages available on NuGet
I have a Service that need inject more than one provider, see below for example. How to use Unity to implement this feature?
public class MyService: IMyService
{
public MyService(IEnumerable<Provider> Providers);
}
I know this is an old question, but maybe this will help someone else that stumbles upon this.
As long as you register the implementations with a specific name, this is possible to easily inject. You will then get all registered implementations.
public class MyService: IMyService
{
public MyService(IProvider[] providers)
{
// Do something with the providers
}
}
Just make sure to inject them as an array. Unity will understand this. And when you register them you can register them as such:
container.RegisterType<IProvider, FooProvider>("Foo");
container.RegisterType<IProvider, BarProvider>("Bar");
One way is to inject the UnityContainer itself, and then resolve all the Providers you need:
public class MyService : IMyService
{
public class MyService(IUnityContainer iocContainer)
{
var providers = iocContainer.ResolveAll<IProvider>();
}
}
The only thing you will need to do is register the UnityContainer with itself somewhere on setup:
unityContainer.Register<IUnityContainer>(unityContainer, new ContainerControllerLifetimeManager());
I'm using Entity Framework Code First. I want to be able to inject a System.Data.Common.DbConnection object when instantiating the context that derives from System.Data.Entity.DbContext. This is so that I can pass different types of connections depending on what environment the code is running in, i.e. use System.Data.SqlClient (SQL Server) in development, System.Data.SQLite when unit testing and something else in production. The pertinent parts of Context looks like this:
public class Context : DbContext
{
public Context(DbConnection dbConnection)
: base(dbConnection, true)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
base.OnModelCreating(modelBuilder);
}
public DbSet<Test> Tests { get; set; }
}
That gives me the following error: The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory. I think this happens during model initialization when Entity Framework apparently feels it needs to new up it's own Context, independent of the IoC pattern I'm trying to achieve. The lack of a default constructor is by design. The IDbContextFactory interface is just as useless - it has to have a default constructor too.
Is Entity Framework Code First completely wedded to the idea of setting up it's config by reading a connectionstring from a config file (or alternatively getting the connectionstring passed directly) or can one work around this?
UPDATE, here's the Windsor config:
container.Register(Component
.For<DbConnection>()
.UsingFactoryMethod(() =>
new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
.LifeStyle.Transient);
container.Register(Component
.For<Context>()
.UsingFactoryMethod(k => new Context(k.Resolve<DbConnection>()))
.LifeStyle.PerWebRequest);
container.Register(Component
.For<IRepository>()
.UsingFactoryMethod(k => new Repository(k.Resolve<Context>()))
.LifeStyle.PerWebRequest);
I'm pretty sure your issue is nothing to do with EF but I'm not really a user of Windsor so i cant tell you for sure what your config issue is. What I have done is to reproduce a similar configuration with ninject which works exactly as you would expect, see below:
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel();
kernel.Bind<DbConnection>().ToMethod((ctx) =>{return new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true");});
kernel.Bind<Context>().ToSelf();//not really needed
kernel.Bind<TestRepository>().ToSelf();//not really needed
kernel.Get<TestRepository>();
}
}
public class Context : DbContext
{
public Context(DbConnection dbConnection)
: base(dbConnection, true){}
public DbSet<Test> Tests { get; set; }
}
public class TestRepository
{
public TestRepository(Context c)
{
c.Tests.Add(new Test());
c.SaveChanges();
var all = c.Tests;
}
}
public class Test
{
public int Id { get; set; }
}
This means that EF isn't trying to do any funkiness with context creation (as a non-empty constructor works fine for me).
From your Windsor config I would expect you need to do something like the following however im not too sure of the exact syntax:
container.Register(Component
.For<DbConnection>()
.UsingFactoryMethod(() =>
new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
.LifeStyle.Transient);
container.Register(Component
.For<Context>()
.ImplementedBySelf()//this probably isn't the correct syntax
.LifeStyle.PerWebRequest);//per request is good, i have some details around why this is good practice if you are interested
container.Register(Component
.For<IRepository>()
.ImplementedBy<ConcreteRepository>()//you arent really calling a method and creating the object yourself you are letting Windsor create the object and sort out the dependancy tree
.LifeStyle.PerWebRequest);
I need to modify an existing web app to use Castle.Windsor as IOC container. It was originally developed with StructureMap.
I am stuck with the following problem.
Lets say I have registered a couple of interfaces and their corresponding implementations:
IFoo -> Foo
IBar -> Bar
Calling container.Resolve<IFoo>() or container.Resolve<IBar>() works just fine. This means that the services are registered correctly.
I have a Web Api class with dependencies on other services, such as IFoo
public class BadRequestErrorHandler : HttpErrorHandler
{
// services
public BadRequestErrorHandler(IFoo foo) {...} // has dependency on IFoo
}
In StructureMap I can call:
var test = ObjectFactory.GetInstance<BadRequestErrorHandler>();
this will resolve the IFoo dependency.
Now this does not work with windsor.
How can this be achieved with windsor?
Thanks!
* EDIT *
I was just able to make it work by explicitely registering the BadRequestErrorHandler.
container.Register(Component.For<BadRequestErrorHandler>());
I am just hoping there is a better way to achieve this, that does not involve registering classes that have dependencies. I have a bunch of them...
* EDIT 2 **
To ease the pain, I added a special method to deal with these concrete types.
public T GetInstanceWithAutoRegister<T>()
{
if (container.Kernel.GetHandler(typeof(T)) == null)
{
container.Register(Component.For<T>());
}
return container.Resolve<T>();
}
public object GetInstanceWithAutoRegister(Type pluginType)
{
if (container.Kernel.GetHandler(pluginType) == null)
{
container.Register(Component.For(pluginType));
}
return container.Resolve(pluginType);
}
not ideal, but at least better than having to explicetly register each type. Hope someone has a better solution
You can achieve what you want by registering an ILazyComponentLoader which is a hook that gets called by Windsor as a "last resort" when a component cannot be resolved.
In your case, the implementation would probably look somewhat like this:
public class JustLetWindsorResolveAllConcreteTypes : ILazyComponentLoader
{
public IRegistration Load(string key, Type service)
{
return Component.For(service);
}
}
-and then it should be registered as such:
container.Register(Component.For<ILazyComponentLoader>()
.ImplementedBy<JustLetWindsorResolveAllConcreteTypes>());
You can read more about it in the docs.