Structuremap syntax in version 2.5.4 - asp.net-mvc

I have just updated to the latest structuremap dll and now my site no longer works at runtime due to deprecated methods in structuremap so I am trying to update my bootstrapper code.
In my bootstrapper class I have rewritten it to:
public class Bootstrapper
{
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize(InitializeStructureMap);
}
private static void InitializeStructureMap(IInitializationExpression x)
{
x.AddRegistry(new DatabaseServiceRegistry());
x.For<IArticleService>().Use<ArticleService>();
x.For<IArticleRepository>().Use<SqlArticleRepository>();
}
}
I have added the registry line as I am using Linq to SQL which is in a seperate project.
This is the code that worked in the older version of StructureMap:
public class DatabaseServiceRegistry : Registry
{
public override void ConfigureStructureMap()
{
ForRequestedType<Database>()
.TheDefaultIs(() => new Database(Settings.Default.server))
.CacheBy(InstanceScope.Hybrid);
}
I think I need to rewrite it to something like this?
public void ConfigureStructureMap()
{
ObjectFactory.Configure(x =>
{
For<Database>().Use(new Database(Settings.Default.server));
});
}
This compiles but then I get a runtime error of:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily MyProject.Data.SqlRepository.Database
What am I doing wrong? I am finding it hard to find documentation that relates to the latest syntax and not referencing deprecated methods :(

You are almost right on with your new 2.5.4 syntax. You are just missing the Hybrid configuration. I tried to reproduce your problem and could not (using trunk or the 2.5.4 release). Here is my successful test.
public class DatabaseServiceRegistry : Registry
{
public const string DefaultSettings = "my settings";
public DatabaseServiceRegistry()
{
For<Database>().HybridHttpOrThreadLocalScoped().Use(new Database(DefaultSettings));
}
}
public class Database
{
public string Settings { get; set; }
public Database(string settings)
{
Settings = settings;
}
}
[TestFixture]
public class Structure_map_configuration
{
[Test]
public void TEST()
{
ObjectFactory.Initialize(cfg =>
{
cfg.AddRegistry<DatabaseServiceRegistry>();
});
ObjectFactory.GetInstance<Database>().Settings.ShouldEqual(DatabaseServiceRegistry.DefaultSettings);
}
}
Is it possible that you have two classes named 'Database' and are configuring the one of them in your registry and a different one in your service location?

Use ObjectFactory.Initialize instead if configure :
ObjectFactory.Initialize(x =>
{
x
.For<IProductsRepository>()
.LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
.Use<SqlProductsRepository>()
.Ctor<string>("connectionString")
.Is(#"Data Source=.\sqlexpress2008;Initial Catalog=SportsStore;Persist Security Info=True;User ID=xxxxx;Password=xxxxxxx");
});
Hope this helps.

Related

Unable to resolve service for type 'Core.Data.CoreContext' while attempting to activate 'Core.Data.Repositories.UnitOfWork'

I have part of WebAPI application that I want to move to separate project as class library.
It is common base structure that almost every app has so idea is to make it easy shareable.
Application type is:
ASP.NET Core Web Application / .NET Framework - ASP.NET Core 2.0 / Web API
What I have done in that direction is created a project named Core and moved those shared elements there, including Base Entities (e.g. User, Settings, etc), CoreContext, UnitOfWork, Generic Repository, BaseRepositories,...
In the Main project of app there are others Entities, AppContext that inherits CoreContext, more Repositories, and all Controllers, ...
I was able to build the app but when starting it get the following error:
InvalidOperationException: Unable to resolve service for type 'Core.Data.CoreContext' while attempting to activate 'Core.Data.Repositories.UnitOfWork'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type
serviceType, Type implementationType, ISet callSiteChain,
ParameterInfo[] parameters, bool throwIfCallSiteNotFound)...
Problem seems to be that UnitOfWork class is in Core project and in Main project is Startup.cs with method ConfigureServices that has services.AddTransient<IUnitOfWork, UnitOfWork>();.
Is this a bug or am I just not configuring it correctly and how could it be achieved, if possible at all?
*Further technical details:
NetCore & EF Core version: 2.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
IDE: Visual Studio 2017 15.3
Operating system: Windows 10
UPDATE: Code Sample
namespace Main
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build();
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddMvc();
var conn = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<AppContext>(options => options.UseSqlServer(conn));
}
}
}
namespace Main.Data
{
public class AppContext : CoreContext
{
...
}
}
-
namespace Core.Data
{
public class UnitOfWork : IUnitOfWork, IDisposable
{
public CoreContext context;
public UnitOfWork(CoreContext context)
{
this.context = context;
}
public T Get<T>() where T : BaseRepository, new()
{
var repository = new T();
repository.Init(context);
return repository;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
public class UnitOfWork<TContext> : IUnitOfWork, IDisposable
where TContext : CoreContext
{
public UnitOfWork(TContext ctx) { ... }
...
}
-
public class AppUnitOfWork : UnitOfWork<AppContext> {
public AppUnitOfWork(AppContext ctx) : base(ctx) { }
}
...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IUnitOfWork, AppUnitOfWork>(); // Note the App prefix
services.AddDbContext<AppContext>(options => options.UseSqlServer(conn)); // Note the App prefix
}
...
}
Solution is from GitHub issue:

Autofac injection to custom Web-Api FilterAttribute

I have a custom ExceptionFilter that logs all uncaught exceptions inside Web-Api controllers. I would like to use Autofac, to inject ILog configurations to it.
My question is how to do so ? Autofac site has almost no explanation on how to do so.
CustomFilter:
public class ApiControllerErrorFilterAttribute : ExceptionFilterAttribute
{
private static readonly ILog log = LogManager.GetLogger("ApiLog");
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
log.Error("Error: ", actionExecutedContext.Exception);
}
}
p.s.
For clarification, I also have a custom Filter for normal controllers and I was able to successfully configure it.
Filter for normal controllers:
public class ControllerErrorFilterAttribute : HandleErrorAttribute
{
public ICustomLogSettings Log { get; set; }
public override void OnException(ExceptionContext filterContext)
{
Log.GetLogger.Error("Error: ", filterContext.Exception);
}
}
Log Configuration:
builder.Register(c => new BaseLog()).As<ICustomLogSettings>().InstancePerRequest();
builder.RegisterFilterProvider();
Some of these examples may help, especially:
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
builder.Register(c => new MyWebApiFilter())
.AsWebApiActionFilterFor<ValuesController>()
.InstancePerApiRequest();
From that, it shows me that you can register a filter that gets resolved just like any other service, this means you should be able to do:
public class ApiControllerErrorFilterAttribute : ExceptionFilterAttribute
{
private readonly ILog _log
public ApiControllerErrorFilterAttribute(ILog log)
{
_log = log;
}
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
_log.Error("Error: ", actionExecutedContext.Exception);
}
}
And then be able to register it like so:
builder.RegisterType<ApiControllerErrorFilterAttribute>()
.AsWebApiActionFilterFor<ValuesController>()
.InstancePerApiRequest();
Then of course, you need to set up registration for resolving ILog, which will be very similar to this part of the wiki.

structuremap nancy bootstrapper

I am trying to boot strap nancyfx with structuremap bootstrapper
https://github.com/NancyFx/Nancy.Bootstrappers.StructureMap
Here is my setup:
protected override void ConfigureApplicationContainer(IContainer container)
{
container.Configure(x =>
{
x.ForSingletonOf<IRazorConfiguration>()
.Use<DefaultRazorConfiguration>();
x.ForSingletonOf<ISessionContainer>().Use<SessionContainer>();
x.For<IRepository>().LifecycleIs(new HttpContextLifecycle()).Use<Repository>();
x.Scan(scanner=>
{
scanner.TheCallingAssembly();
scanner.AddAllTypesOf<IRepository>();
});
});
base.ConfigureApplicationContainer(container);
}
public interface IRepository
{
void Save();
}
public class Repository:IRepository
{
ISessionContainer _session;
public Repository(ISessionContainer container)
{
_session = container;
}
public void Save()
{
}
}
When I use var repo = ObjectFactory.GetInstance<IRepository>();, I get this exception:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily Infrastructure.IRepository, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I'd like to help you get rid of the hack... the source of your problem is the way you are using ObjectFactory. Really you shouldn't be using ObjectFactory to "GetInstance" inside your NancyModule. Instead, you should include IRepository in the constructor of the NancyModule where the repository is needed. Then, Structuremap (which has been wired into the Nancy framework using your bootstrapper) will simple inject the concrete repository into your module when it is instantiated. Here's an example of a NancyModule:
public class ProductModule : NancyModule {
private IRepository _repository;
public ProductModule(IRepository repository) {
_repository = repository;
SetupRoutes();
}
private void SetupRoutes() {
Get["/product/{id}"] = p => {
return _repository.Get<Product>((int)p.id);
};
}
}
Here, the module isn't calling out to the IOC to get a repo... it's already got it. Your bootstrapper makes this possible. Now, you can get rid of the hacky configuration of ObjectFactory.
As some general advice, if you find yourself using "ObjectFactory" to resolve types, you should slap yourself and stop typing. Instead, you should inject the dependency using constructor injection like I show above.
Not sure what happened to the proposed answer, but here is how I ended up resolving this issue.
protected override void ConfigureApplicationContainer(IContainer container)
{
container.Configure(x =>
{
x.ForSingletonOf<IRazorConfiguration>()
.Use<DefaultRazorConfiguration>();
x.ForSingletonOf<ISessionContainer>().Use<SessionContainer>();//Duplicate
x.Scan(scanner=>
{
scanner.TheCallingAssembly();
scanner.AddAllTypesOf<IRepository>();
});
});
ObjectFactory.Configure(x =>
{
x.ForSingletonOf<ISessionContainer>().Use<SessionContainer>();//Duplicate
x.For<IRepository>().Use<Repository>();
});
base.ConfigureApplicationContainer(container);
}
It's a hack but this is the only way I managed to get this to work.

Where to place AutoMapper.CreateMaps?

I'm using AutoMapper in an ASP.NET MVC application. I was told that I should move the AutoMapper.CreateMap elsewhere as they have a lot of overhead. I'm not too sure how to design my application to put these calls in just 1 place.
I have a web layer, service layer and a data layer. Each a project of its own. I use Ninject to DI everything. I'll utilize AutoMapper in both web and service layers.
So what are your setup for AutoMapper's CreateMap? Where do you put it? How do you call it?
Doesn't matter, as long as it's a static class. It's all about convention.
Our convention is that each "layer" (web, services, data) has a single file called AutoMapperXConfiguration.cs, with a single method called Configure(), where X is the layer.
The Configure() method then calls private methods for each area.
Here's an example of our web tier config:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
ConfigureUserMapping();
ConfigurePostMapping();
}
private static void ConfigureUserMapping()
{
Mapper.CreateMap<User,UserViewModel>();
}
// ... etc
}
We create a method for each "aggregate" (User, Post), so things are separated nicely.
Then your Global.asax:
AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc
It's kind of like an "interface of words" - can't enforce it, but you expect it, so you can code (and refactor) if necessary.
EDIT:
Just thought I'd mention that I now use AutoMapper profiles, so the above example becomes:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(new UserProfile());
cfg.AddProfile(new PostProfile());
});
}
}
public class UserProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<User,UserViewModel>();
}
}
Much cleaner/more robust.
You can really put it anywhere as long as your web project references the assembly that it is in. In your situation I would put it in the service layer as that will be accessible by the web layer and the service layer and later if you decide to do a console app or you are doing a unit test project the mapping configuration will be available from those projects as well.
In your Global.asax you will then call the method that sets all of your maps. See below:
File AutoMapperBootStrapper.cs
public static class AutoMapperBootStrapper
{
public static void BootStrap()
{
AutoMapper.CreateMap<Object1, Object2>();
// So on...
}
}
Global.asax on application start
just call
AutoMapperBootStrapper.BootStrap();
Now some people will argue against this method violates some SOLID principles, which they have valid arguments. Here they are for the reading.
Configuring Automapper in Bootstrapper violates Open-Closed Principle?
Update: The approach posted here is no more valid as SelfProfiler has been removed as of AutoMapper v2.
I would take a similar approach as Thoai. But I would use the built-in SelfProfiler<> class to handle the maps, then use the Mapper.SelfConfigure function to initialize.
Using this object as the source:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
And these as the destination:
public class UserViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserWithAgeViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Age { get; set; }
}
You can create these profiles:
public class UserViewModelProfile : SelfProfiler<User,UserViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserViewModel> map)
{
//This maps by convention, so no configuration needed
}
}
public class UserWithAgeViewModelProfile : SelfProfiler<User, UserWithAgeViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserWithAgeViewModel> map)
{
//This map needs a little configuration
map.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Now.Year - s.BirthDate.Year));
}
}
To initialize in your application, create this class
public class AutoMapperConfiguration
{
public static void Initialize()
{
Mapper.Initialize(x=>
{
x.SelfConfigure(typeof (UserViewModel).Assembly);
// add assemblies as necessary
});
}
}
Add this line to your global.asax.cs file: AutoMapperConfiguration.Initialize()
Now you can place your mapping classes where they make sense to you and not worry about one monolithic mapping class.
For those of you who adhere to the following:
using an ioc container
don't like to break open closed for this
don't like a monolithic config file
I did a combo between profiles and leveraging my ioc container:
IoC configuration:
public class Automapper : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
{
Profile[] profiles = k.ResolveAll<Profile>();
Mapper.Initialize(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
profiles.ForEach(k.ReleaseComponent);
return Mapper.Engine;
}));
}
}
Configuration example:
public class TagStatusViewModelMappings : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
}
}
Usage example:
public class TagStatusController : ApiController
{
private readonly IFooService _service;
private readonly IMappingEngine _mapper;
public TagStatusController(IFooService service, IMappingEngine mapper)
{
_service = service;
_mapper = mapper;
}
[Route("")]
public HttpResponseMessage Get()
{
var response = _service.GetTagStatus();
return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response));
}
}
The trade-off is that you have to reference the Mapper by the IMappingEngine interface instead of the static Mapper, but that's a convention I can live with.
All of above solutions provide a static method to call (from app_start or any where) that it should call other methods to configure parts of mapping-configuration. But, if you have a modular application, that modules may plug in and out of application at any time, these solutions does not work. I suggest using WebActivator library that can register some methods to run on app_pre_start and app_post_start any where:
// in MyModule1.dll
public class InitMapInModule1 {
static void Init() {
Mapper.CreateMap<User, UserViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule1), "Init")]
// in MyModule2.dll
public class InitMapInModule2 {
static void Init() {
Mapper.CreateMap<Blog, BlogViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// in MyModule3.dll
public class InitMapInModule3 {
static void Init() {
Mapper.CreateMap<Comment, CommentViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// and in other libraries...
You can install WebActivator via NuGet.
In addition to the best answer, a good way is using Autofac IoC liberary to add some automation. With this you just define your profiles regardless of initiations.
public static class MapperConfig
{
internal static void Configure()
{
var myAssembly = Assembly.GetExecutingAssembly();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(myAssembly)
.Where(t => t.IsSubclassOf(typeof(Profile))).As<Profile>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var profiles = container.Resolve<IEnumerable<Profile>>();
foreach (var profile in profiles)
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(profile);
});
}
}
}
}
and calling this line in Application_Start method:
MapperConfig.Configure();
The above code finds all Profile sub classes and initiate them automatically.
Putting all the mapping logic in 1 location is not a good practice for me. Because the mapping class will be extremely large and very hard to maintain.
I recommend put the mapping stuff together with the ViewModel class in the same cs file. You can easily navigate to the mapping definition you want following this convention. Moreover, while creating the mapping class, you can reference to the ViewModel properties faster since they are in the same file.
So your view model class will look like:
public class UserViewModel
{
public ObjectId Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class UserViewModelMapping : IBootStrapper // Whatever
{
public void Start()
{
Mapper.CreateMap<User, UserViewModel>();
}
}
From new version of AutoMapper using static method Mapper.Map() is deprecated. So you can add MapperConfiguration as static property to MvcApplication (Global.asax.cs) and use it to create instance of Mapper.
App_Start
public class MapperConfig
{
public static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(_ =>
{
_.AddProfile(new FileProfile());
_.AddProfile(new ChartProfile());
});
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
internal static MapperConfiguration MapperConfiguration { get; private set; }
protected void Application_Start()
{
MapperConfiguration = MapperConfig.MapperConfiguration();
...
}
}
BaseController.cs
public class BaseController : Controller
{
//
// GET: /Base/
private IMapper _mapper = null;
protected IMapper Mapper
{
get
{
if (_mapper == null) _mapper = MvcApplication.MapperConfiguration.CreateMapper();
return _mapper;
}
}
}
https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API
For those who are (lost) using:
WebAPI 2
SimpleInjector 3.1
AutoMapper 4.2.1 (With Profiles)
Here's how I managed integrating AutoMapper in the "new way". Also,
a Huge thanks to this answer(and question)
1 - Created a folder in the WebAPI project called "ProfileMappers". In this folder I place all my profiles classes which creates my mappings:
public class EntityToViewModelProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserViewModel>();
}
public override string ProfileName
{
get
{
return this.GetType().Name;
}
}
}
2 - In my App_Start, I have a SimpleInjectorApiInitializer which configures my SimpleInjector container:
public static Container Initialize(HttpConfiguration httpConfig)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
//Register Installers
Register(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
//Verify container
container.Verify();
//Set SimpleInjector as the Dependency Resolver for the API
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
return container;
}
private static void Register(Container container)
{
container.Register<ISingleton, Singleton>(Lifestyle.Singleton);
//Get all my Profiles from the assembly (in my case was the webapi)
var profiles = from t in typeof(SimpleInjectorApiInitializer).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
//add all profiles found to the MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
//Register IMapper instance in the container.
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
//If you need the config for LinqProjections, inject also the config
//container.RegisterSingleton<MapperConfiguration>(config);
}
3 - Startup.cs
//Just call the Initialize method on the SimpleInjector class above
var container = SimpleInjectorApiInitializer.Initialize(configuration);
4 - Then, in your controller just inject as usually a IMapper interface:
private readonly IMapper mapper;
public AccountController( IMapper mapper)
{
this.mapper = mapper;
}
//Using..
var userEntity = mapper.Map<UserViewModel, User>(entity);
For vb.net programmers using the new Version (5.x) of AutoMapper.
Global.asax.vb:
Public Class MvcApplication
Inherits System.Web.HttpApplication
Protected Sub Application_Start()
AutoMapperConfiguration.Configure()
End Sub
End Class
AutoMapperConfiguration:
Imports AutoMapper
Module AutoMapperConfiguration
Public MapperConfiguration As IMapper
Public Sub Configure()
Dim config = New MapperConfiguration(
Sub(cfg)
cfg.AddProfile(New UserProfile())
cfg.AddProfile(New PostProfile())
End Sub)
MapperConfiguration = config.CreateMapper()
End Sub
End Module
Profiles:
Public Class UserProfile
Inherits AutoMapper.Profile
Protected Overrides Sub Configure()
Me.CreateMap(Of User, UserViewModel)()
End Sub
End Class
Mapping:
Dim ViewUser = MapperConfiguration.Map(Of UserViewModel)(User)

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