PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/NHibernate.Validator/src/NHibernate.Validator/Engine/ValidatorEngine.cs

https://bitbucket.org/dabide/nhcontrib
C# | 616 lines | 380 code | 64 blank | 172 comment | 44 complexity | 5ccf6f208c8a64702a8e340aa399241b MD5 | raw file
Possible License(s): BSD-3-Clause, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, Apache-2.0, LGPL-3.0, LGPL-2.1
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Configuration;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Resources;
  8. using System.Xml;
  9. using NHibernate.Mapping;
  10. using NHibernate.Util;
  11. using NHibernate.Validator.Cfg;
  12. using NHibernate.Validator.Exceptions;
  13. using NHibernate.Validator.Util;
  14. using Environment=NHibernate.Validator.Cfg.Environment;
  15. using System.Reflection;
  16. namespace NHibernate.Validator.Engine
  17. {
  18. /// <summary>
  19. /// The engine of NHibernate Validator
  20. /// </summary>
  21. /// <remarks>
  22. /// The engine is the easy way to work with NHibernate.Validator.
  23. /// It hold all class validators.
  24. /// Usually an application will create a single <see cref="ValidatorEngine" />.
  25. /// </remarks>
  26. /// <seealso cref="Cfg.Environment"/>
  27. /// <seealso cref="ISharedEngineProvider"/>.
  28. [Serializable]
  29. public class ValidatorEngine
  30. {
  31. private static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof(ValidatorEngine));
  32. private StateFullClassValidatorFactory factory;
  33. private IMessageInterpolator interpolator;
  34. private ValidatorMode defaultMode;
  35. private IConstraintValidatorFactory constraintValidatorFactory;
  36. private bool applyToDDL;
  37. private bool autoRegisterListeners;
  38. private IEntityTypeInspector entityTypeInspector;
  39. private readonly ThreadSafeDictionary<System.Type, ValidatableElement> validators =
  40. new ThreadSafeDictionary<System.Type, ValidatableElement>(new Dictionary<System.Type, ValidatableElement>());
  41. private static readonly ValidatableElement AlwaysValidPlaceHolder = new ValidatableElement(typeof (object), new EmptyClassValidator());
  42. private class EmptyClassValidator: IClassValidator
  43. {
  44. public bool HasValidationRules
  45. {
  46. get { return false; }
  47. }
  48. public IEnumerable<InvalidValue> GetInvalidValues(object entity)
  49. {
  50. yield break;
  51. }
  52. public IEnumerable<InvalidValue> GetInvalidValues(object entity, string propertyName)
  53. {
  54. yield break;
  55. }
  56. public void AssertValid(object entity)
  57. {
  58. }
  59. public IEnumerable<InvalidValue> GetPotentialInvalidValues(string propertyName, object value)
  60. {
  61. yield break;
  62. }
  63. public void Apply(PersistentClass persistentClass)
  64. {
  65. }
  66. public IEnumerable<Attribute> GetMemberConstraints(string propertyName)
  67. {
  68. yield break;
  69. }
  70. public IEnumerable<InvalidValue> GetInvalidValues(object entity, params object[] tags)
  71. {
  72. yield break;
  73. }
  74. public IEnumerable<InvalidValue> GetInvalidValues(object entity, string propertyName, params object[] tags)
  75. {
  76. yield break;
  77. }
  78. public IEnumerable<InvalidValue> GetPotentialInvalidValues(string propertyName, object value, params object[] tags)
  79. {
  80. yield break;
  81. }
  82. }
  83. public ValidatorEngine()
  84. {
  85. constraintValidatorFactory = Environment.ConstraintValidatorFactory ?? new DefaultConstraintValidatorFactory();
  86. entityTypeInspector = new DefaultEntityTypeInspector();
  87. factory = new StateFullClassValidatorFactory(constraintValidatorFactory, null, null, null, ValidatorMode.UseAttribute,
  88. entityTypeInspector);
  89. }
  90. /// <summary>
  91. /// Default MessageInterpolator
  92. /// </summary>
  93. public virtual IMessageInterpolator Interpolator
  94. {
  95. get { return interpolator; }
  96. }
  97. /// <summary>
  98. /// Default Mode to construct validators
  99. /// </summary>
  100. public virtual ValidatorMode DefaultMode
  101. {
  102. get { return defaultMode; }
  103. }
  104. /// <summary>
  105. /// Database schema-level validation enabled
  106. /// </summary>
  107. public virtual bool ApplyToDDL
  108. {
  109. get { return applyToDDL; }
  110. }
  111. /// <summary>
  112. /// NHibernate event-based validation
  113. /// </summary>
  114. public virtual bool AutoRegisterListeners
  115. {
  116. get { return autoRegisterListeners; }
  117. }
  118. /// <summary>
  119. /// Configure NHibernate.Validator using the <c>&lt;nhv-configuration&gt;</c> section
  120. /// from the application config file, if found, or the file <c>nhvalidator.cfg.xml</c> if the
  121. /// <c>&lt;nhv-configuration&gt;</c> section not include the session-factory configuration.
  122. /// If both are found merge the two configuration.
  123. /// </summary>
  124. /// <remarks>
  125. /// To configure NHibernate explicitly using <c>nhvalidator.cfg.xml</c>, appling merge/override
  126. /// of the application configuration file, use this code:
  127. /// <code>
  128. /// configuration.Configure("path/to/nhvalidator.cfg.xml");
  129. /// </code>
  130. /// </remarks>
  131. public virtual void Configure()
  132. {
  133. var nhvhc = ConfigurationManager.GetSection(CfgXmlHelper.CfgSectionName) as INHVConfiguration;
  134. if (nhvhc != null)
  135. {
  136. Configure(nhvhc);
  137. }
  138. string filePath = GetDefaultConfigurationFilePath();
  139. if (File.Exists(filePath))
  140. Configure(filePath); // merge the configuration
  141. }
  142. /// <summary>
  143. /// Configure NHibernate.Validator using the file specified.
  144. /// </summary>
  145. /// <param name="configFilePath">The location of the XML file to use to configure NHibernate.Validator.</param>
  146. /// <remarks>
  147. /// Calling Configure(string) will override/merge the values set in app.config or web.config
  148. /// </remarks>
  149. public virtual void Configure(string configFilePath)
  150. {
  151. using (var reader = new XmlTextReader(configFilePath))
  152. {
  153. Configure(reader);
  154. }
  155. }
  156. /// <summary>
  157. /// Configure NHibernate.Validator using the specified <see cref="XmlReader"/>.
  158. /// </summary>
  159. /// <param name="configReader">The <see cref="XmlReader"/> that contains the Xml to configure NHibernate.Validator.</param>
  160. /// <remarks>
  161. /// Calling Configure(XmlReader) will overwrite the values set in app.config or web.config
  162. /// </remarks>
  163. public virtual void Configure(XmlReader configReader)
  164. {
  165. if (configReader == null)
  166. {
  167. throw new ValidatorConfigurationException("Could not configure NHibernate.Validator.",
  168. new ArgumentNullException("configReader"));
  169. }
  170. INHVConfiguration nhvc = new XmlConfiguration(configReader);
  171. Configure(nhvc);
  172. }
  173. /// <summary>
  174. /// Configure NHibernate.Validator using the specified <see cref="INHVConfiguration"/>.
  175. /// </summary>
  176. /// <param name="config">The <see cref="INHVConfiguration"/> that is the configuration reader to configure NHibernate.Validator.</param>
  177. /// <remarks>
  178. /// Calling Configure(INHVConfiguration) will overwrite the values set in app.config or web.config.
  179. /// <para>
  180. /// You can use this overload is you are working with Attributes or Xml-files.
  181. /// </para>
  182. /// </remarks>
  183. public virtual void Configure(INHVConfiguration config)
  184. {
  185. Configure(config, config as IMappingLoader);
  186. }
  187. /// <summary>
  188. /// Configure NHibernate.Validator using the specified <see cref="INHVConfiguration"/>.
  189. /// </summary>
  190. /// <param name="config">The <see cref="INHVConfiguration"/> that is the configuration reader to configure NHibernate.Validator.</param>
  191. /// <param name="mappingLoader">The <see cref="XmlMappingLoader"/> instance.</param>
  192. /// <remarks>
  193. /// Calling Configure(INHVConfiguration) will overwrite the values set in app.config or web.config
  194. /// </remarks>
  195. public virtual void Configure(INHVConfiguration config, IMappingLoader mappingLoader)
  196. {
  197. if (config == null)
  198. {
  199. throw new ValidatorConfigurationException("Could not configure NHibernate.Validator.",
  200. new ArgumentNullException("config"));
  201. }
  202. Clear();
  203. applyToDDL = PropertiesHelper.GetBoolean(Environment.ApplyToDDL, config.Properties, true);
  204. autoRegisterListeners = PropertiesHelper.GetBoolean(Environment.AutoregisterListeners, config.Properties, true);
  205. defaultMode =
  206. CfgXmlHelper.ValidatorModeConvertFrom(PropertiesHelper.GetString(Environment.ValidatorMode, config.Properties,
  207. string.Empty));
  208. interpolator =
  209. GetImplementation<IMessageInterpolator>(
  210. PropertiesHelper.GetString(Environment.MessageInterpolatorClass, config.Properties, string.Empty),
  211. "message interpolator");
  212. if (Environment.ConstraintValidatorFactory == null)
  213. {
  214. constraintValidatorFactory = GetImplementation<IConstraintValidatorFactory>(
  215. PropertiesHelper.GetString(Environment.ConstraintValidatorFactoryClass,
  216. config.Properties,
  217. string.Empty),
  218. "Constraint Validator Factory") ?? new DefaultConstraintValidatorFactory();
  219. }
  220. else
  221. {
  222. constraintValidatorFactory = Environment.ConstraintValidatorFactory;
  223. }
  224. var inspectorsTypes = new HashSet<System.Type>(config.EntityTypeInspectors) {typeof (DefaultEntityTypeInspector)};
  225. if (inspectorsTypes.Count > 1)
  226. {
  227. var inspectors = config.EntityTypeInspectors.Select(typeInspector => Instatiate<IEntityTypeInspector>(typeInspector)).ToArray();
  228. entityTypeInspector = new MultiEntityTypeInspector(inspectors);
  229. }
  230. else
  231. {
  232. entityTypeInspector = new DefaultEntityTypeInspector();
  233. }
  234. ResourceManager customResourceManager = null;
  235. var customResourceManagerBaseName = PropertiesHelper.GetString(Environment.CustomResourceManager, config.Properties,
  236. null);
  237. if (!string.IsNullOrEmpty(customResourceManagerBaseName))
  238. {
  239. var resourceAndAssembly = TypeNameParser.Parse(customResourceManagerBaseName);
  240. try
  241. {
  242. var assembly = Assembly.Load(resourceAndAssembly.Assembly);
  243. customResourceManager = new ResourceManager(resourceAndAssembly.Type, assembly);
  244. }
  245. catch (Exception e)
  246. {
  247. throw new ValidatorConfigurationException("Could not configure NHibernate.Validator (custom resource manager).", e);
  248. }
  249. }
  250. factory = new StateFullClassValidatorFactory(constraintValidatorFactory, customResourceManager, null, interpolator, defaultMode,
  251. entityTypeInspector);
  252. // UpLoad Mappings
  253. if(mappingLoader == null)
  254. {
  255. // Configured or Default loader (XmlMappingLoader)
  256. mappingLoader = GetImplementation<IMappingLoader>(
  257. PropertiesHelper.GetString(Environment.MappingLoaderClass, config.Properties, string.Empty),
  258. "mapping loader") ?? new XmlMappingLoader();
  259. }
  260. mappingLoader.LoadMappings(config.Mappings);
  261. Initialize(mappingLoader);
  262. }
  263. private void Initialize(IMappingLoader loader)
  264. {
  265. factory.Initialize(loader);
  266. foreach (KeyValuePair<System.Type, IClassValidator> validator in factory.Validators)
  267. {
  268. AddValidatableElement(new ValidatableElement(validator.Key, validator.Value));
  269. }
  270. }
  271. public virtual void Clear()
  272. {
  273. validators.Clear();
  274. }
  275. /// <summary>
  276. /// Apply constraints/rules on a entity instance.
  277. /// </summary>
  278. /// <param name="entity">The entity instance to validate</param>
  279. /// <param name="activeTags">Tags included in the validation.</param>
  280. /// <returns>All the failures or an empty array if <paramref name="entity"/> is null.</returns>
  281. /// <remarks>
  282. /// If the <see cref="System.Type"/> of the <paramref name="entity"/> was never inspected, or
  283. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  284. /// </remarks>
  285. public virtual InvalidValue[] Validate(object entity, params object[] activeTags)
  286. {
  287. return InternalValidate(entity, activeTags).ToArray();
  288. }
  289. private IEnumerable<InvalidValue> InternalValidate(object entity, params object[] activeTags)
  290. {
  291. if (entity == null)
  292. return ClassValidator.EmptyInvalidValueArray;
  293. System.Type entityType = GuessEntityType(entity);
  294. if (!entityType.ShouldNeedValidation())
  295. return ClassValidator.EmptyInvalidValueArray;
  296. ValidatableElement element = GetElementOrNew(entityType);
  297. if(activeTags != null && activeTags.Length == 0)
  298. {
  299. activeTags = null;
  300. }
  301. return ValidateSubElements(element, entity, activeTags).Concat(element.Validator.GetInvalidValues(entity, activeTags));
  302. }
  303. private System.Type GuessEntityType(object entity)
  304. {
  305. System.Type result = entityTypeInspector.GuessType(entity);
  306. return result ?? entity.GetType();
  307. }
  308. private static IEnumerable<InvalidValue> ValidateSubElements(ValidatableElement element, object entity, params object[] activeTags)
  309. {
  310. if (element != null)
  311. {
  312. return from subElement in element.SubElements
  313. let component = subElement.Getter.Get(entity)
  314. from invalidValue in subElement.Validator.GetInvalidValues(component, activeTags).Concat(ValidateSubElements(subElement, component, activeTags))
  315. select invalidValue;
  316. }
  317. return ClassValidator.EmptyInvalidValueArray;
  318. }
  319. /// <summary>
  320. /// Apply constraints/rules on a entity instance.
  321. /// </summary>
  322. /// <param name="entity">The entity instance to validate</param>
  323. /// <param name="activeTags">Tags included in the validation.</param>
  324. /// <returns>
  325. /// False if there is one or more the failures; True otherwise (including when <paramref name="entity"/> is null).
  326. /// </returns>
  327. /// <remarks>
  328. /// If the <see cref="System.Type"/> of the <paramref name="entity"/> was never inspected, or
  329. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  330. /// </remarks>
  331. public virtual bool IsValid(object entity, params object[] activeTags)
  332. {
  333. return !InternalValidate(entity, activeTags).Any();
  334. }
  335. /// <summary>
  336. /// Assert a valid entity.
  337. /// </summary>
  338. /// <param name="entity">The entity instance to validate</param>
  339. /// <exception cref="InvalidStateException">when <paramref name="entity"/> have an invalid state.</exception>
  340. /// <remarks>
  341. /// If the <see cref="System.Type"/> of the <paramref name="entity"/> was never inspected, or
  342. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  343. /// </remarks>
  344. public virtual void AssertValid(object entity)
  345. {
  346. if (entity == null) return;
  347. ValidatableElement element = GetElementOrNew(GuessEntityType(entity));
  348. element.Validator.AssertValid(entity);
  349. }
  350. /// <summary>
  351. /// Use the <see cref="ClassValidator.GetPotentialInvalidValues(string, object)"/> for a given <see cref="System.Type"/>.
  352. /// </summary>
  353. /// <typeparam name="T">The entity type</typeparam>
  354. /// <param name="propertyName">The name of a property</param>
  355. /// <param name="value">The value of the property.</param>
  356. /// <param name="activeTags">Tags included in the validation.</param>
  357. /// <returns>All the invalid values.</returns>
  358. /// <remarks>
  359. /// If the <typeparamref name="T"/> was never inspected, or
  360. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  361. /// </remarks>
  362. public virtual InvalidValue[] ValidatePropertyValue<T>(string propertyName, object value, params object[] activeTags)
  363. {
  364. return ValidatePropertyValue(typeof(T), propertyName, value, activeTags);
  365. }
  366. /// <summary>
  367. /// Use the <see cref="ClassValidator.GetPotentialInvalidValues(string, object)"/> for a given <see cref="System.Type"/>.
  368. /// </summary>
  369. /// <typeparam name="TEntity">The entity type</typeparam>
  370. /// <typeparam name="TProperty">The property type.</typeparam>
  371. /// <param name="expression">The lamda expression of the property getter.</param>
  372. /// <param name="value">The potencial value of the property.</param>
  373. /// <param name="activeTags">Tags included in the validation.</param>
  374. /// <remarks>
  375. /// If the <typeparamref name="TEntity"/> was never inspected, or
  376. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  377. /// </remarks>
  378. public virtual InvalidValue[] ValidatePropertyValue<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> expression, TProperty value, params object[] activeTags) where TEntity : class
  379. {
  380. var propertyName = TypeUtils.DecodeMemberAccessExpression(expression).Name;
  381. return ValidatePropertyValue(typeof (TEntity), propertyName, value, activeTags);
  382. }
  383. /// <summary>
  384. /// Use the <see cref="ClassValidator.GetPotentialInvalidValues(string, object)"/> for a given entity instance.
  385. /// </summary>
  386. /// <param name="entity">The entity instance to validate</param>
  387. /// <param name="propertyName">The name of a property</param>
  388. /// <param name="activeTags">Tags included in the validation.</param>
  389. /// <returns>All the invalid values.</returns>
  390. /// <remarks>
  391. /// If the <see cref="System.Type"/> of the <paramref name="entity"/> was never inspected, or
  392. /// it was not configured, the <see cref="IClassValidator"/> will be automatic added to the engine.
  393. /// </remarks>
  394. public virtual InvalidValue[] ValidatePropertyValue(object entity, string propertyName, params object[] activeTags)
  395. {
  396. if (entity == null)
  397. return ClassValidator.EmptyInvalidValueArray;
  398. System.Type entityType = GuessEntityType(entity);
  399. if (!entityType.ShouldNeedValidation())
  400. return ClassValidator.EmptyInvalidValueArray;
  401. ValidatableElement element = GetElementOrNew(entityType);
  402. if (activeTags != null && activeTags.Length == 0)
  403. {
  404. activeTags = null;
  405. }
  406. return element.Validator.GetInvalidValues(entity, propertyName, activeTags).ToArray();
  407. }
  408. public virtual InvalidValue[] ValidatePropertyValue<TEntity, TProperty>(TEntity entity, Expression<Func<TEntity, TProperty>> expression, params object[] activeTags) where TEntity : class
  409. {
  410. return ValidatePropertyValue(entity, TypeUtils.DecodeMemberAccessExpression(expression).Name, activeTags);
  411. }
  412. /// <summary>
  413. /// Use the <see cref="ClassValidator.GetPotentialInvalidValues(string, object)"/> for a given entity instance.
  414. /// </summary>
  415. /// <param name="entityType">The entity instance to validate</param>
  416. /// <param name="propertyName">The name of a property</param>
  417. /// <param name="value">The value of the property.</param>
  418. /// <param name="activeTags">Tags included in the validation.</param>
  419. /// <returns>All the invalid values.</returns>
  420. public virtual InvalidValue[] ValidatePropertyValue(System.Type entityType, string propertyName, object value, params object[] activeTags)
  421. {
  422. IClassValidator cv = GetElementOrNew(entityType).Validator;
  423. if (activeTags != null && activeTags.Length == 0)
  424. {
  425. activeTags = null;
  426. }
  427. return cv.GetPotentialInvalidValues(propertyName, value, activeTags).ToArray();
  428. }
  429. /// <summary>
  430. /// Add a validator to the engine or override existing one.
  431. /// </summary>
  432. /// <typeparam name="T">The type of an entity.</typeparam>
  433. /// <remarks>
  434. /// Create an istance of <see cref="IClassValidator"/> for the given <typeparamref name="T"/>.
  435. /// </remarks>
  436. public virtual void AddValidator<T>()
  437. {
  438. AddValidator<T>(null);
  439. }
  440. /// <summary>
  441. /// Add a validator to the engine or override existing one.
  442. /// </summary>
  443. /// <typeparam name="T">The type of an entity.</typeparam>
  444. /// <param name="inspector">Inspector for sub-elements</param>
  445. public virtual void AddValidator<T>(IValidatableSubElementsInspector inspector)
  446. {
  447. AddValidator(typeof (T), inspector);
  448. }
  449. internal void AddValidator(System.Type entityType, IValidatableSubElementsInspector inspector)
  450. {
  451. IClassValidator cv = GetClassValidator(entityType);
  452. var element = new ValidatableElement(entityType, cv);
  453. if (inspector != null)
  454. inspector.Inspect(element);
  455. AddValidatableElement(element);
  456. }
  457. internal void AddValidatableElement(ValidatableElement element)
  458. {
  459. if (element.HasSubElements || element.Validator.HasValidationRules)
  460. validators[element.EntityType] = element;
  461. else
  462. validators[element.EntityType] = AlwaysValidPlaceHolder;
  463. }
  464. /// <summary>
  465. /// Gets an acquaintance <see cref="IClassValidator"/>.
  466. /// </summary>
  467. /// <typeparam name="T">The type of an entity.</typeparam>
  468. /// <returns>A acquaintance <see cref="IClassValidator"/> for the give type
  469. /// or null if the the <typeparamref name="T"/> was never used in the engine instance.</returns>
  470. public virtual IClassValidator GetValidator<T>()
  471. {
  472. return GetValidator(typeof(T));
  473. }
  474. private ValidatableElement GetElementOrNew(System.Type entityType)
  475. {
  476. ValidatableElement element;
  477. if (!validators.TryGetValue(entityType, out element))
  478. {
  479. IClassValidator cv = GetClassValidator(entityType);
  480. element = new ValidatableElement(entityType, cv);
  481. AddValidatableElement(element);
  482. }
  483. return element;
  484. }
  485. internal IClassValidator GetValidator(System.Type entityType)
  486. {
  487. ValidatableElement element;
  488. validators.TryGetValue(entityType, out element);
  489. return element == null ? null : element.Validator;
  490. }
  491. /// <summary>
  492. /// Gets a <see cref="IClassValidator"/> for a given <see cref="System.Type"/>
  493. /// </summary>
  494. /// <param name="entityType">The given <see cref="System.Type"/>.</param>
  495. /// <returns>
  496. /// A validator for a <see cref="System.Type"/> or null if the <paramref name="entityType"/>
  497. /// is not supported by <see cref="ClassValidator"/>.
  498. /// </returns>
  499. /// <remarks>
  500. /// In general a common application don't need to use this method but it can be useful for some kind of framework.
  501. /// </remarks>
  502. public virtual IClassValidator GetClassValidator(System.Type entityType)
  503. {
  504. if (!entityType.ShouldNeedValidation())
  505. return null;
  506. return factory.GetRootValidator(entityType);
  507. }
  508. private static T GetImplementation<T>(string classQualifiedName, string frendlyName) where T:class
  509. {
  510. if (!string.IsNullOrEmpty(classQualifiedName))
  511. {
  512. try
  513. {
  514. System.Type type = ReflectHelper.ClassForName(classQualifiedName);
  515. return Instatiate<T>(type);
  516. }
  517. catch (ValidatorConfigurationException)
  518. {
  519. throw;
  520. }
  521. catch (Exception ex)
  522. {
  523. throw new ValidatorConfigurationException("Unable to instanciate " + frendlyName + ": " + classQualifiedName, ex);
  524. }
  525. }
  526. return null;
  527. }
  528. private static T Instatiate<T>(System.Type type)
  529. {
  530. try
  531. {
  532. return (T)Activator.CreateInstance(type);
  533. }
  534. catch (MissingMethodException ex)
  535. {
  536. throw new ValidatorConfigurationException("Public constructor was not found at : " + type.AssemblyQualifiedName, ex);
  537. }
  538. catch (InvalidCastException ex)
  539. {
  540. throw new ValidatorConfigurationException(
  541. "Type does not implement '" + typeof(T).FullName + "': " + type.AssemblyQualifiedName, ex);
  542. }
  543. }
  544. private static string GetDefaultConfigurationFilePath()
  545. {
  546. string baseDir = AppDomain.CurrentDomain.BaseDirectory;
  547. string relativeSearchPath = AppDomain.CurrentDomain.RelativeSearchPath;
  548. string binPath = relativeSearchPath == null ? baseDir : Path.Combine(baseDir, relativeSearchPath);
  549. return Path.Combine(binPath, CfgXmlHelper.DefaultNHVCfgFileName);
  550. }
  551. }
  552. }