diff --git a/Servant/Lifestyle.cs b/Servant/Lifestyle.cs
new file mode 100644
index 0000000..cab9127
--- /dev/null
+++ b/Servant/Lifestyle.cs
@@ -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
+{
+ ///
+ /// Specifies how instances are reused between dependants.
+ ///
+ public enum Lifestyle
+ {
+ ///
+ /// Only a single instance of the service will be created.
+ ///
+ Singleton,
+
+ ///
+ /// A new instance of the service will be created for each dependant.
+ ///
+ Transient
+ }
+}
\ No newline at end of file
diff --git a/Servant/Servant.cs b/Servant/Servant.cs
index b7b4ca5..ac2cdca 100644
--- a/Servant/Servant.cs
+++ b/Servant/Servant.cs
@@ -25,111 +25,12 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using JetBrains.Annotations;
namespace Servant
{
- ///
- /// Specifies how instances are reused between dependants.
- ///
- public enum Lifestyle
- {
- ///
- /// Only a single instance of the service will be created.
- ///
- Singleton,
-
- ///
- /// A new instance of the service will be created for each dependant.
- ///
- Transient
- }
-
- internal sealed class TypeEntry
- {
- public Type DeclaredType { get; }
-
- [CanBeNull] public TypeProvider Provider { get; set; }
-
- public TypeEntry(Type declaredType)
- {
- DeclaredType = declaredType;
- }
- }
-
- internal sealed class TypeProvider
- {
- public Lifestyle Lifestyle { get; }
- public IReadOnlyList Dependencies { get; }
-
- private readonly Servant _servant;
- private readonly Func> _factory;
- private readonly Type _declaredType;
-
- [CanBeNull] private object _singletonInstance;
-
- public TypeProvider(Servant servant, Func> factory, Type declaredType, Lifestyle lifestyle, IReadOnlyList dependencies)
- {
- _servant = servant;
- _factory = factory;
- _declaredType = declaredType;
- Lifestyle = lifestyle;
- Dependencies = dependencies;
- }
-
- public async Task 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>();
- 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;
- }
- }
-
///
/// Serves instances of specific types, resolving dependencies as required, and running any async initialisation.
///
@@ -303,20 +204,4 @@ public void Dispose()
disposable.Dispose();
}
}
-
- ///
- /// An exception raised by Servant.
- ///
- [ExcludeFromCodeCoverage]
- public sealed class ServantException : Exception
- {
- ///
- public ServantException() { }
-
- ///
- public ServantException(string message) : base(message) { }
-
- ///
- public ServantException(string message, Exception innerException) : base(message, innerException) { }
- }
}
diff --git a/Servant/Servant.csproj b/Servant/Servant.csproj
index 29c25ab..f5868cf 100644
--- a/Servant/Servant.csproj
+++ b/Servant/Servant.csproj
@@ -39,8 +39,10 @@
+
+
True
@@ -48,6 +50,8 @@
ServantExtensions.Generated.tt
+
+
diff --git a/Servant/ServantException.cs b/Servant/ServantException.cs
new file mode 100644
index 0000000..6357c9f
--- /dev/null
+++ b/Servant/ServantException.cs
@@ -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
+{
+ ///
+ /// An exception raised by Servant.
+ ///
+ [ExcludeFromCodeCoverage]
+ public sealed class ServantException : Exception
+ {
+ ///
+ public ServantException() { }
+
+ ///
+ public ServantException(string message) : base(message) { }
+
+ ///
+ public ServantException(string message, Exception innerException) : base(message, innerException) { }
+ }
+}
\ No newline at end of file
diff --git a/Servant/TypeEntry.cs b/Servant/TypeEntry.cs
new file mode 100644
index 0000000..66ca20c
--- /dev/null
+++ b/Servant/TypeEntry.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Servant/TypeProvider.cs b/Servant/TypeProvider.cs
new file mode 100644
index 0000000..4ea023e
--- /dev/null
+++ b/Servant/TypeProvider.cs
@@ -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 Dependencies { get; }
+
+ private readonly Servant _servant;
+ private readonly Func> _factory;
+ private readonly Type _declaredType;
+
+ [CanBeNull] private object _singletonInstance;
+
+ public TypeProvider(Servant servant, Func> factory, Type declaredType, Lifestyle lifestyle, IReadOnlyList dependencies)
+ {
+ _servant = servant;
+ _factory = factory;
+ _declaredType = declaredType;
+ Lifestyle = lifestyle;
+ Dependencies = dependencies;
+ }
+
+ public async Task 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>();
+ 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;
+ }
+ }
+}
\ No newline at end of file