Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v4
- uses: actions/setup-dotnet@v5
with:
dotnet-version: '9.0.x'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v4
- uses: actions/setup-dotnet@v5
with:
dotnet-version: '8.0.x'

Expand Down
44 changes: 24 additions & 20 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
{
"csharpOrganizeUsings.removeUnnecessaryUsings": true,
"csharpOrganizeUsings.sortOrder": "System",
"csharpOrganizeUsings.splitGroups": false,
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"files.associations": {
".dockerignore": "ignore",
"appsettings*.json": "jsonc",
"web.config": "xml"
},
"omnisharp.enableAsyncCompletion": true,
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableMsBuildLoadProjectsOnDemand": true,
"[aspnetcorerazor]": {
"editor.defaultFormatter": "ms-dotnettools.csharp"
},
"[csharp]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.organizeImports": "explicit"
},
"editor.defaultFormatter": "ms-dotnettools.csharp"
},
"[razor]": {
"editor.defaultFormatter": "ms-dotnettools.csharp"
},
"[jsonc]": {
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[json]": {
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[markdown]": {
"editor.codeActionsOnSave": {
"source.fixAll.markdownlint": "explicit"
},
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[razor]": {
"editor.defaultFormatter": "ms-dotnettools.csharp"
},
"csharpOrganizeUsings.removeUnnecessaryUsings": true,
"csharpOrganizeUsings.sortOrder": "System",
"csharpOrganizeUsings.splitGroups": false,
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"files.associations": {
".dockerignore": "ignore",
"appsettings*.json": "jsonc",
"web.config": "xml"
},
"markdownlint.config": {
"MD024": false
},
"omnisharp.enableAsyncCompletion": true,
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableMsBuildLoadProjectsOnDemand": true,
"remote.autoForwardPortsFallback": 0
}
202 changes: 178 additions & 24 deletions examples-dotnet.sln

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>$(LatestFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Autofac;
using Examples.Tests.Autofac.Fixtures.Greetings;

namespace Examples.Tests.Autofac.BasicUsage;

public class MultipleRegisteredServicesTests
{
[Fact]
public void WhenMultipleEntriesRegisteredWithSameInterface_ReturnsAsIEnumerable()
{
var mock = new Mock<IMessagePrinter>();
mock.Setup(x => x.Print("Hello Autofac world 1st."));
mock.Setup(x => x.Print("Hello Autofac world 2nd."));
mock.Setup(x => x.Print("Hello Autofac world 3rd."));

var builder = new ContainerBuilder();

builder.RegisterInstance(mock.Object)
.As<IMessagePrinter>()
.ExternallyOwned();

builder.RegisterTypes(
typeof(MyMessageGenerator1),
typeof(MyMessageGenerator2),
typeof(MyMessageGenerator3))
.As<IMessageGenerator>()
.SingleInstance();

builder
.RegisterType<GreetingService>()
.As<IGreetingService>()
.SingleInstance();

using var container = builder.Build();

var instance = container.Resolve<IGreetingService>();
instance?.Greet();

mock.Verify(x => x.Print("Hello Autofac world 1st."), Times.Exactly(1));
mock.Verify(x => x.Print("Hello Autofac world 2nd."), Times.Exactly(1));
mock.Verify(x => x.Print("Hello Autofac world 3rd."), Times.Exactly(1));
mock.VerifyNoOtherCalls();
}


private class MyMessageGenerator1 : IMessageGenerator
{
public string Generate() => "Hello Autofac world 1st.";
}

private class MyMessageGenerator2 : IMessageGenerator
{
public string Generate() => "Hello Autofac world 2nd.";
}

private class MyMessageGenerator3 : IMessageGenerator
{
public string Generate() => "Hello Autofac world 3rd.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using Autofac;
using Examples.Tests.Autofac.Fixtures.Greetings;

namespace Examples.Tests.Autofac.BasicUsage;

public partial class ServiceLifetimesTests
{
[Fact]
public void WhenRegisteredWithInstancePerDependency_ReturnsDifferentInstanceEachTime()
{
var mock = new Mock<IMessagePrinter>();
mock.Setup(x => x.Print("Hello Ioc world."));

var builder = new ContainerBuilder();

builder.RegisterInstance(mock.Object)
.As<IMessagePrinter>()
.ExternallyOwned();
builder.RegisterType<HelloMessageGenerator>()
.As<IMessageGenerator>()
//.InstancePerDependency() // default
;
builder.RegisterType<GreetingService>()
.As<IGreetingService>()
//.InstancePerDependency() // default
;

using var container = builder.Build();

var instance = container.Resolve<IGreetingService>();
instance?.Greet();

var another = container.Resolve<IGreetingService>();
another?.Greet();

another!.IsNotSameReferenceAs(instance);

mock.Verify(x => x.Print("Hello Ioc world."), Times.Exactly(2));
mock.VerifyNoOtherCalls();
}

[Fact]
public void WhenRegisteredWithInstancePerLifetimeScope_ReturnsSameInstanceWithinScope()
{
var mock = new Mock<IMessagePrinter>();
mock.Setup(x => x.Print("Hello Ioc world."));

var builder = new ContainerBuilder();

builder.RegisterInstance(mock.Object)
.As<IMessagePrinter>()
.ExternallyOwned();
builder.RegisterType<HelloMessageGenerator>()
.As<IMessageGenerator>()
.InstancePerLifetimeScope();
builder.RegisterType<GreetingService>()
.As<IGreetingService>()
.InstancePerLifetimeScope();

using var container = builder.Build();

var outScope = container.Resolve<IGreetingService>();
outScope?.Greet();

using (var scope = container.BeginLifetimeScope())
{
var inScope = scope.Resolve<IGreetingService>();
inScope?.Greet();

inScope!.IsNotSameReferenceAs(outScope);

var anotherInScope = scope.Resolve<IGreetingService>();
anotherInScope?.Greet();

anotherInScope!.IsSameReferenceAs(inScope);
anotherInScope!.IsNotSameReferenceAs(outScope);
}

mock.Verify(x => x.Print("Hello Ioc world."), Times.Exactly(3));
mock.VerifyNoOtherCalls();
}

[Fact]
public void WhenRegisteredWithSingleInstance_AlwaysReturnsSameInstance()
{
var mock = new Mock<IMessagePrinter>();
mock.Setup(x => x.Print("Hello Ioc world."));

var builder = new ContainerBuilder();

builder.RegisterInstance(mock.Object)
.As<IMessagePrinter>()
.ExternallyOwned();
builder.RegisterType<HelloMessageGenerator>()
.As<IMessageGenerator>()
.SingleInstance();
builder.RegisterType<GreetingService>()
.As<IGreetingService>()
.SingleInstance();

using var container = builder.Build();

var instance = container.Resolve<IGreetingService>();
instance?.Greet();

var another = container.Resolve<IGreetingService>();
another?.Greet();

another!.IsSameReferenceAs(instance);

using (var scope = container.BeginLifetimeScope())
{
var inScope = scope.Resolve<IGreetingService>();
inScope!.Greet();

inScope!.IsSameReferenceAs(instance);
}

mock.Verify(x => x.Print("Hello Ioc world."), Times.Exactly(3));
mock.VerifyNoOtherCalls();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Examples.Tests.Autofac.Fixtures.Greetings;

public sealed class GreetingService(
IMessagePrinter printer,
IEnumerable<IMessageGenerator> generators) : IGreetingService
{
private readonly IMessagePrinter _printer = printer;
private readonly IEnumerable<IMessageGenerator> _generators = generators;

public void Greet()
{
foreach (var greater in _generators)
{
_printer.Print(greater.Generate());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Examples.Tests.Autofac.Fixtures.Greetings;

public interface IMessagePrinter
{
void Print(string message);
}

public interface IMessageGenerator
{
string Generate();
}

public interface IGreetingService
{
void Greet();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Examples.Tests.Autofac.Fixtures.Greetings;

public class HelloMessageGenerator : IMessageGenerator
{
public string Generate() => "Hello Ioc world.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(LatestFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup>
<RootNamespace>Examples.Tests</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="8.4.0" />
<PackageReference Include="ChainingAssertion.Core.Xunit" Version="1.1.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
<Using Include="ChainingAssertion" />
<Using Include="Moq" />
</ItemGroup>

</Project>
Loading