-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d30ec24
commit 6f1575d
Showing
6 changed files
with
233 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#region License | ||
// | ||
// Servant | ||
// | ||
// Copyright 2016 Drew Noakes | ||
// | ||
// 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. | ||
// | ||
// More information about this project is available at: | ||
// | ||
// https://github.com/drewnoakes/servant | ||
// | ||
#endregion | ||
|
||
namespace Servant | ||
{ | ||
/// <summary> | ||
/// Specifies how instances are reused between dependants. | ||
/// </summary> | ||
public enum Lifestyle | ||
{ | ||
/// <summary> | ||
/// Only a single instance of the service will be created. | ||
/// </summary> | ||
Singleton, | ||
|
||
/// <summary> | ||
/// A new instance of the service will be created for each dependant. | ||
/// </summary> | ||
Transient | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#region License | ||
// | ||
// Servant | ||
// | ||
// Copyright 2016 Drew Noakes | ||
// | ||
// 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. | ||
// | ||
// More information about this project is available at: | ||
// | ||
// https://github.com/drewnoakes/servant | ||
// | ||
#endregion | ||
|
||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Servant | ||
{ | ||
/// <summary> | ||
/// An exception raised by Servant. | ||
/// </summary> | ||
[ExcludeFromCodeCoverage] | ||
public sealed class ServantException : Exception | ||
{ | ||
/// <inheritdoc /> | ||
public ServantException() { } | ||
|
||
/// <inheritdoc /> | ||
public ServantException(string message) : base(message) { } | ||
|
||
/// <inheritdoc /> | ||
public ServantException(string message, Exception innerException) : base(message, innerException) { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#region License | ||
// | ||
// Servant | ||
// | ||
// Copyright 2016 Drew Noakes | ||
// | ||
// 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. | ||
// | ||
// More information about this project is available at: | ||
// | ||
// https://github.com/drewnoakes/servant | ||
// | ||
#endregion | ||
|
||
using System; | ||
using JetBrains.Annotations; | ||
|
||
namespace Servant | ||
{ | ||
internal sealed class TypeEntry | ||
{ | ||
public Type DeclaredType { get; } | ||
|
||
[CanBeNull] public TypeProvider Provider { get; set; } | ||
|
||
public TypeEntry(Type declaredType) | ||
{ | ||
DeclaredType = declaredType; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#region License | ||
// | ||
// Servant | ||
// | ||
// Copyright 2016 Drew Noakes | ||
// | ||
// 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. | ||
// | ||
// More information about this project is available at: | ||
// | ||
// https://github.com/drewnoakes/servant | ||
// | ||
#endregion | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using JetBrains.Annotations; | ||
|
||
namespace Servant | ||
{ | ||
internal sealed class TypeProvider | ||
{ | ||
public Lifestyle Lifestyle { get; } | ||
public IReadOnlyList<TypeEntry> Dependencies { get; } | ||
|
||
private readonly Servant _servant; | ||
private readonly Func<object[], Task<object>> _factory; | ||
private readonly Type _declaredType; | ||
|
||
[CanBeNull] private object _singletonInstance; | ||
|
||
public TypeProvider(Servant servant, Func<object[], Task<object>> factory, Type declaredType, Lifestyle lifestyle, IReadOnlyList<TypeEntry> dependencies) | ||
{ | ||
_servant = servant; | ||
_factory = factory; | ||
_declaredType = declaredType; | ||
Lifestyle = lifestyle; | ||
Dependencies = dependencies; | ||
} | ||
|
||
public async Task<object> GetAsync() | ||
{ | ||
// TODO make concurrency-safe here to avoid double-allocation of singleton | ||
|
||
if (Lifestyle == Lifestyle.Singleton && _singletonInstance != null) | ||
return _singletonInstance; | ||
|
||
// find arguments | ||
var argumentTasks = new List<Task<object>>(); | ||
foreach (var dep in Dependencies) | ||
{ | ||
if (dep.Provider == null) | ||
{ | ||
// No provider exists for this dependency. | ||
var message = $"Type \"{_declaredType}\" depends upon unregistered type \"{dep.DeclaredType}\"."; | ||
|
||
// See whether we have a super-type of the requested type. | ||
var superTypes = _servant.GetRegisteredTypes().Where(type => type.IsAssignableFrom(dep.DeclaredType)).ToList(); | ||
if (superTypes.Any()) | ||
message += $" Did you mean to reference registered super type {string.Join(" or ", superTypes.Select(st => $"\"{st}\""))}?"; | ||
|
||
throw new ServantException(message); | ||
} | ||
argumentTasks.Add(dep.Provider.GetAsync()); | ||
} | ||
|
||
await Task.WhenAll(argumentTasks); | ||
|
||
var instance = await _factory.Invoke(argumentTasks.Select(t => t.Result).ToArray()); | ||
|
||
if (instance == null) | ||
throw new ServantException($"Instance for type \"{_declaredType}\" cannot be null."); | ||
|
||
if (!_declaredType.IsInstanceOfType(instance)) | ||
throw new ServantException($"Instance produced for type \"{_declaredType}\" is not an instance of that type."); | ||
|
||
if (Lifestyle == Lifestyle.Singleton) | ||
{ | ||
_singletonInstance = instance; | ||
|
||
var disposable = instance as IDisposable; | ||
if (disposable != null) | ||
_servant.PushDisposableSingleton(disposable); | ||
} | ||
|
||
return instance; | ||
} | ||
} | ||
} |