├── .editorconfig
├── .github
└── workflows
│ ├── dotnet-core.yml
│ ├── toc.yml
│ └── wiki.yml
├── .gitignore
├── Directory.Build.props
├── LICENSE
├── NuGet.config
├── README.md
├── Samples
├── AspNetCore
│ ├── Container.cs
│ ├── Controllers
│ │ ├── UsersController.cs
│ │ └── WeatherForecastController.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── README.md
│ ├── Services
│ │ ├── DatabaseDecorator.cs
│ │ ├── DatabaseUsersCache.cs
│ │ ├── IDatabase.cs
│ │ ├── IUsersCache.cs
│ │ ├── IWeatherForecastProvider.cs
│ │ ├── IWeatherSummarizer.cs
│ │ ├── MockDatabase.cs
│ │ ├── User.cs
│ │ ├── WeatherForecastProvider.cs
│ │ └── WeatherSummarizer.cs
│ ├── Startup.cs
│ ├── StrongInject.Samples.AspNetCore.csproj
│ ├── WeatherForecast.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Console
│ ├── App.cs
│ ├── Cache.cs
│ ├── Config.cs
│ ├── Container.cs
│ ├── ICommitable.cs
│ ├── IConfigLoader.cs
│ ├── IConsumer.cs
│ ├── IProducer.cs
│ ├── JsonConfigLoader.cs
│ ├── JsonDeserializer.cs
│ ├── JsonSerializer.cs
│ ├── KafkaConsumer.cs
│ ├── KafkaModule.cs
│ ├── KafkaProducer.cs
│ ├── Message.cs
│ ├── Program.cs
│ ├── README.md
│ ├── StrongInject.Samples.ConsoleApp.csproj
│ ├── User.cs
│ ├── config.json
│ └── docker-compose.yml
├── Wpf
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── Commands
│ │ └── RelayCommand.cs
│ ├── Container.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Models
│ │ ├── IDatabase.cs
│ │ ├── MockDatabase.cs
│ │ └── User.cs
│ ├── README.md
│ ├── StrongInject.Samples.Wpf.csproj
│ ├── ViewModels
│ │ ├── MainWindowViewModel.cs
│ │ ├── UserViewModel.cs
│ │ └── UsersViewModel.cs
│ └── Views
│ │ ├── UsersView.xaml
│ │ └── UsersView.xaml.cs
└── Xamarin
│ ├── README.md
│ ├── StrongInject.Samples.XamarinApp.Android
│ ├── Assets
│ │ └── AboutAssets.txt
│ ├── MainActivity.cs
│ ├── Properties
│ │ ├── AndroidManifest.xml
│ │ └── AssemblyInfo.cs
│ ├── Resources
│ │ ├── AboutResources.txt
│ │ ├── Resource.designer.cs
│ │ ├── drawable
│ │ │ ├── icon_about.png
│ │ │ ├── icon_feed.png
│ │ │ └── xamarin_logo.png
│ │ ├── layout
│ │ │ ├── Tabbar.xml
│ │ │ └── Toolbar.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── icon.xml
│ │ │ └── icon_round.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── icon.png
│ │ │ └── launcher_foreground.png
│ │ ├── mipmap-mdpi
│ │ │ ├── icon.png
│ │ │ └── launcher_foreground.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── icon.png
│ │ │ └── launcher_foreground.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── icon.png
│ │ │ └── launcher_foreground.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── icon.png
│ │ │ └── launcher_foreground.png
│ │ └── values
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ └── StrongInject.Samples.XamarinApp.Android.csproj
│ └── StrongInject.Samples.XamarinApp
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AppShell.xaml
│ ├── AppShell.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── Container.cs
│ ├── GettingStarted.txt
│ ├── Models
│ └── Item.cs
│ ├── Services
│ ├── Browser.cs
│ ├── IBrowser.cs
│ ├── IDataStore.cs
│ ├── INavigationService.cs
│ ├── MockDataStore.cs
│ └── NavigationService.cs
│ ├── StrongInject.Samples.XamarinApp.csproj
│ ├── ViewModels
│ ├── AboutViewModel.cs
│ ├── BaseViewModel.cs
│ ├── ItemDetailViewModel.cs
│ ├── ItemsViewModel.cs
│ ├── LoginViewModel.cs
│ └── NewItemViewModel.cs
│ └── Views
│ ├── AboutPage.xaml
│ ├── AboutPage.xaml.cs
│ ├── IViewOf.cs
│ ├── ItemDetailPage.xaml
│ ├── ItemDetailPage.xaml.cs
│ ├── ItemsPage.xaml
│ ├── ItemsPage.xaml.cs
│ ├── LoginPage.xaml
│ ├── LoginPage.xaml.cs
│ ├── NewItemPage.xaml
│ └── NewItemPage.xaml.cs
├── StrongInject.Extensions.DependencyInjection.AspNetCore
├── MvcBuilderExtensions.cs
└── StrongInject.Extensions.DependencyInjection.AspNetCore.csproj
├── StrongInject.Extensions.DependencyInjection.Tests
├── MvcBuilderExtensionTests.cs
├── ServiceCollectionExtensionTests.cs
└── StrongInject.Extensions.DependencyInjection.Tests.csproj
├── StrongInject.Extensions.DependencyInjection
├── ServiceCollectionExtensions.cs
└── StrongInject.Extensions.DependencyInjection.csproj
├── StrongInject.Generator.Roslyn38
├── SourceGenerator.cs
└── StrongInject.Generator.Roslyn38.csproj
├── StrongInject.Generator.Roslyn40
├── IncrementalGenerator.cs
└── StrongInject.Generator.Roslyn40.csproj
├── StrongInject.Generator
├── AutoIndenter.cs
├── ContainerGenerator.cs
├── DecoratorOptions.cs
├── DecoratorSource.cs
├── Disposal.cs
├── DisposalLowerer.cs
├── DisposalStyle.cs
├── DisposalStyleDeterminant.cs
├── Extensions.cs
├── FactoryOfMethod.cs
├── GenericDecoratorsResolver.cs
├── GenericRegistrationsResolver.cs
├── GenericResolutionHelpers.cs
├── ImmutableSetInInsertionOrder.cs
├── InstanceSource.cs
├── InstanceSources.cs
├── InstanceSourcesScope.cs
├── IsExternalInit.cs
├── Operation.cs
├── Options.cs
├── RegistrationCalculator.cs
├── RoslynExtensions.cs
├── Scope.cs
├── Statement.cs
├── StrongInject.Generator.csproj
├── Visitors
│ ├── BaseVisitor.cs
│ ├── DependencyCheckerVisitor.cs
│ ├── IVisitor.cs
│ ├── LoweringVisitor.cs
│ ├── PartialOrderingOfSingleInstanceDependenciesVisitor.cs
│ ├── RequiresAsyncVisitor.cs
│ ├── RequiresUnsafeVisitor.cs
│ ├── SimpleVisitor.cs
│ └── SingleInstanceVariablesToCreateEarlyVisitor.cs
└── WellKnownTypes.cs
├── StrongInject.Tests.Integration
├── DynamicProxyDecoratorTests.cs
├── IsExternalInit.cs
├── Modules
│ ├── CollectionTests.cs
│ ├── ImmutableArrayTests.cs
│ └── LazyTests.cs
├── StrongInject.Tests.Integration.csproj
├── TestCircularFuncDependencies.cs
├── TestContainerExtensions.cs
├── TestDisposalAfterUsage.cs
├── TestFuncParameterInjection.cs
├── TestFuncScope.cs
├── TestInstancePerDependencyHasCorrectScope.cs
├── TestInstancePerResolutionHasCorrectScope.cs
├── TestNullableConversion.cs
├── TestOwnedInjection.cs
├── TestParallelismAndResolutionFailureBehaviour.cs
├── TestReadmeExamples.cs
├── TestReadmeExamples_AsOfCommit_008a07c7b075e72d491a9144e2f4233aff5a7b7b.cs
├── TestSingleInstanceHasCorrectScope.cs
├── TestSingleInstanceNull.cs
└── TestSingleInstanceStruct.cs
├── StrongInject.Tests.Unit
├── AssertionExtensions.cs
├── DependencyCheckerTests.cs
├── DiagnosticVerifier.cs
├── GeneratorTests.cs
├── OwnedInjectionTests.cs
├── OwnedTests.cs
├── RoslynExtensions.cs
├── StrongInject.Tests.Unit.csproj
├── TestBase.cs
└── WellKnownTypesTests.cs
├── StrongInject.sln
├── StrongInject
├── DecoratorFactoryAttribute.cs
├── DecoratorOptions.cs
├── DummyParameter.cs
├── FactoryAttribute.cs
├── FactoryOfAttribute.cs
├── Helpers.cs
├── IContainer.cs
├── IFactory.cs
├── IRequiresInitialization.cs
├── InstanceAttribute.cs
├── Modules
│ ├── CollectionsModule.cs
│ ├── LazyModule.cs
│ ├── SafeImmutableArrayModule.cs
│ ├── StandardModule.cs
│ ├── UnsafeImmutableArrayModule.cs
│ └── ValueTupleModule.cs
├── ObsoleteTypes
│ ├── ContainerExtensions.cs
│ ├── FactoryRegistrationAttribute.cs
│ ├── ModuleRegistrationAtribute.cs
│ └── RegistrationAttribute.cs
├── Options.cs
├── Owned.cs
├── RegisterAttribute.cs
├── RegisterDecoratorAttribute.cs
├── RegisterFactoryAttribute.cs
├── RegisterModuleAttribute.cs
├── Scope.cs
├── StrongInject.csproj
├── StrongInjectContainerExtensions.cs
├── StrongInjectException.cs
├── ValueTaskExtensions.cs
└── buildTransitive
│ └── StrongInject.targets
├── Utilities
└── GeneratorTestsUpdater
│ ├── GeneratorTestsUpdater.csproj
│ └── Program.cs
├── docs
├── Containers.md
├── DesignDecisions.md
├── Home.md
├── Registration.md
├── Registration
│ ├── BestRegistration.md
│ ├── DecoratorFactoryRegistration.md
│ ├── DecoratorTypeRegistration.md
│ ├── Decorators.md
│ ├── FactoryMethodRegistration.md
│ ├── FactoryTypeRegistration.md
│ ├── InstanceRegistration.md
│ ├── ModuleRegistration.md
│ ├── RegistrationOptions.md
│ ├── Scopes.md
│ └── TypeRegistration.md
└── Resolution.md
└── resources
├── logo-circle.ico
├── logo-circle.png
├── logo-circle.svg
├── logo-horizontal.ico
├── logo-horizontal.png
└── logo-horizontal.svg
/.github/workflows/toc.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 | name: TOC Generator
6 | jobs:
7 | generateTOC:
8 | name: TOC Generator
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: technote-space/toc-generator@v2
12 | with:
13 | TOC_TITLE: |
14 | ## Table Of Contents
15 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
16 | TARGET_PATHS: README.md, docs/**.md, docs/*/**.md
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/wiki.yml:
--------------------------------------------------------------------------------
1 | name: Wiki
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 |
7 | jobs:
8 | run:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v1
13 | # Additional steps to generate documentation in "Documentation" directory
14 | - name: Upload Documentation to Wiki
15 | uses: SwiftDocOrg/github-wiki-publish-action@rsync
16 | with:
17 | path: "docs/"
18 | env:
19 | GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
20 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | preview
4 | enable
5 | true
6 | CS1591;RS1024
7 | AD0001
8 | true
9 | AllEnabledByDefault
10 | preview
11 | true
12 | 1.4.5
13 | *-*
14 |
15 |
16 |
17 | StrongInject
18 | StrongInject
19 | MIT
20 | https://github.com/YairHalberstadt/stronginject
21 | https://github.com/YairHalberstadt/stronginject
22 | true
23 | true
24 | snupkg
25 | logo-circle.png
26 | true
27 |
28 |
29 |
30 | true
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | True
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Yair Halberstadt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Container.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.Logging;
3 | using StrongInject.Samples.AspNetCore.Controllers;
4 | using StrongInject.Samples.AspNetCore.Services;
5 | using System;
6 |
7 | namespace StrongInject.Samples.AspNetCore
8 | {
9 | [Register(typeof(WeatherForecastController), Scope.InstancePerResolution)]
10 | [Register(typeof(WeatherForecastProvider), Scope.InstancePerDependency, typeof(IWeatherForecastProvider))]
11 | [Register(typeof(WeatherSummarizer), Scope.SingleInstance, typeof(IWeatherSummarizer))]
12 | [Register(typeof(UsersController), Scope.InstancePerResolution)]
13 | [Register(typeof(DatabaseUsersCache), Scope.SingleInstance, typeof(IUsersCache))]
14 | [Register(typeof(MockDatabase), Scope.SingleInstance, typeof(IDatabase))]
15 | [RegisterDecorator(typeof(DatabaseDecorator), typeof(IDatabase))]
16 | public partial class Container : IContainer, IContainer
17 | {
18 | private readonly IServiceProvider _serviceProvider;
19 |
20 | public Container(IServiceProvider serviceProvider)
21 | {
22 | _serviceProvider = serviceProvider;
23 | }
24 |
25 | [Factory] private ILogger GetLogger() => _serviceProvider.GetRequiredService>();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Controllers/UsersController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Microsoft.Extensions.Logging;
3 | using StrongInject.Samples.AspNetCore.Services;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace StrongInject.Samples.AspNetCore.Controllers
8 | {
9 | [ApiController]
10 | [Route("[controller]")]
11 | public class UsersController : ControllerBase
12 | {
13 | private readonly IUsersCache _usersCache;
14 | private readonly ILogger _logger;
15 |
16 | public UsersController(IUsersCache usersCache, ILogger logger)
17 | {
18 | _usersCache = usersCache;
19 | _logger = logger;
20 | }
21 |
22 | [HttpGet]
23 | public ValueTask> Get()
24 | {
25 | _logger.LogInformation($"Requesting users");
26 | return _usersCache.GetUsersList();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Microsoft.Extensions.Logging;
3 | using StrongInject.Samples.AspNetCore.Services;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace StrongInject.Samples.AspNetCore.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private readonly Func _weatherForecastProvider;
15 | private readonly ILogger _logger;
16 |
17 | public WeatherForecastController(Func weatherForecastProvider, ILogger logger)
18 | {
19 | _weatherForecastProvider = weatherForecastProvider;
20 | _logger = logger;
21 | }
22 |
23 | [HttpGet]
24 | public IEnumerable Get(string location)
25 | {
26 | _logger.LogInformation($"Requesting weather forecasts at {location}");
27 | var rng = new Random();
28 | return Enumerable.Range(1, 5)
29 | .Select(index => _weatherForecastProvider(location).GetForecast(DateTime.Now.AddDays(index)))
30 | .ToArray();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Hosting;
4 | using Microsoft.Extensions.Logging;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace StrongInject.Samples.AspNetCore
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:50527",
8 | "sslPort": 44383
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "weatherforecast?location=London",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "WebApplication2": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "weatherforecast?location=London",
24 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/README.md:
--------------------------------------------------------------------------------
1 | # StrongInject.Samples.AspNetCore
2 |
3 | ## Overview
4 |
5 | This sample demonstrates a simple rest API with two controllers. Both controllers are instantiated using StrongInject.
6 |
7 | The weather forecast controller is reached at https://localhost:44383/weatherforecast?location= and returns a (randomly generated) weather forecast for that location.
8 |
9 | The users controller is reached at https://localhost:44383/users and returns a list of users.
10 |
11 | ## Learning Points
12 |
13 | This app demonstrates how to integrate StrongInject with ASP.NET Core using the StrongInject.Extensions.DependencyInjection.AspNetCore package.
14 |
15 | It also demonstrates a number of other key features of StrongInject:
16 |
17 | 1. Usages of Scopes to control lifetimes. For example Controllers should be `InstancePerDependency` whilst caches should be `SingleInstance`.
18 | 2. Passing `IServiceProvider` as a parameter to the container, and using it to resolve `ILogger`, allowing for two way integration with other IOC containers.
19 | 3. Whilst `StrongInject` supports async resolution, Microsoft.Extensions.DependencyInjection does not. `DatabaseUsersCache` can only be prepared asynchronously so a different technique is used where requests on it become asynchronous instead.
20 | 4. Usage of a generic factory method to register `ILogger` for all `T` at once.
21 |
22 | ## Notes
23 |
24 | If you intend to use StrongInject to resolve all your controllers, then call `services.AddControllers().ResolveControllersThroughServiceProvider()` in `StartUp`. This tells ASP.NET Core to resolve all controllers through the service provider, but doesn't auto register them with the service provider. You can then register them yourselves manually.
25 |
26 | If however you want to auto register all controllers with the service provider, and only override some of them with StrongInject, then you will need to call `services.AddControllers().AddControllersAsServices()` instead. This not only tells ASP.NET Core to resolve all controllers through the service provider, but also auto registers them as well. You will then need to make sure you remove these auto registrations when you manually overwrite the default registration by calling `services.ReplaceWithTransientServiceUsingContainer()` (or any of the related `ReplaceWithXServiceUsingContainer` methods).
27 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/DatabaseDecorator.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace StrongInject.Samples.AspNetCore.Services
8 | {
9 | public class DatabaseDecorator : IDatabase
10 | {
11 | private readonly IDatabase _underlying;
12 | private readonly ILogger _logger;
13 |
14 | public DatabaseDecorator(IDatabase underlying, ILogger logger)
15 | {
16 | _underlying = underlying;
17 | _logger = logger;
18 | }
19 |
20 | public async Task> Get()
21 | {
22 | _logger.LogInformation($"Requesting {typeof(T).Name}s from database...");
23 |
24 | try
25 | {
26 | var results = await _underlying.Get();
27 | _logger.LogInformation($"Successfully recieved {results.Count()} {typeof(T).Name}s from database");
28 | return results;
29 | }
30 | catch (Exception e)
31 | {
32 | _logger.LogError($"Error when requesting {typeof(T).Name}s from database: {e}");
33 | throw;
34 | }
35 |
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/DatabaseUsersCache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace StrongInject.Samples.AspNetCore.Services
7 | {
8 | public class DatabaseUsersCache : IUsersCache, IDisposable
9 | {
10 | private Timer? _timer;
11 |
12 | private ValueTask> _users;
13 |
14 | public DatabaseUsersCache(IDatabase database)
15 | {
16 | _users = new ValueTask>(database.Get());
17 | _timer = new Timer(async _ =>
18 | {
19 | var users = await database.Get();
20 | _users = new ValueTask>(users);
21 | }, null, 60000, 60000);
22 | }
23 |
24 | public void Dispose()
25 | {
26 | _timer?.Dispose();
27 | _timer = null;
28 |
29 | }
30 |
31 | ValueTask> IUsersCache.GetUsersList()
32 | {
33 | return _users;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/IDatabase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace StrongInject.Samples.AspNetCore.Services
5 | {
6 | public interface IDatabase
7 | {
8 | public Task> Get();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/IUsersCache.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace StrongInject.Samples.AspNetCore.Services
5 | {
6 | public interface IUsersCache
7 | {
8 | public ValueTask> GetUsersList();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/IWeatherForecastProvider.cs:
--------------------------------------------------------------------------------
1 | using StrongInject.Samples.AspNetCore;
2 | using System;
3 |
4 | namespace StrongInject.Samples.AspNetCore.Services
5 | {
6 | public interface IWeatherForecastProvider
7 | {
8 | WeatherForecast GetForecast(DateTime day);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/IWeatherSummarizer.cs:
--------------------------------------------------------------------------------
1 | namespace StrongInject.Samples.AspNetCore.Services
2 | {
3 | public interface IWeatherSummarizer
4 | {
5 | string Summarize(int temperatureC);
6 | }
7 | }
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/MockDatabase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace StrongInject.Samples.AspNetCore.Services
7 | {
8 | public class MockDatabase : IDatabase
9 | {
10 | public async Task> Get()
11 | {
12 | await Task.Yield();
13 |
14 | if (typeof(T) == typeof(User))
15 | {
16 | return new[] {
17 | new User("Rebekah Riley", DateTime.Parse("1/2/1996")),
18 | new User("Gene Simons", DateTime.Parse("3/4/1978")),
19 | new User("Nabilah Downs", DateTime.Parse("5/6/2002"))
20 | }.Cast();
21 | }
22 |
23 | return Array.Empty();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/User.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StrongInject.Samples.AspNetCore.Services
4 | {
5 | public class User
6 | {
7 | public User(string name, DateTime dateOfBirth)
8 | {
9 | Name = name;
10 | DateOfBirth = dateOfBirth;
11 | }
12 |
13 | public string Name { get; }
14 |
15 | public DateTime DateOfBirth { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/WeatherForecastProvider.cs:
--------------------------------------------------------------------------------
1 | using StrongInject.Samples.AspNetCore;
2 | using System;
3 |
4 | namespace StrongInject.Samples.AspNetCore.Services
5 | {
6 | public class WeatherForecastProvider : IWeatherForecastProvider
7 | {
8 | public WeatherForecastProvider(string location, IWeatherSummarizer weatherSummarizer)
9 | {
10 | _location = location;
11 | _weatherSummarizer = weatherSummarizer;
12 | }
13 |
14 | private readonly Random _random = new Random();
15 | private readonly string _location;
16 | private readonly IWeatherSummarizer _weatherSummarizer;
17 |
18 | public WeatherForecast GetForecast(DateTime day)
19 | {
20 | var temperatureC = _random.Next(-20, 55);
21 | return new WeatherForecast
22 | {
23 | Location = _location,
24 | Date = day,
25 | TemperatureC = temperatureC,
26 | Summary = _weatherSummarizer.Summarize(temperatureC),
27 | };
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Services/WeatherSummarizer.cs:
--------------------------------------------------------------------------------
1 | namespace StrongInject.Samples.AspNetCore.Services
2 | {
3 | public class WeatherSummarizer : IWeatherSummarizer
4 | {
5 | public string Summarize(int temperatureC)
6 | {
7 | return temperatureC switch
8 | {
9 | < 0 => "Freezing",
10 | < 5 => "Bracing",
11 | < 10 => "Chilly",
12 | < 15 => "Cool",
13 | < 20 => "Mild",
14 | < 25 => "Warm",
15 | < 30 => "Balmy",
16 | < 35 => "Hot",
17 | < 40 => "Sweltering",
18 | _ => "Scorching",
19 | };
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/Startup.cs:
--------------------------------------------------------------------------------
1 | #define DontAutoRegisterControllers
2 |
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using StrongInject.Extensions.DependencyInjection;
9 | using StrongInject.Extensions.DependencyInjection.AspNetCore;
10 | using StrongInject.Samples.AspNetCore.Controllers;
11 |
12 | namespace StrongInject.Samples.AspNetCore
13 | {
14 | public class Startup
15 | {
16 | public Startup(IConfiguration configuration)
17 | {
18 | Configuration = configuration;
19 | }
20 |
21 | public IConfiguration Configuration { get; }
22 |
23 | // This method gets called by the runtime. Use this method to add services to the container.
24 | public void ConfigureServices(IServiceCollection services)
25 | {
26 | #if DontAutoRegisterControllers
27 | services.AddControllers().ResolveControllersThroughServiceProvider(); // Tells ASP.NET to resolve controllers through the ServiceProvider, rather than calling their constructors directly.
28 | services.AddTransientServiceUsingContainer(); // register the controller with the ServiceProvider.
29 | services.AddTransientServiceUsingContainer();
30 | #else
31 | services.AddControllers().AddControllersAsServices(); // Tells ASP.NET to resolve controllers through the ServiceProvider, rather than calling their constructors directly, and then auto registers all controllers with the service provider.
32 | services.ReplaceWithTransientServiceUsingContainer(); // register the controller with the ServiceProvider, and remove the existing registration that was added automatically by AddControllersAsServices().
33 | services.ReplaceWithTransientServiceUsingContainer();
34 | #endif
35 | }
36 |
37 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
38 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
39 | {
40 | if (env.IsDevelopment())
41 | {
42 | app.UseDeveloperExceptionPage();
43 | }
44 |
45 | app.UseHttpsRedirection();
46 |
47 | app.UseRouting();
48 |
49 | app.UseAuthorization();
50 |
51 | app.UseEndpoints(endpoints =>
52 | {
53 | endpoints.MapControllers();
54 | });
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/StrongInject.Samples.AspNetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | Debug;Release;Wpf;All
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StrongInject.Samples.AspNetCore
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string? Summary { get; set; }
14 |
15 | public string? Location { get; internal set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/AspNetCore/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/Console/App.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace StrongInject.Samples.ConsoleApp
5 | {
6 | public class App
7 | {
8 | private readonly IConsumer _consumer;
9 | private readonly Cache> _producerCache;
10 | private readonly string _targetTopicPrefix;
11 |
12 | public App(IConsumer consumer, Cache> producerCache, string targetTopicPrefix)
13 | {
14 | _consumer = consumer;
15 | _producerCache = producerCache;
16 | _targetTopicPrefix = targetTopicPrefix;
17 | }
18 |
19 | public async Task FanMessagesToRecipients()
20 | {
21 | await foreach (var commitableMessage in _consumer.Consume())
22 | {
23 | var (key, value) = (commitableMessage.Key, commitableMessage.Value);
24 | Console.WriteLine($"Forwarding message from {key.Name} to {value.Recipient.Name}");
25 | await _producerCache.Get(_targetTopicPrefix + value.Recipient.Id).Produce(key, value);
26 | commitableMessage.Commit();
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Samples/Console/Cache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 |
4 | namespace StrongInject.Samples.ConsoleApp
5 | {
6 | public class Cache where TKey : notnull
7 | {
8 | private readonly Func _factory;
9 |
10 | public Cache(Func factory)
11 | {
12 | _factory = factory;
13 | }
14 |
15 | private readonly ConcurrentDictionary _cached = new();
16 | public TValue Get(TKey key) => _cached.GetOrAdd(key, _factory);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Samples/Console/Config.cs:
--------------------------------------------------------------------------------
1 | namespace StrongInject.Samples.ConsoleApp
2 | {
3 | public class Config
4 | {
5 | public string BootstrapServers { get; init; } = "";
6 | public string GroupId { get; init; } = "";
7 | public string ConsumedTopic { get; init; } = "";
8 | public string TargetTopicPrefix { get; init; } = "";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/Console/Container.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace StrongInject.Samples.ConsoleApp
5 | {
6 |
7 | [RegisterModule(typeof(KafkaModule))]
8 | [Register(typeof(JsonConfigLoader), Scope.SingleInstance, typeof(IConfigLoader))]
9 | public partial class Container : IAsyncContainer
10 | {
11 | [Factory] private App CreateApp(IConsumer consumer, Cache> producerCache, Config config)
12 | => new App(consumer, producerCache, config.TargetTopicPrefix);
13 |
14 | [Factory(Scope.SingleInstance)] ValueTask CreateConfig(IConfigLoader configLoader) => configLoader.LoadConfig();
15 |
16 | [Factory] Cache CreateCache(Func factory) where TKey : notnull => new Cache(factory);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Samples/Console/ICommitable.cs:
--------------------------------------------------------------------------------
1 | namespace StrongInject.Samples.ConsoleApp
2 | {
3 | public interface ICommitable
4 | {
5 | TKey Key { get; }
6 | TValue Value { get; }
7 | void Commit();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/Console/IConfigLoader.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace StrongInject.Samples.ConsoleApp
4 | {
5 | public interface IConfigLoader
6 | {
7 | ValueTask LoadConfig();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/Console/IConsumer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace StrongInject.Samples.ConsoleApp
4 | {
5 | public interface IConsumer
6 | {
7 | IAsyncEnumerable> Consume();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/Console/IProducer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace StrongInject.Samples.ConsoleApp
4 | {
5 | public interface IProducer
6 | {
7 | public Task Produce(TKey key, TValue value);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Samples/Console/JsonConfigLoader.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text.Json;
3 | using System.Threading.Tasks;
4 |
5 | namespace StrongInject.Samples.ConsoleApp
6 | {
7 | public class JsonConfigLoader : IConfigLoader
8 | {
9 | public async ValueTask LoadConfig()
10 | {
11 | await using (var fileStream = File.OpenRead("config.json"))
12 | {
13 | return await JsonSerializer.DeserializeAsync(fileStream) ?? throw new JsonException("Invalid Config");
14 | }
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Samples/Console/JsonDeserializer.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 | using System;
3 | using System.Text.Json;
4 |
5 | namespace StrongInject.Samples.ConsoleApp
6 | {
7 | public class JsonDeserializer : IDeserializer
8 | {
9 | public T? Deserialize(ReadOnlySpan data, bool isNull, SerializationContext context)
10 | {
11 | if (isNull)
12 | return default;
13 | return JsonSerializer.Deserialize(data);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Samples/Console/JsonSerializer.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 | using System;
3 | using System.Text.Json;
4 |
5 | namespace StrongInject.Samples.ConsoleApp
6 | {
7 | public class JsonSerializer : ISerializer
8 | {
9 | public byte[] Serialize(T? data, SerializationContext context)
10 | {
11 | return data is null ? Array.Empty() : JsonSerializer.SerializeToUtf8Bytes(data);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Samples/Console/KafkaConsumer.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace StrongInject.Samples.ConsoleApp
6 | {
7 | public class KafkaConsumer : IConsumer
8 | {
9 | private readonly Confluent.Kafka.IConsumer _consumer;
10 | private readonly string _topic;
11 |
12 | public KafkaConsumer(Confluent.Kafka.IConsumer consumer, string topic)
13 | {
14 | _consumer = consumer;
15 | _topic = topic;
16 | }
17 |
18 | public async IAsyncEnumerable> Consume()
19 | {
20 | _consumer.Subscribe(_topic);
21 |
22 | while (true)
23 | {
24 | var result = _consumer.Consume();
25 | if (result.IsPartitionEOF)
26 | {
27 | await Task.Delay(1000);
28 | }
29 | else
30 | {
31 | yield return new Commitable(result, _consumer);
32 | }
33 | }
34 | }
35 |
36 | private class Commitable : ICommitable
37 | {
38 | private readonly Confluent.Kafka.IConsumer _consumer;
39 | private readonly ConsumeResult _consumeResult;
40 |
41 | public Commitable(ConsumeResult consumeResult, Confluent.Kafka.IConsumer consumer)
42 | {
43 | _consumeResult = consumeResult;
44 | _consumer = consumer;
45 | }
46 |
47 | public TKey Key => _consumeResult.Message.Key;
48 |
49 | public TValue Value => _consumeResult.Message.Value;
50 |
51 | public void Commit()
52 | {
53 | _consumer.Commit(_consumeResult);
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Samples/Console/KafkaModule.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 |
3 | namespace StrongInject.Samples.ConsoleApp
4 | {
5 | public class KafkaModule
6 | {
7 | [Factory(Scope.SingleInstance)] public static ISerializer CreateSerializer() => new JsonSerializer();
8 | [Factory(Scope.SingleInstance)] public static IDeserializer CreateDeserializer() => new JsonDeserializer();
9 | [Factory] public static Confluent.Kafka.IConsumer CreateConfluentConsumer(IDeserializer keyDeserializer, IDeserializer valueDeserializer, Config config)
10 | {
11 | return new ConsumerBuilder(new ConsumerConfig() { BootstrapServers = config.BootstrapServers, GroupId = config.GroupId })
12 | .SetKeyDeserializer(keyDeserializer)
13 | .SetValueDeserializer(valueDeserializer)
14 | .Build();
15 | }
16 | [Factory] public static Confluent.Kafka.IProducer CreateConfluentProducer(ISerializer keySerializer, ISerializer valueSerializer, Config config)
17 | {
18 | return new ProducerBuilder(new ProducerConfig() { BootstrapServers = config.BootstrapServers })
19 | .SetKeySerializer(keySerializer)
20 | .SetValueSerializer(valueSerializer)
21 | .Build();
22 | }
23 |
24 | [Factory] public static IConsumer CreateConsumer(Confluent.Kafka.IConsumer consumer, Config config) => new KafkaConsumer(consumer, config.ConsumedTopic);
25 | [Factory] public static IProducer CreateProducer(Confluent.Kafka.IProducer producer, string topic) => new KafkaProducer(producer, topic);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Samples/Console/KafkaProducer.cs:
--------------------------------------------------------------------------------
1 | using Confluent.Kafka;
2 | using System.Threading.Tasks;
3 |
4 | namespace StrongInject.Samples.ConsoleApp
5 | {
6 | public class KafkaProducer : IProducer
7 | {
8 | private readonly Confluent.Kafka.IProducer _producer;
9 | private readonly string _topic;
10 |
11 | public KafkaProducer(Confluent.Kafka.IProducer producer, string topic)
12 | {
13 | _producer = producer;
14 | _topic = topic;
15 | }
16 |
17 | public Task Produce(TKey key, TValue value)
18 | {
19 | return _producer.ProduceAsync(_topic, new Message() { Key = key, Value = value });
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Samples/Console/Message.cs:
--------------------------------------------------------------------------------
1 | namespace StrongInject.Samples.ConsoleApp
2 | {
3 | public record Message
4 | {
5 | public string Content { get; init; } = null!;
6 | public User Recipient { get; init; } = null!;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Samples/Console/README.md:
--------------------------------------------------------------------------------
1 | # StrongInject.Samples.ConsoleApp
2 |
3 | ## Overview
4 |
5 | This sample demonstrates a console application that might be part of a messaging application.
6 |
7 | It reads messages from a kafka topic ("all_messages") then forwards the message to the recipients inbox (the "inbox_[user-id]" kafka topic).
8 |
9 | ## Requirements
10 |
11 | Docker
12 |
13 | ## Learning Points
14 |
15 | This app demonstrates a number of key features and techniques using StrongInject:
16 |
17 | 1. Factories are used extensively, to facilitate passing a config around, and to enable registering a lot of generic types.
18 | 2. Loading a config at runtime, in a way that makes it easy to swap out how the config is loaded.
19 | 3. Using async resolution (in this case to asynchronously load a config file from disk).
20 | 4. Usage of a module to separate out groups of registrations that conceptually belong together.
21 |
22 | ## Notes
23 |
24 | Program.cs has a lot of code to start some docker containers, create kafka topics, and produce messages to those topics. You can ignore most of this code.
25 |
--------------------------------------------------------------------------------
/Samples/Console/StrongInject.Samples.ConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | Debug;Release;Wpf;All
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | PreserveNewest
17 |
18 |
19 | PreserveNewest
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Samples/Console/User.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StrongInject.Samples.ConsoleApp
4 | {
5 | public record User
6 | {
7 | public Guid Id { get; init; }
8 | public string Name { get; init; } = null!;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Samples/Console/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "BootstrapServers": "localhost:29092",
3 | "GroupId": "StrongInJectKafkaConsumer",
4 | "TargetTopicPrefix": "inbox_",
5 | "ConsumedTopic": "all_messages"
6 | }
--------------------------------------------------------------------------------
/Samples/Console/docker-compose.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: '2'
3 |
4 | services:
5 | zookeeper:
6 | image: confluentinc/cp-zookeeper
7 | hostname: zookeeper
8 | container_name: zookeeper
9 | ports:
10 | - "2181:2181"
11 | environment:
12 | ZOOKEEPER_CLIENT_PORT: 2181
13 | ZOOKEEPER_TICK_TIME: 2000
14 |
15 | broker:
16 | image: confluentinc/cp-kafka
17 | hostname: broker
18 | container_name: broker
19 | depends_on:
20 | - zookeeper
21 | ports:
22 | - "29092:29092"
23 | environment:
24 | KAFKA_BROKER_ID: 1
25 | KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
26 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
27 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:9092,PLAINTEXT_HOST://localhost:29092
28 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
29 | KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
30 | KAFKA_TOOLS_LOG4J_LOGLEVEL: ERROR
--------------------------------------------------------------------------------
/Samples/Wpf/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Samples/Wpf/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace StrongInject.Samples.Wpf
4 | {
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | private async void Application_Startup(object sender, StartupEventArgs e)
11 | {
12 | var container = new Container();
13 | MainWindow = (await container.ResolveAsync()).Value;
14 |
15 | // We never dispose of the container because its lifetime is the lifetime of the app.
16 | // Whilst we could hook into the Application Exit event, this will not be called if the app crashes or is forcefully terminated.
17 | // Therefore best practice is simply to make sure we don't rely on the container being disposed.
18 | // This will usually be the case as terminating the application frees up most resources.
19 |
20 | MainWindow.Show();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/Wpf/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/Samples/Wpf/Commands/RelayCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows.Input;
7 |
8 | namespace StrongInject.Samples.Wpf.Commands
9 | {
10 | public class RelayCommand : ICommand
11 | {
12 | private readonly Action