diff --git a/docs/guide/compilation/frames/frame.md b/docs/guide/compilation/frames/frame.md index ecec0d04..ee20be16 100644 --- a/docs/guide/compilation/frames/frame.md +++ b/docs/guide/compilation/frames/frame.md @@ -49,7 +49,7 @@ a C# `using` block that surrounds the inner code: ```cs public class NoArgCreationFrame : SyncFrame { - public NoArgCreationFrame(Type concreteType) + public NoArgCreationFrame(Type concreteType) { // By creating the variable this way, we're // marking the variable as having been created @@ -80,7 +80,7 @@ public class NoArgCreationFrame : SyncFrame } } ``` -snippet source | anchor +snippet source | anchor ## Creating a Variable within a Frame @@ -99,7 +99,7 @@ public NoArgCreationFrame(Type concreteType) Output = new Variable(concreteType, this); } ``` -snippet source | anchor +snippet source | anchor Otherwise, you could also have written that code like this: @@ -115,7 +115,7 @@ public NoArgCreationFrame(Type concreteType) Output = Create(concreteType); } ``` -snippet source | anchor +snippet source | anchor ## Finding Dependent Variables @@ -131,33 +131,20 @@ public class GetInstanceFrame : SyncFrame, IResolverFrame { private static readonly MethodInfo _resolveMethod = ReflectionHelper.GetMethod(x => x.Resolve(null)); - - - - private Variable _scope; + private readonly string _name; + private Variable _scope; + public GetInstanceFrame(Instance instance) { Variable = new ServiceVariable(instance, this, ServiceDeclaration.ServiceType); - - _name = instance.Name; - } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInstance)}<{Variable.VariableType.FullNameInCode()}>(\"{_name}\");"); - Next?.GenerateCode(method, writer); + _name = instance.Name; } - public override IEnumerable FindVariables(IMethodVariables chain) - { - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; - } - public ServiceVariable Variable { get; } - + public void WriteExpressions(LambdaDefinition definition) { var scope = definition.Scope(); @@ -165,22 +152,32 @@ public class GetInstanceFrame : SyncFrame, IResolverFrame var instance = Variable.Instance; - var @call = Expression.Call(Expression.Constant(instance), _resolveMethod, scope); - var assign = Expression.Assign(expr, Expression.Convert(@call, Variable.VariableType)); + var call = Expression.Call(Expression.Constant(instance), _resolveMethod, scope); + var assign = Expression.Assign(expr, Expression.Convert(call, Variable.VariableType)); definition.Body.Add(assign); - if (Next is IResolverFrame next) - { - next.WriteExpressions(definition); - } - else + if (Next is null) { - throw new InvalidCastException($"{Next.GetType().GetFullName()} does not implement {nameof(IResolverFrame)}"); + throw new InvalidCastException( + $"{typeof(GetInstanceFrame).GetFullName()}.{nameof(Next)} must not be null."); } } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInstance)}<{Variable.VariableType.FullNameInCode()}>(\"{_name}\");"); + Next?.GenerateCode(method, writer); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; + } } ``` -snippet source | anchor +snippet source | anchor When you write a `FindVariables()` method, be sure to keep a reference to any variable you need for later, and return that variable as part of the enumeration from this method. Lamar uses the dependency relationship between frames, the variables they depend on, and the creators of those variables to diff --git a/docs/guide/index.md b/docs/guide/index.md index 6a3cca6b..c1f4943c 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -33,14 +33,14 @@ var container = new Container(x => { // Using StructureMap style registrations x.For().Use(); - + // Using ASP.Net Core DI style registrations x.AddTransient(); - + // and lots more services in all likelihood }); ``` -snippet source | anchor +snippet source | anchor Now, to resolve services from your container: @@ -65,7 +65,7 @@ var clock2 = provider.GetRequiredService(); // Try to resolve a service if it's registered var service2 = provider.GetService(); ``` -snippet source | anchor +snippet source | anchor Definitely note that the old StructureMap style of service resolution is semantically different than ASP.Net Core's DI resolution methods. That's been the cause of much user aggravation over the years. @@ -159,20 +159,26 @@ builder.Host.UseLamar((context, registry) => { // register services using Lamar registry.For().Use(); + + // Add your own Lamar ServiceRegistry collections + // of registrations registry.IncludeRegistry(); - // add the controllers + // discover MVC controllers -- this was problematic + // inside of the UseLamar() method, but is "fixed" in + // Lamar V8 registry.AddControllers(); }); var app = builder.Build(); app.MapControllers(); +// Add Minimal API routes app.MapGet("/", (ITest service) => service.SayHello()); app.Run(); ``` -snippet source | anchor +snippet source | anchor ::: tip diff --git a/docs/guide/ioc/auto-wiring.md b/docs/guide/ioc/auto-wiring.md index 618a1b50..70cfe86e 100644 --- a/docs/guide/ioc/auto-wiring.md +++ b/docs/guide/ioc/auto-wiring.md @@ -18,7 +18,7 @@ public ShippingScreenPresenter(IContainer container) _repository = container.GetInstance(); } ``` -snippet source | anchor +snippet source | anchor Instead of binding `ShippingScreenPresenter` so tightly to Lamar and having to explicitly fetch its dependencies, let's switch @@ -37,7 +37,7 @@ public ShippingScreenPresenter(IShippingService service, IRepository repository) _repository = repository; } ``` -snippet source | anchor +snippet source | anchor As long as a Lamar `Container` knows how to resolve the `IRepository` and @@ -69,5 +69,5 @@ public void ShowBuildPlan() _output.WriteLine(buildPlan); } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guide/ioc/bootstrapping.md b/docs/guide/ioc/bootstrapping.md index eae452a3..ae6a108c 100644 --- a/docs/guide/ioc/bootstrapping.md +++ b/docs/guide/ioc/bootstrapping.md @@ -5,12 +5,9 @@ To configure and bootstrap a Lamar container, you have a couple options. You can ```cs -var container = new Container(x => -{ - x.AddTransient(); -}); +var container = new Container(x => { x.AddTransient(); }); ``` -snippet source | anchor +snippet source | anchor Or pass in a configured `ServiceRegistry` object as shown below: @@ -33,10 +30,9 @@ registry.For() .Use() .Singleton(); - var container = new Container(registry); ``` -snippet source | anchor +snippet source | anchor Lamar's `ServiceRegistry` supports a subset of StructureMap's old `Registry` class and should be used as a replacement when replacing StructureMap with diff --git a/docs/guide/ioc/decorators.md b/docs/guide/ioc/decorators.md index 48eba6f7..9e9e2dfe 100644 --- a/docs/guide/ioc/decorators.md +++ b/docs/guide/ioc/decorators.md @@ -48,7 +48,7 @@ public class WidgetDecorator : IWidget } public IWidget Inner { get; } - + public void DoSomething() { // do something before @@ -57,7 +57,7 @@ public class WidgetDecorator : IWidget } } ``` -snippet source | anchor +snippet source | anchor We can configure Lamar to add a decorator around all other `IWidget` registrations with this syntax: @@ -70,11 +70,11 @@ var container = new Container(_ => // This usage adds the WidgetHolder as a decorator // on all IWidget registrations _.For().DecorateAllWith(); - + // The AWidget type will be decorated w/ // WidgetHolder when you resolve it from the container _.For().Use(); - + _.For().Use(); }); @@ -83,7 +83,7 @@ container.GetInstance() .ShouldBeOfType() .Inner.ShouldBeOfType(); ``` -snippet source | anchor +snippet source | anchor ## Activators @@ -107,18 +107,18 @@ things up like this class: ```cs public class Poller : IPoller { - public void Start() - { - // start the actual polling - } - public void Dispose() { // stop polling } + + public void Start() + { + // start the actual polling + } } ``` -snippet source | anchor +snippet source | anchor When we register the class above with Lamar, we can supply a Lambda function to start up @@ -130,13 +130,13 @@ When we register the class above with Lamar, we can supply a Lambda function to var container = new Container(x => { x.For().Use() - + // This registers an activator on just this // one registration .OnCreation(poller => poller.Start()); }); ``` -snippet source | anchor +snippet source | anchor In the sample above, we registered an activator on one and only one service registration. Lamar @@ -152,7 +152,7 @@ public interface IStartable : IDisposable void Start(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IStartable @@ -162,7 +162,7 @@ public interface IStartable void Start(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IStartable @@ -193,7 +193,7 @@ public class StartablePoller : IPoller, IStartable } } ``` -snippet source | anchor +snippet source | anchor And going back to the `IPoller` registration, we could now do this: @@ -206,15 +206,15 @@ var container = new Container(services => // Remember that Lamar natively understands .Net // DI registrations w/o any adapter services.AddSingleton(); - + // Other registrations that might include other // IStartable types - + services.For() .OnCreationForAll(x => x.Start()); }); ``` -snippet source | anchor +snippet source | anchor The call to `For().OnCreationForAll(Action)` will apply to any registrations of @@ -231,11 +231,10 @@ around in our system at any time with this simple class: ```cs public class StartableTracker { - public List Startables { get; } - = new List(); + public List Startables { get; } = new(); } ``` -snippet source | anchor +snippet source | anchor Now, we'd like our `IStartable` objects to both `Start()` and be tracked by the class above, @@ -247,10 +246,10 @@ so we'll use an activator like this: var container = new Container(services => { services.AddSingleton(); - + // Other registrations that might include other // IStartable types - + services.AddSingleton(); services.For() @@ -263,7 +262,7 @@ var container = new Container(services => }); }); ``` -snippet source | anchor +snippet source | anchor ## Interceptors @@ -303,10 +302,9 @@ public void intercept_a_single_instance() container.GetInstance("no") .ShouldBeOfType(); - } ``` -snippet source | anchor +snippet source | anchor Just like activators, there is the option to only use the original object or the ability diff --git a/docs/guide/ioc/diagnostics/build-plans.md b/docs/guide/ioc/diagnostics/build-plans.md index 8152a408..63c9dd05 100644 --- a/docs/guide/ioc/diagnostics/build-plans.md +++ b/docs/guide/ioc/diagnostics/build-plans.md @@ -28,7 +28,7 @@ var container = new Container(x => Console.WriteLine(container.HowDoIBuild()); ``` -snippet source | anchor +snippet source | anchor This method also provides the same kind of filtering as the [WhatDoIHave](/guide/ioc/diagnostics/what-do-i-have) operation. @@ -52,7 +52,6 @@ container = new Container(x => x.AddSingleton(new ColorRule("red")); x.AddScoped(); - x.For().Use(); @@ -61,7 +60,7 @@ container = new Container(x => x.For().Use(); }); ``` -snippet source | anchor +snippet source | anchor And you have a concrete type like this one: @@ -71,19 +70,19 @@ And you have a concrete type like this one: ```cs public class UsesStuff { - public IWidget Widget { get; } - public IThing Thing { get; } - public IEngine Engine { get; } - public UsesStuff(IWidget widget, IThing thing, IEngine engine) { Widget = widget; Thing = thing; Engine = engine; } + + public IWidget Widget { get; } + public IThing Thing { get; } + public IEngine Engine { get; } } ``` -snippet source | anchor +snippet source | anchor To see what the generated code is to resolve that `UsesStuff` type, we can use the [container diagnostic model](/guide/ioc/diagnostics/using-the-container-model) to access that code for us with this syntax: @@ -93,7 +92,7 @@ To see what the generated code is to resolve that `UsesStuff` type, we can use t ```cs var plan = container.Model.For().Default.DescribeBuildPlan(); ``` -snippet source | anchor +snippet source | anchor Which outputs this lovely looking code below: diff --git a/docs/guide/ioc/diagnostics/index.md b/docs/guide/ioc/diagnostics/index.md index 2b7b81ce..d7f423b7 100644 --- a/docs/guide/ioc/diagnostics/index.md +++ b/docs/guide/ioc/diagnostics/index.md @@ -20,6 +20,10 @@ static Task Main(string[] args) // And the rest of your application's // DI registrations. services.IncludeRegistry(); + + // This one was problematic with oddball type names, + // so it's in our testing + services.AddHttpClient(); }) // Call this method to start your application @@ -28,7 +32,7 @@ static Task Main(string[] args) .RunOaktonCommands(args); } ``` -snippet source | anchor +snippet source | anchor Once the `Lamar.Diagnostics` NuGet is installed to your application and you've opted into Oakton to handle command line options, typing this command at the root of your project will show all the installed commands: diff --git a/docs/guide/ioc/diagnostics/type-scanning.md b/docs/guide/ioc/diagnostics/type-scanning.md index b067b516..ae6377b4 100644 --- a/docs/guide/ioc/diagnostics/type-scanning.md +++ b/docs/guide/ioc/diagnostics/type-scanning.md @@ -50,7 +50,7 @@ var container = new Container(_ => Console.WriteLine(container.WhatDidIScan()); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(_ => @@ -118,7 +118,7 @@ Conventions */ ``` -snippet source | anchor +snippet source | anchor ```cs /* diff --git a/docs/guide/ioc/diagnostics/using-the-container-model.md b/docs/guide/ioc/diagnostics/using-the-container-model.md index d559bb1c..83eb1a89 100644 --- a/docs/guide/ioc/diagnostics/using-the-container-model.md +++ b/docs/guide/ioc/diagnostics/using-the-container-model.md @@ -100,7 +100,7 @@ public interface IStartable : IDisposable void Start(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IStartable @@ -110,7 +110,7 @@ public interface IStartable void Start(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IStartable @@ -128,11 +128,11 @@ We could walk through the entire Lamar model and find every registered instance ```cs -var allStartables = container.Model.GetAllPossible(); -allStartables.ToArray() - .Each(x => x.Start()); +var allStartables = container.Model.GetAllPossible() + .ToArray(); +foreach (var startable in allStartables) startable.Start(); ``` -snippet source | anchor +snippet source | anchor ```cs var allStartables = container.Model.GetAllPossible(); diff --git a/docs/guide/ioc/diagnostics/what-do-i-have.md b/docs/guide/ioc/diagnostics/what-do-i-have.md index d6876c19..28c9d550 100644 --- a/docs/guide/ioc/diagnostics/what-do-i-have.md +++ b/docs/guide/ioc/diagnostics/what-do-i-have.md @@ -10,7 +10,7 @@ var report = container.WhatDoIHave(); Console.WriteLine(report); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(); @@ -42,7 +42,7 @@ var container = new Container(x => x.For().UseIfNone(); }); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(x => @@ -72,7 +72,7 @@ If you were to run the code below against this `Container`: ```cs Console.WriteLine(container.WhatDoIHave()); ``` -snippet source | anchor +snippet source | anchor ```cs Debug.WriteLine(container.WhatDoIHave()); @@ -107,7 +107,7 @@ var byNamespace = container.WhatDoIHave(@namespace: "StructureMap.Testing.Widget // against the Service Type name var byType = container.WhatDoIHave(typeName: "Widget"); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(); diff --git a/docs/guide/ioc/disposing.md b/docs/guide/ioc/disposing.md index 178991a0..08882cf4 100644 --- a/docs/guide/ioc/disposing.md +++ b/docs/guide/ioc/disposing.md @@ -22,7 +22,7 @@ implement both `IDisposable` and `IAsyncDisposable`. It is **not** necessary to // Asynchronously disposing the container await container.DisposeAsync(); ``` -snippet source | anchor +snippet source | anchor The following table explains what method is called on a tracked object when the creating @@ -93,8 +93,6 @@ public void nested_container_disposal() // A transient scoped service _.For().Use(); - - // An AlwaysUnique scoped service _.AddTransient(); @@ -134,7 +132,7 @@ public void nested_container_disposal() singleton.WasDisposed.ShouldBeFalse(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] diff --git a/docs/guide/ioc/generics.md b/docs/guide/ioc/generics.md index 45419852..9bcf6ca9 100644 --- a/docs/guide/ioc/generics.md +++ b/docs/guide/ioc/generics.md @@ -26,7 +26,7 @@ public interface ILogVisualizer string ToHtml(object log); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface ILogVisualizer @@ -56,7 +56,7 @@ var created = new IssueCreated(); // I can get the html representation: var html = visualizer.ToHtml(created); ``` -snippet source | anchor +snippet source | anchor ```cs // Just setting up a Container and ILogVisualizer @@ -66,7 +66,7 @@ var visualizer = container.GetInstance(); var items = logs.Select(visualizer.ToHtml); var html = string.Join("
", items); ``` -snippet source | anchor +snippet source | anchor ```cs // Just setting up a Container and ILogVisualizer @@ -105,7 +105,7 @@ var logs = new object[] new IssueResolved() }; ``` -snippet source | anchor +snippet source | anchor ```cs var logs = new object[] @@ -132,7 +132,7 @@ public interface IVisualizer string ToHtml(TLog log); } ``` -snippet source | anchor +snippet source | anchor Inside of the concrete implementation of `ILogVisualizer` we need to be able to pull out and use the correct `IVisualizer` strategy for a log type. We of course @@ -150,7 +150,7 @@ public class DefaultVisualizer : IVisualizer } } ``` -snippet source | anchor +snippet source | anchor ```cs public class DefaultVisualizer : IVisualizer @@ -178,10 +178,7 @@ Let's say to begin with all we want to do is to always use the `DefaultVisualize [Fact] public void register_open_generic_type() { - var container = new Container(_ => - { - _.For(typeof(IVisualizer<>)).Use(typeof(DefaultVisualizer<>)); - }); + var container = new Container(_ => { _.For(typeof(IVisualizer<>)).Use(typeof(DefaultVisualizer<>)); }); container.GetInstance>() .ShouldBeOfType>(); @@ -190,7 +187,7 @@ public void register_open_generic_type() .ShouldBeOfType>(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -275,7 +272,7 @@ public void generic_defaults() .ShouldBeOfType>(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -332,7 +329,7 @@ public class IssueResolvedVisualizer : IVisualizer } } ``` -snippet source | anchor +snippet source | anchor ```cs public class IssueCreatedVisualizer : IVisualizer @@ -382,11 +379,10 @@ public class VisualizationRegistry : ServiceRegistry x.TheCallingAssembly(); x.ConnectImplementationsToTypesClosing(typeof(IVisualizer<>)); }); - } } ``` -snippet source | anchor +snippet source | anchor ```cs public class VisualizationRegistry : Registry @@ -458,7 +454,7 @@ public void visualization_registry() .ShouldBeOfType>(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] diff --git a/docs/guide/ioc/index.md b/docs/guide/ioc/index.md index fac2c57f..a60f5627 100644 --- a/docs/guide/ioc/index.md +++ b/docs/guide/ioc/index.md @@ -12,7 +12,7 @@ Lamar's `Container` class subclasses another class in Lamar called `Scope` that public class Container : Scope, IContainer, INestedContainer, IServiceScopeFactory, IServiceScope, ISupportRequiredService ``` -snippet source | anchor +snippet source | anchor `Scope` itself directly implements several other ASP.Net Core related interfaces: @@ -20,12 +20,9 @@ public class Container : Scope, IContainer, INestedContainer, IServiceScopeFacto ```cs -public class Scope : IServiceContext -#if NET6_0_OR_GREATER - , IServiceProviderIsService -#endif +public class Scope : IServiceContext, IServiceProviderIsService ``` -snippet source | anchor +snippet source | anchor [IServiceScope](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.iservicescope?view=aspnetcore-2.1), [ISupportRequiredService](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.isupportrequiredservice?view=aspnetcore-2.1), [IServiceScopeFactory](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.iservicescopefactory?view=aspnetcore-2.1) are all ASP.Net Core DI abstractions. diff --git a/docs/guide/ioc/injecting-at-runtime.md b/docs/guide/ioc/injecting-at-runtime.md index bbfba608..5d6176d2 100644 --- a/docs/guide/ioc/injecting-at-runtime.md +++ b/docs/guide/ioc/injecting-at-runtime.md @@ -15,7 +15,7 @@ public class ExecutionContext public Guid Id { get; set; } = Guid.NewGuid(); } ``` -snippet source | anchor +snippet source | anchor We might well have a service in our code that is resolved from a Lamar container that depends on that `ExecutionContext` interface: @@ -25,15 +25,15 @@ We might well have a service in our code that is resolved from a Lamar container ```cs public class ContextUsingService { - public ExecutionContext Context { get; } - public ContextUsingService(ExecutionContext context) { Context = context; } + + public ExecutionContext Context { get; } } ``` -snippet source | anchor +snippet source | anchor The first thing we have to do is make a registration in Lamar **upfront** that lets the container know that `ExecutionContext` is going to be injected @@ -42,12 +42,9 @@ at runtime: ```cs -var container = new Container(_ => -{ - _.Injectable(); -}); +var container = new Container(_ => { _.Injectable(); }); ``` -snippet source | anchor +snippet source | anchor At runtime, we can inject `ExecutionContext` like this: @@ -60,7 +57,7 @@ var context = new ExecutionContext(); var nested = container.GetNestedContainer(); nested.Inject(context); ``` -snippet source | anchor +snippet source | anchor Finally, when we resolve a service that depends on `ExecutionContext` from the nested container @@ -72,5 +69,5 @@ we built above, we can see that it has a reference to our context object: var service = nested.GetInstance(); service.Context.ShouldBeSameAs(context); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guide/ioc/lazy-resolution.md b/docs/guide/ioc/lazy-resolution.md index bc87fa1f..6cd5cb80 100644 --- a/docs/guide/ioc/lazy-resolution.md +++ b/docs/guide/ioc/lazy-resolution.md @@ -29,25 +29,19 @@ public class WidgetLazyUser _widget = widget; } - public IWidget Widget - { - get { return _widget.Value; } - } + public IWidget Widget => _widget.Value; } [Fact] public void lazy_resolution_in_action() { - var container = new Container(_ => - { - _.For().Use(); - }); + var container = new Container(_ => { _.For().Use(); }); container.GetInstance() .Widget.ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs public class WidgetLazyUser @@ -90,10 +84,7 @@ Likewise, you can also declare a dependency on `Func` with very similar mecha [Fact] public void build_a_func_that_returns_a_singleton() { - var container = new Container(x => - { - x.ForSingletonOf().Use(); - }); + var container = new Container(x => { x.ForSingletonOf().Use(); }); var func = container.GetInstance>(); var w1 = func(); @@ -107,7 +98,7 @@ public void build_a_func_that_returns_a_singleton() w2.ShouldBeSameAs(w3); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -159,7 +150,7 @@ public void build_a_func_by_string() func("red").ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -199,20 +190,17 @@ public class Thing1 _thing2 = thing2; } - public Thing2 Thing2 - { - get { return _thing2.Value; } - } + public Thing2 Thing2 => _thing2.Value; } public class Thing2 { - public Thing1 Thing1 { get; set; } - public Thing2(Thing1 thing1) { Thing1 = thing1; } + + public Thing1 Thing1 { get; set; } } [Fact] @@ -223,7 +211,7 @@ public void use_lazy_as_workaround_for_bi_directional_dependency() _.AddSingleton(); _.AddSingleton(); }); - + var thing1 = container.GetInstance(); var thing2 = container.GetInstance(); @@ -231,7 +219,7 @@ public void use_lazy_as_workaround_for_bi_directional_dependency() thing2.Thing1.ShouldBeSameAs(thing1); } ``` -snippet source | anchor +snippet source | anchor ```cs [Singleton] diff --git a/docs/guide/ioc/lifetime.md b/docs/guide/ioc/lifetime.md index 855f4d52..b1ce468f 100644 --- a/docs/guide/ioc/lifetime.md +++ b/docs/guide/ioc/lifetime.md @@ -28,13 +28,13 @@ public class LifetimeRegistry : ServiceRegistry this.AddSingleton(); this.AddScoped(); - + // Lifetimes the old StructureMap way // Transient is the default For().Use(); For().Use().Singleton(); - + // or ForSingletonOf().Use(); @@ -43,5 +43,5 @@ public class LifetimeRegistry : ServiceRegistry } } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guide/ioc/nested-containers.md b/docs/guide/ioc/nested-containers.md index 937f57ab..0d749f9d 100644 --- a/docs/guide/ioc/nested-containers.md +++ b/docs/guide/ioc/nested-containers.md @@ -27,21 +27,21 @@ public void using_nested_containers() var rootService = container.GetInstance(); var nested = container.GetNestedContainer(); - + // Singleton scoped objects are the same nested.GetInstance() .ShouldBeSameAs(rootWidget); - + // Scoped objects are specific to the container var nestedService = nested.GetInstance(); nestedService .ShouldNotBeSameAs(rootService); - + nested.GetInstance() .ShouldBeSameAs(nestedService); } ``` -snippet source | anchor +snippet source | anchor You probably won't directly interact with nested containers, but do note that they are used behind the scenes at runtime of basically every diff --git a/docs/guide/ioc/registration/attributes.md b/docs/guide/ioc/registration/attributes.md index 95d4af8a..ec593070 100644 --- a/docs/guide/ioc/registration/attributes.md +++ b/docs/guide/ioc/registration/attributes.md @@ -8,29 +8,28 @@ That being said, there are plenty of times when simple attribute usage is effect ```cs /// -/// Base class for custom configuration attributes +/// Base class for custom configuration attributes /// public abstract class LamarAttribute : Attribute { /// - /// Make configuration alterations to a single IConfiguredInstance object + /// Make configuration alterations to a single IConfiguredInstance object /// - /// + /// public virtual void Alter(IConfiguredInstance instance) { } /// - /// Make configuration changes to the most generic form of Instance + /// Make configuration changes to the most generic form of Instance /// /// public virtual void Alter(Instance instance) { - } } ``` -snippet source | anchor +snippet source | anchor There's a couple thing to note, here about this new attribute: @@ -46,7 +45,7 @@ Take the new `[Singleton]` attribute shown below: ```cs /// -/// Makes Lamar treat a Type as a singleton in the lifecycle scoping +/// Makes Lamar treat a Type as a singleton in the lifecycle scoping /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] public class SingletonAttribute : LamarAttribute @@ -58,7 +57,7 @@ public class SingletonAttribute : LamarAttribute } } ``` -snippet source | anchor +snippet source | anchor This new attribute can be used on either the service type (typically an interface) or on a concrete type to make an individual type registration be a singleton. You can see the usage on some types below: @@ -71,11 +70,11 @@ public class SingleWidget : IWidget { public void DoSomething() { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } ``` -snippet source | anchor +snippet source | anchor ```cs [Singleton] // ALL Instance's of ITeamCache will be singletons by default diff --git a/docs/guide/ioc/registration/auto-registration-and-conventions.md b/docs/guide/ioc/registration/auto-registration-and-conventions.md index e2204ac4..958fb030 100644 --- a/docs/guide/ioc/registration/auto-registration-and-conventions.md +++ b/docs/guide/ioc/registration/auto-registration-and-conventions.md @@ -36,7 +36,7 @@ public class BasicScanning : ServiceRegistry } } ``` -snippet source | anchor +snippet source | anchor Please note (because I've been asked this several times over the years) that each call to `ServiceRegistry.Scan()` is an entirely atomic operation that has no impact on previous or subsequent calls. @@ -210,7 +210,7 @@ public class BiHolder : IBiHolder } } ``` -snippet source | anchor +snippet source | anchor ## Custom Registration Conventions @@ -230,7 +230,7 @@ public interface IRegistrationConvention void ScanTypes(TypeSet types, ServiceRegistry services); } ``` -snippet source | anchor +snippet source | anchor Let's say that you'd like a custom convention that just registers a concrete type against all the interfaces @@ -261,19 +261,17 @@ public class AllInterfacesConvention : IRegistrationConvention public void ScanTypes(TypeSet types, ServiceRegistry services) { // Only work on concrete types - foreach (var type in types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(x => x.Name == "BusyGuy")) + foreach (var type in types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed) + .Where(x => x.Name == "BusyGuy")) { // Register against all the interfaces implemented // by this concrete class - foreach (var @interface in type.GetInterfaces()) - { - services.AddTransient(@interface, type); - } - - }; - } + foreach (var @interface in type.GetInterfaces()) services.AddTransient(@interface, type); + } + ; + } } [Fact] @@ -299,7 +297,7 @@ public void use_custom_registration_convention() container.GetInstance().ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IFoo @@ -369,13 +367,21 @@ the I[Something]/[Something] naming convention as shown in this sample: ```cs -public interface ISpaceship { } +public interface ISpaceship +{ +} -public class Spaceship : ISpaceship { } +public class Spaceship : ISpaceship +{ +} -public interface IRocket { } +public interface IRocket +{ +} -public class Rocket : IRocket { } +public class Rocket : IRocket +{ +} [Fact] public void default_scanning_in_action() @@ -393,7 +399,7 @@ public void default_scanning_in_action() container.GetInstance().ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface ISpaceship { } @@ -433,16 +439,16 @@ var container = new Container(_ => _.Scan(x => { x.Assembly("Lamar.Testing"); - + // This is the default, add all discovered registrations // regardless of existing registrations x.WithDefaultConventions(OverwriteBehavior.Always); - + // Do not add any registrations if the *ServiceType* // is already registered. This will prevent the scanning // from overwriting existing default registrations x.WithDefaultConventions(OverwriteBehavior.Never); - + // Only add new ImplementationType registrations for // the ServiceType. This will prevent duplicate concrete // types for the same ServiceType being registered by the @@ -451,7 +457,7 @@ var container = new Container(_ => }); }); ``` -snippet source | anchor +snippet source | anchor ::: tip INFO @@ -468,16 +474,16 @@ var container = new Container(_ => _.Scan(x => { x.Assembly("Lamar.Testing"); - + // Use Scoped as the lifetime x.WithDefaultConventions(ServiceLifetime.Scoped); - + // Mix and match with override behavior x.WithDefaultConventions(OverwriteBehavior.Never, ServiceLifetime.Singleton); }); }); ``` -snippet source | anchor +snippet source | anchor Otherwise, the default registration will be `Lifetime.Transient`. @@ -489,9 +495,13 @@ To tell Lamar to automatically register any interface that only has one concrete ```cs -public interface ISong { } +public interface ISong +{ +} -public class TheOnlySong : ISong { } +public class TheOnlySong : ISong +{ +} [Fact] public void only_implementation() @@ -509,7 +519,7 @@ public void only_implementation() .ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface ISong { } @@ -542,13 +552,21 @@ To add all concrete types that can be cast to a named service type, use this syn ```cs -public interface IFantasySeries { } +public interface IFantasySeries +{ +} -public class WheelOfTime : IFantasySeries { } +public class WheelOfTime : IFantasySeries +{ +} -public class GameOfThrones : IFantasySeries { } +public class GameOfThrones : IFantasySeries +{ +} -public class BlackCompany : IFantasySeries { } +public class BlackCompany : IFantasySeries +{ +} [Fact] public void register_all_types_of_an_interface() @@ -577,7 +595,7 @@ public void register_all_types_of_an_interface() container.GetInstance("blackcompany").ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IFantasySeries { } diff --git a/docs/guide/ioc/registration/changing-configuration-at-runtime.md b/docs/guide/ioc/registration/changing-configuration-at-runtime.md index 731aa511..0390f9ab 100644 --- a/docs/guide/ioc/registration/changing-configuration-at-runtime.md +++ b/docs/guide/ioc/registration/changing-configuration-at-runtime.md @@ -15,12 +15,12 @@ plans for existing registrations to accommodate changes here. public void add_all_new_services() { var container = new Container(_ => { _.AddTransient(); }); - + container.Configure(_ => _.AddTransient()); container.GetInstance() .ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guide/ioc/registration/configured-instance.md b/docs/guide/ioc/registration/configured-instance.md index 33b1bd5d..c2fb23b5 100644 --- a/docs/guide/ioc/registration/configured-instance.md +++ b/docs/guide/ioc/registration/configured-instance.md @@ -8,30 +8,34 @@ public interface IConfiguredInstance { /// - /// The constructor function that this registration is going to use to - /// construct the object + /// The constructor function that this registration is going to use to + /// construct the object /// ConstructorInfo Constructor { get; set; } - + /// - /// The service type that you can request. This would normally be an interface or other - /// abstraction + /// The service type that you can request. This would normally be an interface or other + /// abstraction /// Type ServiceType { get; } - + /// - /// The actual, concrete type + /// The actual, concrete type /// Type ImplementationType { get; } - - + ServiceLifetime Lifetime { get; set; } - + /// - /// The instance name for requesting this object by name + /// The instance name for requesting this object by name /// string Name { get; set; } + /// + /// Directly add or interrogate the inline dependencies for this instance + /// + IReadOnlyList InlineDependencies { get; } + /// /// Inline definition of a constructor dependency. Select the constructor argument by type and constructor name. /// Use this method if there is more than one constructor arguments of the same type @@ -40,20 +44,15 @@ public interface IConfiguredInstance /// /// DependencyExpression Ctor(string constructorArg = null); - - /// - /// Directly add or interrogate the inline dependencies for this instance - /// - IReadOnlyList InlineDependencies { get; } /// - /// Adds an inline dependency + /// Adds an inline dependency /// /// void AddInline(Instance instance); } ``` -snippet source | anchor +snippet source | anchor ## Changing the Instance Lifecycle diff --git a/docs/guide/ioc/registration/constructor-selection.md b/docs/guide/ioc/registration/constructor-selection.md index dd62c8c2..bf4aefc8 100644 --- a/docs/guide/ioc/registration/constructor-selection.md +++ b/docs/guide/ioc/registration/constructor-selection.md @@ -60,8 +60,6 @@ You can see this behavior shown below: ```cs public class DbContext { - public string ConnectionString { get; set; } - public DbContext(string connectionString) { ConnectionString = connectionString; @@ -70,6 +68,8 @@ public class DbContext public DbContext() : this("default value") { } + + public string ConnectionString { get; set; } } [Fact] @@ -93,7 +93,7 @@ public void should_use_greediest_ctor_that_has_all_of_simple_dependencies() .ConnectionString.ShouldBe("not the default"); } ``` -snippet source | anchor +snippet source | anchor ```cs public class DbContext @@ -149,12 +149,12 @@ public class Thingie CorrectCtorWasUsed = true; } - public bool CorrectCtorWasUsed { get; set; } - public Thingie(IWidget widget, IService service) { Assert.True(false, "I should not have been called"); } + + public bool CorrectCtorWasUsed { get; set; } } [Fact] @@ -177,7 +177,7 @@ public void override_the_constructor_selection() .ShouldBeTrue(); } ``` -snippet source | anchor +snippet source | anchor ```cs public class Thingie @@ -236,12 +236,12 @@ public class AttributedThing CorrectCtorWasUsed = true; } - public bool CorrectCtorWasUsed { get; set; } - public AttributedThing(IWidget widget, IService service) { Assert.True(false, "I should not have been called"); } + + public bool CorrectCtorWasUsed { get; set; } } [Fact] @@ -254,7 +254,7 @@ public void select_constructor_by_attribute() .ShouldBeTrue(); } ``` -snippet source | anchor +snippet source | anchor ```cs public class AttributedThing diff --git a/docs/guide/ioc/registration/index.md b/docs/guide/ioc/registration/index.md index 82eb6196..49fdd418 100644 --- a/docs/guide/ioc/registration/index.md +++ b/docs/guide/ioc/registration/index.md @@ -23,15 +23,15 @@ public interface IFoo public class Foo : IFoo { - public IBar Bar { get; private set; } - public Foo(IBar bar) { Bar = bar; } + + public IBar Bar { get; } } ``` -snippet source | anchor +snippet source | anchor A simple configuration of a Lamar Container might then be: @@ -76,7 +76,7 @@ public class FooBarRegistry : ServiceRegistry } } ``` -snippet source | anchor +snippet source | anchor When you set up a `Container` , you need to simply direct the `Container` to use the configuration in that `ServiceRegistry` class. diff --git a/docs/guide/ioc/registration/inline-dependencies.md b/docs/guide/ioc/registration/inline-dependencies.md index c49f5910..00950b31 100644 --- a/docs/guide/ioc/registration/inline-dependencies.md +++ b/docs/guide/ioc/registration/inline-dependencies.md @@ -45,7 +45,7 @@ public void inline_usage_of_primitive_constructor_argument() .Color.ShouldBe("Red"); } ``` -snippet source | anchor +snippet source | anchor ## Event Condition Action Rules @@ -76,7 +76,7 @@ public interface IEventRule void ProcessEvent(SomeEvent @event); } ``` -snippet source | anchor +snippet source | anchor Now, let's move on to seeing how we could use inline dependency configuration to register new rules. @@ -90,8 +90,8 @@ First off, let's say that we have a `SimpleRule` that takes a single condition a ```cs public class SimpleRule : IEventRule { - private readonly ICondition _condition; private readonly IAction _action; + private readonly ICondition _condition; public SimpleRule(ICondition condition, IAction action) { @@ -108,7 +108,7 @@ public class SimpleRule : IEventRule } } ``` -snippet source | anchor +snippet source | anchor Now, since `SimpleRule` has only a single dependency on both `IAction` and `ICondition`, we can create new rules by registering new Instance's of `SimpleRule` with different combinations of its dependencies: @@ -136,7 +136,6 @@ public class InlineCtorArgs : ServiceRegistry // Pass in your own Instance object For().Use() .Ctor().Is(new MySpecialActionInstance()); - } public class BigCondition : ICondition @@ -174,7 +173,7 @@ public class InlineCtorArgs : ServiceRegistry } } ``` -snippet source | anchor +snippet source | anchor The inline dependency configuration using the `Ctor<>().Is()` syntax supports all the common Lamar configuration options: define by type, by lambdas, by value, or if you really want to risk severe eye strain, you can use your own Instance objects and define the configuration of your dependency's dependencies. @@ -188,9 +187,9 @@ If for some reason you need to specify an inline constructor argument dependency ```cs public class DualConditionRule : IEventRule { + private readonly IAction _action; private readonly ICondition _first; private readonly ICondition _second; - private readonly IAction _action; public DualConditionRule(ICondition first, ICondition second, IAction action) { @@ -220,7 +219,7 @@ public class DualConditionRuleRegistry : ServiceRegistry } } ``` -snippet source | anchor +snippet source | anchor ## Setter Dependencies @@ -253,11 +252,10 @@ public class RuleWithSettersRegistry : ServiceRegistry // or if you need to specify the property name .Setter("Action").Is(); - } } ``` -snippet source | anchor +snippet source | anchor ::: tip INFO @@ -308,21 +306,17 @@ public class Action1 : IAction public class EventRule : IEventRule { - private readonly string _name; - private readonly ICondition _condition; private readonly IAction _action; + private readonly ICondition _condition; public EventRule(string name, ICondition condition, IAction action) { - _name = name; + Name = name; _condition = condition; _action = action; } - public string Name - { - get { return _name; } - } + public string Name { get; } public void ProcessEvent(TEvent @event) { @@ -333,7 +327,7 @@ public class EventRule : IEventRule } } ``` -snippet source | anchor +snippet source | anchor It's frequently useful to explicitly configure all the elements for an enumerable argument (arrays, IEnumerable, or IList). @@ -344,8 +338,8 @@ Lamar provides this syntax to do just that: ```cs public class BigRule : IEventRule { - private readonly IEnumerable _conditions; private readonly IEnumerable _actions; + private readonly IEnumerable _conditions; public BigRule(IEnumerable conditions, IEnumerable actions) { @@ -357,10 +351,10 @@ public class BigRule : IEventRule { if (_conditions.Any(x => x.Matches(@event))) { - _actions.Each(x => x.PerformWork(@event)); + foreach (var action in _actions) action.PerformWork(@event); } } } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guide/ioc/registration/overrides.md b/docs/guide/ioc/registration/overrides.md index e22fcbe7..89079b41 100644 --- a/docs/guide/ioc/registration/overrides.md +++ b/docs/guide/ioc/registration/overrides.md @@ -37,10 +37,7 @@ public void sample_usage_of_overrides() .CreateHostBuilder(Array.Empty()) // This is our chance to make service overrides - .OverrideServices(s => - { - s.For().Use(); - }); + .OverrideServices(s => { s.For().Use(); }); using var host = builder.Build(); @@ -48,7 +45,7 @@ public void sample_usage_of_overrides() .ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor In the code above, the lambda passed into the `OverrideServices()` method is executed in diff --git a/docs/guide/ioc/registration/policies.md b/docs/guide/ioc/registration/policies.md index 5eb053d9..87b412ff 100644 --- a/docs/guide/ioc/registration/policies.md +++ b/docs/guide/ioc/registration/policies.md @@ -26,7 +26,7 @@ public interface IFamilyPolicy : ILamarPolicy ServiceFamily Build(Type type, ServiceGraph serviceGraph); } ``` -snippet source | anchor +snippet source | anchor Internally, if you make a request to `IContainer.GetInstance(type)` for a type that the active `Container` does not recognize, StructureMap will next try to apply all the registered `IFamilyPolicy` policies to create a `ServiceFamily` object for that service type that models the registrations for that service type, including the default, additional named instances, interceptors or decorators, and lifecycle rules. @@ -50,11 +50,11 @@ internal class EnumerablePolicy : IFamilyPolicy if (type.IsEnumerable()) { var elementType = type.GetGenericArguments().First(); - + var instanceType = typeof(ListInstance<>).MakeGenericType(elementType); var ctor = instanceType.GetConstructors().Single(); - var instance = ctor.Invoke(new object[]{type}).As(); - + var instance = ctor.Invoke(new object[] { type }).As(); + return new ServiceFamily(type, new IDecoratorPolicy[0], instance); } @@ -62,7 +62,7 @@ internal class EnumerablePolicy : IFamilyPolicy } } ``` -snippet source | anchor +snippet source | anchor The result of `EnumerablePolicy` in action is shown by the acceptance test below: @@ -111,7 +111,7 @@ public class Color public string Name { get; set; } } ``` -snippet source | anchor +snippet source | anchor And you build a policy that auto-resolves registrations for the `Color` service if none previously exist: @@ -123,19 +123,20 @@ public class ColorPolicy : IFamilyPolicy { public ServiceFamily Build(Type type, ServiceGraph serviceGraph) { - if (type != typeof(Color)) return null; - - return new ServiceFamily(type, serviceGraph.DecoratorPolicies, - ObjectInstance.For(new Color{Name = "Red"}).Named("Red"), - ObjectInstance.For(new Color{Name = "Blue"}).Named("Blue"), - ObjectInstance.For(new Color{Name = "Green"}).Named("Green") - - - ); + if (type != typeof(Color)) + { + return null; + } + + return new ServiceFamily(type, serviceGraph.DecoratorPolicies, + ObjectInstance.For(new Color { Name = "Red" }).Named("Red"), + ObjectInstance.For(new Color { Name = "Blue" }).Named("Blue"), + ObjectInstance.For(new Color { Name = "Green" }).Named("Green") + ); } } ``` -snippet source | anchor +snippet source | anchor You can register the new `ColorPolicy` shown above like this: @@ -143,12 +144,9 @@ You can register the new `ColorPolicy` shown above like this: ```cs -var container = Container.For(_ => -{ - _.Policies.OnMissingFamily(); -}); +var container = Container.For(_ => { _.Policies.OnMissingFamily(); }); ``` -snippet source | anchor +snippet source | anchor Internally, Lamar uses this `IFamilyPolicy` feature for its [generic type support](/guide/ioc/generics), the [enumerable type support described as above](/guide/ioc/working-with-enumerable-types), and the [auto registration of concrete types](/guide/ioc/resolving/requesting-a-concrete-type). @@ -161,21 +159,20 @@ Lamar allows you to create conventional build policies with a mechanism for alte ```cs /// -/// Custom policy on Instance construction that is evaluated -/// as part of creating a "build plan" +/// Custom policy on Instance construction that is evaluated +/// as part of creating a "build plan" /// - public interface IInstancePolicy : ILamarPolicy { /// - /// Apply any conventional changes to the configuration - /// of a single Instance + /// Apply any conventional changes to the configuration + /// of a single Instance /// /// void Apply(Instance instance); } ``` -snippet source | anchor +snippet source | anchor These policies are registered as part of the [ServiceRegistry DSL](/guide/ioc/registration/registry-dsl) with the `Policies.Add()` method: @@ -190,7 +187,7 @@ var container = new Container(_ => _.Policies.Add(new MyCustomPolicy()); }); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(_ => @@ -211,7 +208,7 @@ The `Instance` objects will give you access to the types being created, the conf ```cs /// -/// Base class for using policies against IConfiguredInstance registrations +/// Base class for using policies against IConfiguredInstance registrations /// public abstract class ConfiguredInstancePolicy : IInstancePolicy { @@ -226,7 +223,7 @@ public abstract class ConfiguredInstancePolicy : IInstancePolicy protected abstract void apply(IConfiguredInstance instance); } ``` -snippet source | anchor +snippet source | anchor For more information, see: @@ -244,25 +241,25 @@ So let me say upfront that I don't like this approach, but other folks have aske ```cs public class DatabaseUser { - public string ConnectionString { get; set; } - public DatabaseUser(string connectionString) { ConnectionString = connectionString; } + + public string ConnectionString { get; set; } } public class ConnectedThing { - public string ConnectionString { get; set; } - public ConnectedThing(string connectionString) { ConnectionString = connectionString; } + + public string ConnectionString { get; set; } } ``` -snippet source | anchor +snippet source | anchor ```cs public class DatabaseUser @@ -301,7 +298,7 @@ public class ConnectionStringPolicy : ConfiguredInstancePolicy .GetConstructors() .SelectMany(x => x.GetParameters()) .FirstOrDefault(x => x.Name == "connectionString"); - + if (parameter != null) { var connectionString = findConnectionStringFromConfiguration(); @@ -317,7 +314,7 @@ public class ConnectionStringPolicy : ConfiguredInstancePolicy } } ``` -snippet source | anchor +snippet source | anchor ```cs public class ConnectionStringPolicy : ConfiguredInstancePolicy @@ -351,10 +348,7 @@ Now, let's use that policy against the types that need "connectionString" and se [Fact] public void use_the_connection_string_policy() { - var container = new Container(_ => - { - _.Policies.Add(); - }); + var container = new Container(_ => { _.Policies.Add(); }); container.GetInstance() .ConnectionString.ShouldBe("the connection string"); @@ -363,7 +357,7 @@ public void use_the_connection_string_policy() .ConnectionString.ShouldBe("the connection string"); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -396,24 +390,26 @@ To make this concrete, let's say that our data access is all behind an interface ```cs -public interface IDatabase { } +public interface IDatabase +{ +} public class Database : IDatabase { - public string ConnectionString { get; set; } - public Database(string connectionString) { ConnectionString = connectionString; } + public string ConnectionString { get; set; } + public override string ToString() { return string.Format("ConnectionString: {0}", ConnectionString); } } ``` -snippet source | anchor +snippet source | anchor ```cs public interface IDatabase { } @@ -447,19 +443,18 @@ public class InjectDatabaseByName : ConfiguredInstancePolicy { protected override void apply(IConfiguredInstance instance) { - instance.ImplementationType.GetConstructors() + var parameterInfos = instance.ImplementationType.GetConstructors() .SelectMany(x => x.GetParameters()) - .Where(x => x.ParameterType == typeof(IDatabase)) - .Each(param => - { - // Using ReferencedInstance here tells Lamar - // to "use the IDatabase by this name" - instance.Ctor(param.Name).IsNamedInstance(param.Name); - }); + .Where(x => x.ParameterType == typeof(IDatabase)); + + foreach (var param in parameterInfos) + // Using ReferencedInstance here tells Lamar + // to "use the IDatabase by this name" + instance.Ctor(param.Name).IsNamedInstance(param.Name); } } ``` -snippet source | anchor +snippet source | anchor ```cs public class InjectDatabaseByName : ConfiguredInstancePolicy @@ -498,7 +493,7 @@ var container = new Container(_ => _.Policies.Add(); }); ``` -snippet source | anchor +snippet source | anchor ```cs var container = new Container(_ => @@ -552,12 +547,12 @@ public class DoubleDatabaseUser // Watch out for potential conflicts between setters // and ctor params. The easiest thing is to just make // setters private - public IDatabase Green { get; private set; } + public IDatabase Green { get; } - public IDatabase Red { get; private set; } + public IDatabase Red { get; } } ``` -snippet source | anchor +snippet source | anchor ```cs public class BigService @@ -618,7 +613,7 @@ var user = container.GetInstance(); user.Green.As().ConnectionString.ShouldBe("*green*"); user.Red.As().ConnectionString.ShouldBe("*red*"); ``` -snippet source | anchor +snippet source | anchor ```cs // ImportantService should get the "red" database @@ -666,7 +661,7 @@ public class CacheIsSingleton : IInstancePolicy } } ``` -snippet source | anchor +snippet source | anchor ```cs public class CacheIsSingleton : IInstancePolicy @@ -708,10 +703,10 @@ public void set_cache_to_singleton() // Now that the policy has executed, we // can verify that WidgetCache is a SingletonThing container.Model.For().Default - .Lifetime.ShouldBe(ServiceLifetime.Singleton); + .Lifetime.ShouldBe(ServiceLifetime.Singleton); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] diff --git a/docs/guide/ioc/registration/registry-dsl.md b/docs/guide/ioc/registration/registry-dsl.md index 14a312d3..edd31869 100644 --- a/docs/guide/ioc/registration/registry-dsl.md +++ b/docs/guide/ioc/registration/registry-dsl.md @@ -235,7 +235,7 @@ public void when_singleton_both_interfaces_give_same_instance() instanceA.ShouldBeTheSameAs(instanceB); } ``` -snippet source | anchor +snippet source | anchor The same thing works for scoped registrations; using `.Scoped()` in place of `.Singleton()` in the above sample would result in the same instance being returned when resolving any one of the registered interfaces for the duration of the scope. diff --git a/docs/guide/ioc/resolving/get-a-service-by-plugin-type-and-name.md b/docs/guide/ioc/resolving/get-a-service-by-plugin-type-and-name.md index a932dc90..62c8730b 100644 --- a/docs/guide/ioc/resolving/get-a-service-by-plugin-type-and-name.md +++ b/docs/guide/ioc/resolving/get-a-service-by-plugin-type-and-name.md @@ -26,7 +26,7 @@ public void get_a_named_instance() container.GetInstance(typeof(IWidget), "C").ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] @@ -58,4 +58,42 @@ public void get_a_named_instance() While Lamar (and StructureMap before that) has supported the idea of named service registrations in production applications since 2004 (!), .NET finally discovered this usage in .NET 8. Lamar 12.1.0 introduces native support for [keyed services](https://weblogs.asp.net/ricardoperes/net-8-dependency-injection-changes-keyed-services) according to the new .NET standard as shown below: -snippet: sample_adding_keyed_services \ No newline at end of file + + +```cs +[Fact] +public void register_by_name_using_dot_net_core_syntax() +{ + var container = Container.For(services => + { + + services.AddKeyedSingleton("one"); + services.AddKeyedScoped("two", (_, _) => new BWidget()); + services.AddKeyedSingleton("three", new CWidget()); + + services.AddKeyedSingleton("C1"); + services.AddKeyedSingleton("C2"); + services.AddKeyedSingleton("C3"); + }); + + container.GetInstance("one").ShouldBeOfType(); + container.GetKeyedService("one").ShouldBeOfType(); + + container.GetInstance("two").ShouldBeOfType(); + container.GetKeyedService("two").ShouldBeOfType(); + + container.GetInstance("three").ShouldBeOfType(); + container.GetKeyedService("three").ShouldBeOfType(); + + container.GetInstance("C1").ShouldBeOfType(); + container.GetKeyedService("C2").ShouldBeOfType(); + + container.GetKeyedService("C2") + .ShouldBeSameAs(container.GetKeyedService("C2")); + + container.GetKeyedService("C2") + .ShouldNotBeSameAs(container.GetKeyedService("C3")); +} +``` +snippet source | anchor + diff --git a/docs/guide/ioc/resolving/get-a-service-by-service-type.md b/docs/guide/ioc/resolving/get-a-service-by-service-type.md index e1c0db0f..3659b153 100644 --- a/docs/guide/ioc/resolving/get-a-service-by-service-type.md +++ b/docs/guide/ioc/resolving/get-a-service-by-service-type.md @@ -8,10 +8,7 @@ Requesting the default configured object of a service type is done through the ` [Fact] public void get_the_default_instance() { - var container = new Container(x => - { - x.For().Use(); - }); + var container = new Container(x => { x.For().Use(); }); container.GetInstance() .ShouldBeOfType(); @@ -22,7 +19,7 @@ public void get_the_default_instance() .ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] diff --git a/docs/guide/ioc/resolving/get-all-services-by-service-type.md b/docs/guide/ioc/resolving/get-all-services-by-service-type.md index e93b77f7..9689eb39 100644 --- a/docs/guide/ioc/resolving/get-all-services-by-service-type.md +++ b/docs/guide/ioc/resolving/get-all-services-by-service-type.md @@ -22,7 +22,7 @@ public void get_all_instances() x.For().Add().Named("B"); x.For().Add().Named("C"); }); - + container.QuickBuildAll() .Select(x => x.GetType()) .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget)); @@ -39,7 +39,7 @@ public void get_all_instances() .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget)); } ``` -snippet source | anchor +snippet source | anchor ```cs [Fact] diff --git a/docs/guide/ioc/setter-injection.md b/docs/guide/ioc/setter-injection.md index 23fff8a5..ebd8cd20 100644 --- a/docs/guide/ioc/setter-injection.md +++ b/docs/guide/ioc/setter-injection.md @@ -29,14 +29,12 @@ public class Repository // Adding the SetterProperty to a setter directs // Lamar to use this property when // constructing a Repository instance - [SetterProperty] - public IDataProvider Provider { get; set; } + [SetterProperty] public IDataProvider Provider { get; set; } - [SetterProperty] - public bool ShouldCache { get; set; } + [SetterProperty] public bool ShouldCache { get; set; } } ``` -snippet source | anchor +snippet source | anchor Without the `[SetterProperty]` attributes decorating the setters, Lamar would ignore the `Provider` and `ShouldCache` properties when it builds up a `Repository` object. With the attributes, Lamar will try to build and attach values for the two properties as part of object construction. @@ -93,11 +91,10 @@ public class RuleWithSettersRegistry : ServiceRegistry // or if you need to specify the property name .Setter("Action").Is(); - } } ``` -snippet source | anchor +snippet source | anchor See also: [Inline Dependencies](/guide/ioc/registration/inline-dependencies) @@ -142,7 +139,7 @@ public void specify_setter_policy_and_construct_an_object() target.Gateway.ShouldBeOfType(); } ``` -snippet source | anchor +snippet source | anchor All calls to `Registry.Policies.SetAllProperties()` are additive, meaning you can use as many criteria as possible for setter injection. diff --git a/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj b/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj index dc589858..e15858dd 100644 --- a/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj +++ b/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj @@ -2,7 +2,7 @@ Adds diagnostic checks to the command line of your Lamar-enabled ASP.Net Core app - 13.0.1 + 13.0.2 Jeremy D. Miller net6.0;net7.0;net8.0 portable diff --git a/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj b/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj index 30413755..c83ab7dc 100644 --- a/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj +++ b/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj @@ -1,7 +1,7 @@  Lamar Adapter for HostBuilder Integration - 13.0.1 + 13.0.2 Jeremy D. Miller net6.0;net7.0;net8.0 portable @@ -17,12 +17,20 @@ false - + + + + + + + + + diff --git a/src/Lamar/Lamar.csproj b/src/Lamar/Lamar.csproj index af751d3d..b1673f55 100644 --- a/src/Lamar/Lamar.csproj +++ b/src/Lamar/Lamar.csproj @@ -1,7 +1,7 @@  Fast ASP.Net Core compatible IoC Tool, Successor to StructureMap - 13.0.1 + 13.0.2 Jeremy D. Miller net6.0;net7.0;net8.0 portable