Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/aspnetwebstack.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Web.Mvc/DependencyResolver.cs')
-rw-r--r--src/System.Web.Mvc/DependencyResolver.cs210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/System.Web.Mvc/DependencyResolver.cs b/src/System.Web.Mvc/DependencyResolver.cs
new file mode 100644
index 00000000..6fdb0807
--- /dev/null
+++ b/src/System.Web.Mvc/DependencyResolver.cs
@@ -0,0 +1,210 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Web.Mvc.Properties;
+
+namespace System.Web.Mvc
+{
+ public class DependencyResolver
+ {
+ private static DependencyResolver _instance = new DependencyResolver();
+
+ private IDependencyResolver _current;
+
+ /// <summary>
+ /// Cache should always be a new CacheDependencyResolver(_current).
+ /// </summary>
+ private CacheDependencyResolver _currentCache;
+
+ public DependencyResolver()
+ {
+ InnerSetResolver(new DefaultDependencyResolver());
+ }
+
+ public static IDependencyResolver Current
+ {
+ get { return _instance.InnerCurrent; }
+ }
+
+ internal static IDependencyResolver CurrentCache
+ {
+ get { return _instance.InnerCurrentCache; }
+ }
+
+ public IDependencyResolver InnerCurrent
+ {
+ get { return _current; }
+ }
+
+ /// <summary>
+ /// Provides caching over results returned by Current.
+ /// </summary>
+ internal IDependencyResolver InnerCurrentCache
+ {
+ get { return _currentCache; }
+ }
+
+ public static void SetResolver(IDependencyResolver resolver)
+ {
+ _instance.InnerSetResolver(resolver);
+ }
+
+ public static void SetResolver(object commonServiceLocator)
+ {
+ _instance.InnerSetResolver(commonServiceLocator);
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types.")]
+ public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
+ {
+ _instance.InnerSetResolver(getService, getServices);
+ }
+
+ public void InnerSetResolver(IDependencyResolver resolver)
+ {
+ if (resolver == null)
+ {
+ throw new ArgumentNullException("resolver");
+ }
+
+ _current = resolver;
+ _currentCache = new CacheDependencyResolver(_current);
+ }
+
+ public void InnerSetResolver(object commonServiceLocator)
+ {
+ if (commonServiceLocator == null)
+ {
+ throw new ArgumentNullException("commonServiceLocator");
+ }
+
+ Type locatorType = commonServiceLocator.GetType();
+ MethodInfo getInstance = locatorType.GetMethod("GetInstance", new[] { typeof(Type) });
+ MethodInfo getInstances = locatorType.GetMethod("GetAllInstances", new[] { typeof(Type) });
+
+ if (getInstance == null ||
+ getInstance.ReturnType != typeof(object) ||
+ getInstances == null ||
+ getInstances.ReturnType != typeof(IEnumerable<object>))
+ {
+ throw new ArgumentException(
+ String.Format(
+ CultureInfo.CurrentCulture,
+ MvcResources.DependencyResolver_DoesNotImplementICommonServiceLocator,
+ locatorType.FullName),
+ "commonServiceLocator");
+ }
+
+ var getService = (Func<Type, object>)Delegate.CreateDelegate(typeof(Func<Type, object>), commonServiceLocator, getInstance);
+ var getServices = (Func<Type, IEnumerable<object>>)Delegate.CreateDelegate(typeof(Func<Type, IEnumerable<object>>), commonServiceLocator, getInstances);
+
+ InnerSetResolver(new DelegateBasedDependencyResolver(getService, getServices));
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types.")]
+ public void InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
+ {
+ if (getService == null)
+ {
+ throw new ArgumentNullException("getService");
+ }
+ if (getServices == null)
+ {
+ throw new ArgumentNullException("getServices");
+ }
+
+ InnerSetResolver(new DelegateBasedDependencyResolver(getService, getServices));
+ }
+
+ /// <summary>
+ /// Wraps an IDependencyResolver and ensures single instance per-type.
+ /// </summary>
+ /// <remarks>
+ /// Note it's possible for multiple threads to race and call the _resolver service multiple times.
+ /// We'll pick one winner and ignore the others and still guarantee a unique instance.
+ /// </remarks>
+ private sealed class CacheDependencyResolver : IDependencyResolver
+ {
+ private readonly ConcurrentDictionary<Type, object> _cache = new ConcurrentDictionary<Type, object>();
+ private readonly ConcurrentDictionary<Type, IEnumerable<object>> _cacheMultiple = new ConcurrentDictionary<Type, IEnumerable<object>>();
+
+ private readonly IDependencyResolver _resolver;
+
+ public CacheDependencyResolver(IDependencyResolver resolver)
+ {
+ _resolver = resolver;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ return _cache.GetOrAdd(serviceType, _resolver.GetService);
+ }
+
+ public IEnumerable<object> GetServices(Type serviceType)
+ {
+ return _cacheMultiple.GetOrAdd(serviceType, _resolver.GetServices);
+ }
+ }
+
+ private class DefaultDependencyResolver : IDependencyResolver
+ {
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This method might throw exceptions whose type we cannot strongly link against; namely, ActivationException from common service locator")]
+ public object GetService(Type serviceType)
+ {
+ // Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null
+ // to improve performance and the debugging experience with first-chance exceptions enabled.
+ if (serviceType.IsInterface || serviceType.IsAbstract)
+ {
+ return null;
+ }
+
+ try
+ {
+ return Activator.CreateInstance(serviceType);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public IEnumerable<object> GetServices(Type serviceType)
+ {
+ return Enumerable.Empty<object>();
+ }
+ }
+
+ private class DelegateBasedDependencyResolver : IDependencyResolver
+ {
+ private Func<Type, object> _getService;
+ private Func<Type, IEnumerable<object>> _getServices;
+
+ public DelegateBasedDependencyResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
+ {
+ _getService = getService;
+ _getServices = getServices;
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This method might throw exceptions whose type we cannot strongly link against; namely, ActivationException from common service locator")]
+ public object GetService(Type type)
+ {
+ try
+ {
+ return _getService.Invoke(type);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public IEnumerable<object> GetServices(Type type)
+ {
+ return _getServices(type);
+ }
+ }
+ }
+}