You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			446 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			446 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Collections.Generic;
 | |
| using System.Diagnostics.CodeAnalysis;
 | |
| using System.Globalization;
 | |
| 
 | |
| #if SILVERLIGHT
 | |
| using System.Reflection;
 | |
| #endif
 | |
| 
 | |
| namespace System.ComponentModel.DataAnnotations {
 | |
|     /// <summary>
 | |
|     /// Describes the context in which a validation is being performed.
 | |
|     /// </summary>
 | |
|     /// <remarks>
 | |
|     /// This class contains information describing the instance on which
 | |
|     /// validation is being performed.
 | |
|     /// <para>
 | |
|     /// It supports <see cref="IServiceProvider"/> so that custom validation
 | |
|     /// code can acquire additional services to help it perform its validation.
 | |
|     /// </para>
 | |
|     /// <para>
 | |
|     /// An <see cref="Items"/> property bag is available for additional contextual
 | |
|     /// information about the validation.  Values stored in <see cref="Items"/>
 | |
|     /// will be available to validation methods that use this <see cref="ValidationContext"/>
 | |
|     /// </para>
 | |
|     /// </remarks>
 | |
|     [SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "The actual IServiceProvider implementation lies with the underlying service provider.")]
 | |
|     public sealed class ValidationContext : IServiceProvider
 | |
|     {
 | |
|         #region Member Fields
 | |
| 
 | |
|         private Func<Type, object> _serviceProvider;
 | |
|         private object _objectInstance;
 | |
|         private string _memberName;
 | |
|         private string _displayName;
 | |
|         private Dictionary<object, object> _items;
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Constructors
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Construct a <see cref="ValidationContext"/> for a given object instance being validated.
 | |
|         /// </summary>
 | |
|         /// <param name="instance">The object instance being validated.  It cannot be <c>null</c>.</param>
 | |
|         /// <exception cref="ArgumentNullException">When <paramref name="instance"/> is <c>null</c></exception>
 | |
|         public ValidationContext(object instance)
 | |
|             : this(instance, null, null) {
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Construct a <see cref="ValidationContext"/> for a given object instance and an optional
 | |
|         /// property bag of <paramref name="items"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="instance">The object instance being validated.  It cannot be null.</param>
 | |
|         /// <param name="items">Optional set of key/value pairs to make available to consumers via <see cref="Items"/>.
 | |
|         /// If null, an empty dictionary will be created.  If not null, the set of key/value pairs will be copied into a
 | |
|         /// new dictionary, preventing consumers from modifying the original dictionary.
 | |
|         /// </param>
 | |
|         /// <exception cref="ArgumentNullException">When <paramref name="instance"/> is <c>null</c></exception>
 | |
|         public ValidationContext(object instance, IDictionary<object, object> items)
 | |
|             : this(instance, null, items) {
 | |
|         }
 | |
| 
 | |
| #if SILVERLIGHT
 | |
|         /// <summary>
 | |
|         /// Construct a <see cref="ValidationContext"/> for a given object instance, an optional <paramref name="serviceProvider"/>, and an optional
 | |
|         /// property bag of <paramref name="items"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="instance">The object instance being validated.  It cannot be null.</param>
 | |
|         /// <param name="serviceProvider">
 | |
|         /// Optional <see cref="IServiceProvider"/> to use when <see cref="GetService"/> is called.
 | |
|         /// If it is null, <see cref="GetService"/> will always return null.
 | |
|         /// </param>
 | |
|         /// <param name="items">Optional set of key/value pairs to make available to consumers via <see cref="Items"/>.
 | |
|         /// If null, an empty dictionary will be created.  If not null, the set of key/value pairs will be copied into a
 | |
|         /// new dictionary, preventing consumers from modifying the original dictionary.
 | |
|         /// </param>
 | |
|         /// <exception cref="ArgumentNullException">When <paramref name="instance"/> is <c>null</c></exception>
 | |
| #else
 | |
|         /// <summary>
 | |
|         /// Construct a <see cref="ValidationContext"/> for a given object instance, an optional <paramref name="serviceProvider"/>, and an optional
 | |
|         /// property bag of <paramref name="items"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="instance">The object instance being validated.  It cannot be null.</param>
 | |
|         /// <param name="serviceProvider">
 | |
|         /// Optional <see cref="IServiceProvider"/> to use when <see cref="GetService"/> is called.
 | |
|         /// <para>
 | |
|         /// If the <paramref name="serviceProvider"/> specified implements <see cref="Design.IServiceContainer"/>,
 | |
|         /// then it will be used as the <see cref="ServiceContainer"/> but its services can still be retrieved
 | |
|         /// through <see cref="GetService"/> as well.
 | |
|         /// </para>
 | |
|         /// </param>
 | |
|         /// <param name="items">Optional set of key/value pairs to make available to consumers via <see cref="Items"/>.
 | |
|         /// If null, an empty dictionary will be created.  If not null, the set of key/value pairs will be copied into a
 | |
|         /// new dictionary, preventing consumers from modifying the original dictionary.
 | |
|         /// </param>
 | |
|         /// <exception cref="ArgumentNullException">When <paramref name="instance"/> is <c>null</c></exception>
 | |
| #endif
 | |
|         public ValidationContext(object instance, IServiceProvider serviceProvider, IDictionary<object, object> items) {
 | |
|             if (instance == null) {
 | |
|                 throw new ArgumentNullException("instance");
 | |
|             }
 | |
| 
 | |
|             if (serviceProvider != null) {
 | |
|                 this.InitializeServiceProvider(serviceType => serviceProvider.GetService(serviceType));
 | |
|             }
 | |
| 
 | |
| #if !SILVERLIGHT
 | |
|             Design.IServiceContainer container = serviceProvider as Design.IServiceContainer;
 | |
| 
 | |
|             if (container != null) {
 | |
|                 this._serviceContainer = new ValidationContextServiceContainer(container);
 | |
|             } else {
 | |
|                 this._serviceContainer = new ValidationContextServiceContainer();
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             if (items != null) {
 | |
|                 this._items = new Dictionary<object, object>(items);
 | |
|             } else {
 | |
|                 this._items = new Dictionary<object, object>();
 | |
|             }
 | |
| 
 | |
|             this._objectInstance = instance;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Properties
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the object instance being validated.  While it will not be null, the state of the instance is indeterminate
 | |
|         /// as it might only be partially initialized during validation.
 | |
|         /// <para>Consume this instance with caution!</para>
 | |
|         /// </summary>
 | |
|         /// <remarks>
 | |
|         /// During validation, especially property-level validation, the object instance might be in an indeterminate state.
 | |
|         /// For example, the property being validated, as well as other properties on the instance might not have been
 | |
|         /// updated to their new values.
 | |
|         /// </remarks>
 | |
|         public object ObjectInstance {
 | |
|             get {
 | |
|                 return this._objectInstance;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the type of the object being validated.  It will not be null.
 | |
|         /// </summary>
 | |
|         public Type ObjectType {
 | |
|             get {
 | |
| #if SILVERLIGHT
 | |
|                 return this.ObjectInstance.GetCustomOrCLRType();
 | |
| #else
 | |
|                 return this.ObjectInstance.GetType();
 | |
| #endif
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the user-visible name of the type or property being validated.
 | |
|         /// </summary>
 | |
|         /// <value>If this name was not explicitly set, this property will consult an associated <see cref="DisplayAttribute"/>
 | |
|         /// to see if can use that instead.  Lacking that, it returns <see cref="MemberName"/>.  The <see cref="ObjectInstance"/>
 | |
|         /// type name will be used if MemberName has not been set.
 | |
|         /// </value>
 | |
|         public string DisplayName {
 | |
|             get {
 | |
|                 if (string.IsNullOrEmpty(this._displayName)) {
 | |
|                     this._displayName = this.GetDisplayName();
 | |
| 
 | |
|                     if (string.IsNullOrEmpty(this._displayName)) {
 | |
|                         this._displayName = this.MemberName;
 | |
| 
 | |
|                         if (string.IsNullOrEmpty(this._displayName)) {
 | |
|                             this._displayName = this.ObjectType.Name;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 return this._displayName;
 | |
|             }
 | |
|             set {
 | |
|                 if (string.IsNullOrEmpty(value)) {
 | |
|                     throw new ArgumentNullException("value");
 | |
|                 }
 | |
|                 this._displayName = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the name of the type or property being validated.
 | |
|         /// </summary>
 | |
|         /// <value>This name reflects the API name of the member being validated, not a localized name.  It should be set
 | |
|         /// only for property or parameter contexts.</value>
 | |
|         public string MemberName {
 | |
|             get {
 | |
|                 return this._memberName;
 | |
|             }
 | |
|             set {
 | |
|                 this._memberName = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the dictionary of key/value pairs associated with this context.
 | |
|         /// </summary>
 | |
|         /// <value>This property will never be null, but the dictionary may be empty.  Changes made
 | |
|         /// to items in this dictionary will never affect the original dictionary specified in the constructor.</value>
 | |
|         public IDictionary<object, object> Items {
 | |
|             get {
 | |
|                 return this._items;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Methods
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Looks up the display name using the DisplayAttribute attached to the respective type or property.
 | |
|         /// </summary>
 | |
|         /// <returns>A display-friendly name of the member represented by the <see cref="MemberName"/>.</returns>
 | |
|         private string GetDisplayName() {
 | |
|             string displayName = null;
 | |
|             ValidationAttributeStore store = ValidationAttributeStore.Instance;
 | |
|             DisplayAttribute displayAttribute = null;
 | |
| 
 | |
|             if (string.IsNullOrEmpty(this._memberName)) {
 | |
|                 displayAttribute = store.GetTypeDisplayAttribute(this);
 | |
|             } else if (store.IsPropertyContext(this)) {
 | |
|                 displayAttribute = store.GetPropertyDisplayAttribute(this);
 | |
|             }
 | |
| 
 | |
|             if (displayAttribute != null) {
 | |
|                 displayName = displayAttribute.GetName();
 | |
|             }
 | |
| 
 | |
|             return displayName ?? this.MemberName;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes the <see cref="ValidationContext"/> with a service provider that can return
 | |
|         /// service instances by <see cref="Type"/> when <see cref="GetService"/> is called.
 | |
|         /// </summary>
 | |
|         /// <param name="serviceProvider">
 | |
|         /// A <see cref="Func{T, TResult}"/> that can return service instances given the
 | |
|         /// desired <see cref="Type"/> when <see cref="GetService"/> is called.
 | |
|         /// If it is <c>null</c>, <see cref="GetService"/> will always return <c>null</c>.
 | |
|         /// </param>
 | |
|         public void InitializeServiceProvider(Func<Type, object> serviceProvider) {
 | |
|             this._serviceProvider = serviceProvider;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IServiceProvider Members
 | |
| 
 | |
| #if SILVERLIGHT
 | |
|         /// <summary>
 | |
|         /// See <see cref="IServiceProvider.GetService(Type)"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="serviceType">The type of the service needed.</param>
 | |
|         /// <returns>An instance of that service or null if it is not available.</returns>
 | |
| #else
 | |
|         /// <summary>
 | |
|         /// See <see cref="IServiceProvider.GetService(Type)"/>.
 | |
|         /// When the <see cref="ServiceContainer"/> is in use, it will be used
 | |
|         /// first to retrieve the requested service.  If the <see cref="ServiceContainer"/>
 | |
|         /// is not being used or it cannot resolve the service, then the
 | |
|         /// <see cref="IServiceProvider"/> provided to this <see cref="ValidationContext"/>
 | |
|         /// will be queried for the service type.
 | |
|         /// </summary>
 | |
|         /// <param name="serviceType">The type of the service needed.</param>
 | |
|         /// <returns>An instance of that service or null if it is not available.</returns>
 | |
| #endif
 | |
|         public object GetService(Type serviceType) {
 | |
|             object service = null;
 | |
| 
 | |
| #if !SILVERLIGHT
 | |
|             if (this._serviceContainer != null) {
 | |
|                 service = this._serviceContainer.GetService(serviceType);
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             if (service == null && this._serviceProvider != null) {
 | |
|                 service = this._serviceProvider(serviceType);
 | |
|             }
 | |
| 
 | |
|             return service;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
| #if !SILVERLIGHT
 | |
|         #region Service Container
 | |
| 
 | |
|         private Design.IServiceContainer _serviceContainer;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// A <see cref="Design.IServiceContainer"/> that can be used for adding,
 | |
|         /// removing, and getting services during validation.  <see cref="GetService"/>
 | |
|         /// will query into this container as well as the <see cref="IServiceProvider"/>
 | |
|         /// specified in the constructor.
 | |
|         /// </summary>
 | |
|         /// <remarks>
 | |
|         /// If the <see cref="IServiceProvider"/> specified to the constructor implements
 | |
|         /// <see cref="Design.IServiceContainer"/>, then it will be used as the
 | |
|         /// <see cref="ServiceContainer"/>, otherwise an empty container will be initialized.
 | |
|         /// </remarks>
 | |
|         public Design.IServiceContainer ServiceContainer {
 | |
|             get {
 | |
|                 if (this._serviceContainer == null) {
 | |
|                     this._serviceContainer = new ValidationContextServiceContainer();
 | |
|                 }
 | |
| 
 | |
|                 return this._serviceContainer;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Private implementation of <see cref="Design.IServiceContainer"/> to act
 | |
|         /// as a default service container on <see cref="ValidationContext"/>.
 | |
|         /// </summary>
 | |
|         [SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "ValidationContext does not need to work with COM interop types. So this is fine.")]
 | |
|         private class ValidationContextServiceContainer : Design.IServiceContainer
 | |
|         {
 | |
|         #region Member Fields
 | |
| 
 | |
|             private Design.IServiceContainer _parentContainer;
 | |
|             private Dictionary<Type, object> _services = new Dictionary<Type, object>();
 | |
|             private readonly object _lock = new object();
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Constructors
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Constructs a new service container that does not have a parent container
 | |
|             /// </summary>
 | |
|             internal ValidationContextServiceContainer() {
 | |
|             }
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Contstructs a new service container that has a parent container, making this container
 | |
|             /// a wrapper around the parent container.  Calls to <c>AddService</c> and <c>RemoveService</c>
 | |
|             /// will promote to the parent container by default, unless <paramref name="promote"/> is
 | |
|             /// specified as <c>false</c> on those calls.
 | |
|             /// </summary>
 | |
|             /// <param name="parentContainer">The parent container to wrap into this container.</param>
 | |
|             internal ValidationContextServiceContainer(Design.IServiceContainer parentContainer) {
 | |
|                 this._parentContainer = parentContainer;
 | |
|             }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IServiceContainer Members
 | |
| 
 | |
|             [SuppressMessage("Microsoft.Usage", "CA2301:EmbeddableTypesInContainersRule", MessageId = "_services", Justification = "ValidationContext does not need to work with COM interop types. So this is fine.")]
 | |
|             public void AddService(Type serviceType, Design.ServiceCreatorCallback callback, bool promote)
 | |
|             {
 | |
|                 if (promote && this._parentContainer != null) {
 | |
|                     this._parentContainer.AddService(serviceType, callback, promote);
 | |
|                 } else {
 | |
|                     lock (this._lock) {
 | |
|                         if (this._services.ContainsKey(serviceType)) {
 | |
|                             throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.DataAnnotationsResources.ValidationContextServiceContainer_ItemAlreadyExists, serviceType), "serviceType");
 | |
|                         }
 | |
| 
 | |
|                         this._services.Add(serviceType, callback);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public void AddService(Type serviceType, Design.ServiceCreatorCallback callback) {
 | |
|                 this.AddService(serviceType, callback, true);
 | |
|             }
 | |
| 
 | |
|             [SuppressMessage("Microsoft.Usage", "CA2301:EmbeddableTypesInContainersRule", MessageId = "_services", Justification = "ValidationContext does not need to work with COM interop types. So this is fine.")]
 | |
|             public void AddService(Type serviceType, object serviceInstance, bool promote)
 | |
|             {
 | |
|                 if (promote && this._parentContainer != null) {
 | |
|                     this._parentContainer.AddService(serviceType, serviceInstance, promote);
 | |
|                 } else {
 | |
|                     lock (this._lock) {
 | |
|                         if (this._services.ContainsKey(serviceType)) {
 | |
|                             throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.DataAnnotationsResources.ValidationContextServiceContainer_ItemAlreadyExists, serviceType), "serviceType");
 | |
|                         }
 | |
| 
 | |
|                         this._services.Add(serviceType, serviceInstance);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public void AddService(Type serviceType, object serviceInstance) {
 | |
|                 this.AddService(serviceType, serviceInstance, true);
 | |
|             }
 | |
| 
 | |
|             public void RemoveService(Type serviceType, bool promote) {
 | |
|                 lock (this._lock) {
 | |
|                     if (this._services.ContainsKey(serviceType)) {
 | |
|                         this._services.Remove(serviceType);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (promote && this._parentContainer != null) {
 | |
|                     this._parentContainer.RemoveService(serviceType);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public void RemoveService(Type serviceType) {
 | |
|                 this.RemoveService(serviceType, true);
 | |
|             }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IServiceProvider Members
 | |
| 
 | |
|             public object GetService(Type serviceType) {
 | |
|                 if (serviceType == null) {
 | |
|                     throw new ArgumentNullException("serviceType");
 | |
|                 }
 | |
| 
 | |
|                 object service = null;
 | |
|                 this._services.TryGetValue(serviceType, out service);
 | |
| 
 | |
|                 if (service == null && this._parentContainer != null) {
 | |
|                     service = this._parentContainer.GetService(serviceType);
 | |
|                 }
 | |
| 
 | |
|                 Design.ServiceCreatorCallback callback = service as Design.ServiceCreatorCallback;
 | |
| 
 | |
|                 if (callback != null) {
 | |
|                     service = callback(this, serviceType);
 | |
|                 }
 | |
| 
 | |
|                 return service;
 | |
|             }
 | |
| 
 | |
|         #endregion
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| #endif
 | |
|     }
 | |
| }
 |