Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for .NET Core 3.x #517

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
de1621e
Add support for .NET Core 3.x as a container for IServiceProvider
ltines Apr 15, 2020
f723d87
Add readme
ltines Apr 15, 2020
b6655d5
Fix renaming
ltines Apr 15, 2020
90f31a2
Add to solution
ltines Apr 15, 2020
864e3c6
Remove the need for InternalsVisible
ltines Apr 15, 2020
fb8365c
Remove Nesting and fixed layout
ltines Apr 19, 2020
e8a766a
Fix layout
ltines Apr 19, 2020
d2e2c0a
Remove warning about target framework
ltines Apr 19, 2020
0c1ca73
Small fixes for coding style
ltines Apr 19, 2020
858c4b7
Fix typos
ltines Apr 22, 2020
de7e469
Fix another typo
ltines Apr 22, 2020
d620c7f
Move starting root scope bit earilier
ltines Apr 24, 2020
92891b7
Fix accessing root scope from different thread
ltines Apr 25, 2020
70743f1
Adding .NET 4.6.1 + some explicit dependendecies
ltines May 3, 2020
0c94508
Add comment why we're using MS namespace
ltines May 3, 2020
fea6656
Typos and intendation
ltines May 3, 2020
4f0d338
Remove coverage dependency
ltines May 3, 2020
043fcdb
Fix targets
ltines May 3, 2020
9557c87
Add tests for net461
ltines May 3, 2020
e1b13b8
Rename project and fix intendation to tabs
ltines May 24, 2020
240c9f9
add both restore and tests to build
ltines May 24, 2020
e5537c7
Reverse order of resolved collection.
ltines May 25, 2020
70586b5
Keep registration order of instances when resolving a collection
ltines Jun 6, 2020
e79a539
Remove NetCore from names and split code into folders
ltines Jun 6, 2020
5699f61
Fix intendation and remove debug test
ltines Jun 7, 2020
598740a
Cosmetic changes
ltines Jun 13, 2020
be676fa
Fix rename
ltines Jun 13, 2020
21da7e0
Update docu
ltines Jun 13, 2020
6b86d13
Move to docs
ltines Jun 15, 2020
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
13 changes: 13 additions & 0 deletions Castle.Windsor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Facilities.AspNet.We
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Facilities.AspNet.WebApi.Tests", "src\Castle.Facilities.AspNet.WebApi.Tests\Castle.Facilities.AspNet.WebApi.Tests.csproj", "{5CD7AE3F-105F-4C7A-940D-B7D130940E66}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Windsor.Extensions.MsDependencyInjection", "src\Castle.Windsor.Extensions.MsDependencyInjection\Castle.Windsor.Extensions.MsDependencyInjection.csproj", "{7710F8A2-33D8-40C1-89F5-648577B5DD01}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindsorServiceProvider.Tests", "src\Castle.Windsor.Extensions.MsDependencyInjection.Tests\WindsorServiceProvider.Tests.csproj", "{7755E40C-EF6D-46E6-ADAC-A8308664B8DA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -121,6 +125,14 @@ Global
{5CD7AE3F-105F-4C7A-940D-B7D130940E66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CD7AE3F-105F-4C7A-940D-B7D130940E66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CD7AE3F-105F-4C7A-940D-B7D130940E66}.Release|Any CPU.Build.0 = Release|Any CPU
{7710F8A2-33D8-40C1-89F5-648577B5DD01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7710F8A2-33D8-40C1-89F5-648577B5DD01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7710F8A2-33D8-40C1-89F5-648577B5DD01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7710F8A2-33D8-40C1-89F5-648577B5DD01}.Release|Any CPU.Build.0 = Release|Any CPU
{7755E40C-EF6D-46E6-ADAC-A8308664B8DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7755E40C-EF6D-46E6-ADAC-A8308664B8DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7755E40C-EF6D-46E6-ADAC-A8308664B8DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7755E40C-EF6D-46E6-ADAC-A8308664B8DA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -140,6 +152,7 @@ Global
{175EF5FC-C3A5-4EE4-BFE6-77F0A53CBA3B} = {7935AFF5-BF6D-4D59-8D66-058B6557F70F}
{501276B2-166F-40CA-AFF0-2F2D70BF4E4F} = {7935AFF5-BF6D-4D59-8D66-058B6557F70F}
{5CD7AE3F-105F-4C7A-940D-B7D130940E66} = {7935AFF5-BF6D-4D59-8D66-058B6557F70F}
{7710F8A2-33D8-40C1-89F5-648577B5DD01} = {7935AFF5-BF6D-4D59-8D66-058B6557F70F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CC2A1EB6-49EC-4064-AD8B-29439E8A45E4}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Castle.Windsor.Extensions.MsDependencyInjection.Tests
{
using System;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Specification;

public class WindsorScopedServiceProviderTests : DependencyInjectionSpecificationTests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This obviously runs the .NET DependencyInjection provided unit tests, so I think the project should probably be named Castle.Windsor.Extensions.DependencyInjection.Specification.Tests. This project is also not being compiled or run in the build.

And have a separate Castle.Windsor.Extensions.DependencyInjection.Tests project using NUnit for extra tests. e.g. support for Options and Logging libraries, and anything else specific to Windsor and for any defects that get found like has already been reported in the pull request but not picked up by this set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can rename.

As for other unit tests - will add though i don't see reason having tests for Options and Logging - those are already tests by specification tests.

This project is also not being compiled or run in the build.
It does for me. Are there any specifc steps for Castle? Becase the build setup for the solution is "unusual".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for other unit tests - will add though i don't see reason having tests for Options and Logging - those are already tests by specification tests.

Great. Even if there are no extra unit tests we will at least have somewhere people can add unit tests before fixing any bugs.

It does for me. Are there any specifc steps for Castle? Becase the build setup for the solution is "unusual".

Yep, it is definitely unusual, the build hacked around in the DNX days to make it work for the buggy tooling of the day, it probably needs to be refreshed to match what you'd do today if you were starting a clean project.

It looks like it actually is being built now, but the unit tests aren't being run. We are running the unit tests from buildscripts/build.cmd:

echo -------------
echo Running Tests
echo -------------
dotnet test src\Castle.Windsor.Tests || exit /b 1
dotnet test src\Castle.Facilities.AspNetCore.Tests || exit /b 1
dotnet test src\Castle.Facilities.AspNet.SystemWeb.Tests || exit /b 1
dotnet test src\Castle.Facilities.AspNet.Mvc.Tests || exit /b 1
dotnet test src\Castle.Facilities.AspNet.WebApi.Tests || exit /b 1
dotnet test src\Castle.Facilities.WcfIntegration.Tests || exit /b 1

{
protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var factory = new WindsorServiceProviderFactory();
var container = factory.CreateBuilder(serviceCollection);
return factory.CreateServiceProvider(container);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>

<IsPackable>false</IsPackable>

<AssemblyName>Castle.Windsor.Extensions.MsDependencyInjection.Tests</AssemblyName>

<RootNamespace>Castle.Windsor.Extensions.MsDependencyInjection.Tests</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Specification.Tests" Version="3.1.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.assert" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Castle.Windsor.Extensions.MsDependencyInjection\Castle.Windsor.Extensions.MsDependencyInjection.csproj" />
</ItemGroup>

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

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<Import Project="..\..\buildscripts\common.props"></Import>

<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Castle.Windsor.Extensions.MsDependencyInjection</PackageId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we agreed that Extensions.MsDependencyInjection didn't make sense since the Extensions.DependencyInjection part comes from the namespace, so adding the MS suffix means it isn't using the namespace anymore.

Since Microsoft.Extensions.DependencyInjection now lives in dotnet/runtime I don't think any Microsoft branding should be in our name. Microsoft developers said with the move to the runtime repo that they can't rename the packages to System.* because it would obviously be a breaking change, however all of these packages will be managed like the System.* packages, just as there are Microsoft.CSharp and Microsoft.Win32.Registry packages in the dotnet/runtime repository.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware of that. Besides for .NET Core 3.x it still in separate repo. I wouldn't worry about .NET 5 - knowing how Core teams move, it might still change until they come to release builds

Happy to rename to Castle.Windsor.Extensions.DependencyInjection

<Title>Castle Windsor extension for .NET Core Dependency Injection </Title>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microsoft.Extensions.DependencyInjection is also available for .NET Framework and .NET Standard.

<Description>Allows to use Castle Windsor as a container using IServiceProvider</Description>
<PackageTags>castle, windsor, inversionOfControl, DependencyInjection, aspnet, core</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);NU5125</NoWarn> <!-- remove once tools are truly ready for NuGet's new 'license' element -->
<AssemblyName>Castle.Windsor.Extensions.MsDependencyInjection</AssemblyName>
<RootNamespace>Castle.Windsor.Extensions.MsDependencyInjection</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Castle.Windsor\Castle.Windsor.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Microsoft.Extensions.Hosting
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
{
using Castle.Windsor;
using Castle.Windsor.Extensions.MsDependencyInjection;

public static class HostBuilderExtensions
{
/// <summary>
/// Uses <see name="IWindsorContainer" /> as the DI container for the host
/// </summary>
/// <param name="hostBuilder">Host builder</param>
/// <returns>Host builder</returns>
public static IHostBuilder UseWindsorContainerServiceProvider(this IHostBuilder hostBuilder)
{
return hostBuilder.UseServiceProviderFactory<IWindsorContainer>(new WindsorServiceProviderFactory());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.MsDependencyInjection
{
using Castle.Core;
using Castle.MicroKernel;
using Castle.MicroKernel.Context;

using Microsoft.Extensions.Logging;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microsoft.Extensions.Logging isn't declared as an explicit dependency, should it be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comes with Microsoft.Extensions.Hosting but added as explicit as well. What's the policy on transient dependencies?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the policy on transient dependencies?

We don't really have a policy, but I know Microsoft recently removed some transient dependencies between ASP.NET packages that weren't needed, which breaks situations like this. I think if the Windsor code uses the public API of the Logging package it should define an explicit dependency rather than just relying on it being there because something else brings it in.


public class LoggerDependencyResolver : ISubDependencyResolver
{
private readonly IKernel kernel;

public LoggerDependencyResolver(IKernel kernel)
{
this.kernel = kernel;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return dependency.TargetType == typeof(ILogger);
}

public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
var factory = kernel.Resolve<ILoggerFactory>();
return factory.CreateLogger(RegistrationAdapter.OriginalComponentName(model.Name));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.MsDependencyInjection
{
using System;

using Castle.Core;
using Castle.MicroKernel;
using Castle.MicroKernel.Context;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;

public class NetCoreCollectionResolver : CollectionResolver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this custom CollectionResolver do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has a check kernel.HasComponent(dependency.TargetItemType). Normal CollectionResolver didn't work. Tbh found on the internets

{
public NetCoreCollectionResolver(IKernel kernel, bool allowEmptyCollections = true) : base(kernel, allowEmptyCollections)
{
}

public override bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
DependencyModel dependency)
{
if (kernel.HasComponent(dependency.TargetItemType))
{
return false;
}

return base.CanResolve(context, contextHandlerResolver, model, dependency);
}

public override object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
DependencyModel dependency)
{
Array items = base.Resolve(context, contextHandlerResolver, model, dependency) as Array;
return items;
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.MsDependencyInjection
{
internal class NetCoreRootScope : NetCoreScope
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
{
private NetCoreRootScope() : base(null)
{

}
public static NetCoreRootScope BeginRootScope()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably throw if RootScope != null just to make sure things are in a valid state.

{
var scope = new NetCoreRootScope();
NetCoreScope.current.Value = scope;
return scope;
}

public override NetCoreRootScope RootScope => this;
public override int Nesting => 0;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.MsDependencyInjection
{
using System;

using Castle.MicroKernel.Context;
using Castle.MicroKernel.Lifestyle.Scoped;

internal class NetCoreRootScopeAccessor : IScopeAccessor
{
public ILifetimeScope GetScope(CreationContext context)
{
if(NetCoreScope.Current == null)
{
throw new InvalidOperationException("No scope");
}

if(NetCoreRootScope.Current.RootScope == null)
{
throw new InvalidOperationException("No root scope");
}

return NetCoreRootScope.Current.RootScope;
}

public void Dispose()
jonorossi marked this conversation as resolved.
Show resolved Hide resolved
{
}
}
}
Loading