ServiceMetadataBehavior.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Description
  5. {
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Collections.ObjectModel;
  9. using System.ComponentModel;
  10. using System.Diagnostics;
  11. using System.Runtime;
  12. using System.Runtime.Diagnostics;
  13. using System.ServiceModel.Channels;
  14. using System.ServiceModel.Diagnostics;
  15. using System.ServiceModel.Dispatcher;
  16. using System.Xml;
  17. public class ServiceMetadataBehavior : IServiceBehavior
  18. {
  19. public const string MexContractName = "IMetadataExchange";
  20. internal const string MexContractNamespace = "http://schemas.microsoft.com/2006/04/mex";
  21. static readonly Uri emptyUri = new Uri(String.Empty, UriKind.Relative);
  22. bool httpGetEnabled = false;
  23. bool httpsGetEnabled = false;
  24. Uri httpGetUrl;
  25. Uri httpsGetUrl;
  26. Binding httpGetBinding;
  27. Binding httpsGetBinding;
  28. Uri externalMetadataLocation = null;
  29. MetadataExporter metadataExporter = null;
  30. static ContractDescription mexContract = null;
  31. static object thisLock = new object();
  32. public bool HttpGetEnabled
  33. {
  34. get { return this.httpGetEnabled; }
  35. set { this.httpGetEnabled = value; }
  36. }
  37. [TypeConverter(typeof(UriTypeConverter))]
  38. public Uri HttpGetUrl
  39. {
  40. get { return this.httpGetUrl; }
  41. set
  42. {
  43. if (value != null && value.IsAbsoluteUri && value.Scheme != Uri.UriSchemeHttp)
  44. {
  45. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxServiceMetadataBehaviorUrlMustBeHttpOrRelative,
  46. "HttpGetUrl", Uri.UriSchemeHttp, value.ToString(), value.Scheme));
  47. }
  48. this.httpGetUrl = value;
  49. }
  50. }
  51. public bool HttpsGetEnabled
  52. {
  53. get { return this.httpsGetEnabled; }
  54. set { this.httpsGetEnabled = value; }
  55. }
  56. [TypeConverter(typeof(UriTypeConverter))]
  57. public Uri HttpsGetUrl
  58. {
  59. get { return this.httpsGetUrl; }
  60. set
  61. {
  62. if (value != null && value.IsAbsoluteUri && value.Scheme != Uri.UriSchemeHttps)
  63. {
  64. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxServiceMetadataBehaviorUrlMustBeHttpOrRelative,
  65. "HttpsGetUrl", Uri.UriSchemeHttps, value.ToString(), value.Scheme));
  66. }
  67. this.httpsGetUrl = value;
  68. }
  69. }
  70. public Binding HttpGetBinding
  71. {
  72. get { return this.httpGetBinding; }
  73. set
  74. {
  75. if (value != null)
  76. {
  77. if (!value.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
  78. {
  79. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxBindingSchemeDoesNotMatch,
  80. value.Scheme, value.GetType().ToString(), Uri.UriSchemeHttp));
  81. }
  82. CustomBinding customBinding = new CustomBinding(value);
  83. TextMessageEncodingBindingElement textMessageEncodingBindingElement = customBinding.Elements.Find<TextMessageEncodingBindingElement>();
  84. if (textMessageEncodingBindingElement != null && !textMessageEncodingBindingElement.MessageVersion.IsMatch(MessageVersion.None))
  85. {
  86. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxIncorrectMessageVersion,
  87. textMessageEncodingBindingElement.MessageVersion.ToString(), MessageVersion.None.ToString()));
  88. }
  89. HttpTransportBindingElement httpTransportBindingElement = customBinding.Elements.Find<HttpTransportBindingElement>();
  90. if (httpTransportBindingElement != null)
  91. {
  92. httpTransportBindingElement.Method = "GET";
  93. }
  94. this.httpGetBinding = customBinding;
  95. }
  96. }
  97. }
  98. public Binding HttpsGetBinding
  99. {
  100. get { return this.httpsGetBinding; }
  101. set
  102. {
  103. if (value != null)
  104. {
  105. if (!value.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
  106. {
  107. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxBindingSchemeDoesNotMatch,
  108. value.Scheme, value.GetType().ToString(), Uri.UriSchemeHttps));
  109. }
  110. CustomBinding customBinding = new CustomBinding(value);
  111. TextMessageEncodingBindingElement textMessageEncodingBindingElement = customBinding.Elements.Find<TextMessageEncodingBindingElement>();
  112. if (textMessageEncodingBindingElement != null && !textMessageEncodingBindingElement.MessageVersion.IsMatch(MessageVersion.None))
  113. {
  114. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxIncorrectMessageVersion,
  115. textMessageEncodingBindingElement.MessageVersion.ToString(), MessageVersion.None.ToString()));
  116. }
  117. HttpsTransportBindingElement httpsTransportBindingElement = customBinding.Elements.Find<HttpsTransportBindingElement>();
  118. if (httpsTransportBindingElement != null)
  119. {
  120. httpsTransportBindingElement.Method = "GET";
  121. }
  122. this.httpsGetBinding = customBinding;
  123. }
  124. }
  125. }
  126. [TypeConverter(typeof(UriTypeConverter))]
  127. public Uri ExternalMetadataLocation
  128. {
  129. get { return this.externalMetadataLocation; }
  130. set
  131. {
  132. if (value != null && value.IsAbsoluteUri && !(value.Scheme == Uri.UriSchemeHttp || value.Scheme == Uri.UriSchemeHttps))
  133. {
  134. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("ExternalMetadataLocation", SR.GetString(SR.SFxBadMetadataLocationUri, value.OriginalString, value.Scheme));
  135. }
  136. this.externalMetadataLocation = value;
  137. }
  138. }
  139. public MetadataExporter MetadataExporter
  140. {
  141. get
  142. {
  143. if (this.metadataExporter == null)
  144. this.metadataExporter = new WsdlExporter();
  145. return this.metadataExporter;
  146. }
  147. set
  148. {
  149. this.metadataExporter = value;
  150. }
  151. }
  152. static internal ContractDescription MexContract
  153. {
  154. get
  155. {
  156. EnsureMexContractDescription();
  157. return ServiceMetadataBehavior.mexContract;
  158. }
  159. }
  160. void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
  161. {
  162. }
  163. void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
  164. {
  165. }
  166. void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
  167. {
  168. if (description == null)
  169. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
  170. if (serviceHostBase == null)
  171. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceHostBase");
  172. ApplyBehavior(description, serviceHostBase);
  173. }
  174. void ApplyBehavior(ServiceDescription description, ServiceHostBase host)
  175. {
  176. ServiceMetadataExtension mex = ServiceMetadataExtension.EnsureServiceMetadataExtension(description, host);
  177. SetExtensionProperties(description, host, mex);
  178. CustomizeMetadataEndpoints(description, host, mex);
  179. CreateHttpGetEndpoints(description, host, mex);
  180. }
  181. private void CreateHttpGetEndpoints(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtension mex)
  182. {
  183. bool httpDispatcherEnabled = false;
  184. bool httpsDispatcherEnabled = false;
  185. if (this.httpGetEnabled)
  186. {
  187. httpDispatcherEnabled = EnsureGetDispatcher(host, mex, this.httpGetUrl, Uri.UriSchemeHttp);
  188. }
  189. if (this.httpsGetEnabled)
  190. {
  191. httpsDispatcherEnabled = EnsureGetDispatcher(host, mex, this.httpsGetUrl, Uri.UriSchemeHttps);
  192. }
  193. if (!httpDispatcherEnabled && !httpsDispatcherEnabled)
  194. {
  195. if (this.httpGetEnabled)
  196. {
  197. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceMetadataBehaviorNoHttpBaseAddress)));
  198. }
  199. if (this.httpsGetEnabled)
  200. {
  201. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceMetadataBehaviorNoHttpsBaseAddress)));
  202. }
  203. }
  204. }
  205. static bool EnsureGetDispatcher(ServiceHostBase host, ServiceMetadataExtension mex, Uri url, string scheme)
  206. {
  207. Uri address = host.GetVia(scheme, url == null ? new Uri(string.Empty, UriKind.Relative) : url);
  208. if (address != null)
  209. {
  210. ChannelDispatcher channelDispatcher = mex.EnsureGetDispatcher(address, false /* isServiceDebugBehavior */);
  211. ((ServiceMetadataExtension.HttpGetImpl)channelDispatcher.Endpoints[0].DispatchRuntime.SingletonInstanceContext.UserObject).GetWsdlEnabled = true;
  212. return true;
  213. }
  214. return false;
  215. }
  216. void SetExtensionProperties(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtension mex)
  217. {
  218. mex.ExternalMetadataLocation = this.ExternalMetadataLocation;
  219. mex.Initializer = new MetadataExtensionInitializer(this, description, host);
  220. mex.HttpGetEnabled = this.httpGetEnabled;
  221. mex.HttpsGetEnabled = this.httpsGetEnabled;
  222. mex.HttpGetUrl = host.GetVia(Uri.UriSchemeHttp, this.httpGetUrl == null ? new Uri(string.Empty, UriKind.Relative) : this.httpGetUrl);
  223. mex.HttpsGetUrl = host.GetVia(Uri.UriSchemeHttps, this.httpsGetUrl == null ? new Uri(string.Empty, UriKind.Relative) : this.httpsGetUrl);
  224. mex.HttpGetBinding = this.httpGetBinding;
  225. mex.HttpsGetBinding = this.httpsGetBinding;
  226. UseRequestHeadersForMetadataAddressBehavior dynamicUpdateBehavior = description.Behaviors.Find<UseRequestHeadersForMetadataAddressBehavior>();
  227. if (dynamicUpdateBehavior != null)
  228. {
  229. mex.UpdateAddressDynamically = true;
  230. mex.UpdatePortsByScheme = new Dictionary<string, int>(dynamicUpdateBehavior.DefaultPortsByScheme);
  231. }
  232. foreach (ChannelDispatcherBase dispatcherBase in host.ChannelDispatchers)
  233. {
  234. ChannelDispatcher dispatcher = dispatcherBase as ChannelDispatcher;
  235. if (dispatcher != null && IsMetadataTransferDispatcher(description, dispatcher))
  236. {
  237. mex.MexEnabled = true;
  238. mex.MexUrl = dispatcher.Listener.Uri;
  239. if (dynamicUpdateBehavior != null)
  240. {
  241. foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
  242. {
  243. if (!endpointDispatcher.AddressFilterSetExplicit)
  244. {
  245. endpointDispatcher.AddressFilter = new MatchAllMessageFilter();
  246. }
  247. }
  248. }
  249. break;
  250. }
  251. }
  252. }
  253. private static void CustomizeMetadataEndpoints(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtension mex)
  254. {
  255. for (int i = 0; i < host.ChannelDispatchers.Count; i++)
  256. {
  257. ChannelDispatcher channelDispatcher = host.ChannelDispatchers[i] as ChannelDispatcher;
  258. if (channelDispatcher != null && ServiceMetadataBehavior.IsMetadataTransferDispatcher(description, channelDispatcher))
  259. {
  260. if (channelDispatcher.Endpoints.Count != 1)
  261. {
  262. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  263. new InvalidOperationException(SR.GetString(SR.SFxServiceMetadataBehaviorInstancingError, channelDispatcher.Listener.Uri, channelDispatcher.CreateContractListString())));
  264. }
  265. DispatchRuntime dispatcher = channelDispatcher.Endpoints[0].DispatchRuntime;
  266. // set instancing
  267. dispatcher.InstanceContextProvider =
  268. InstanceContextProviderBase.GetProviderForMode(InstanceContextMode.Single, dispatcher);
  269. bool isListeningOnHttps = channelDispatcher.Listener.Uri.Scheme == Uri.UriSchemeHttps;
  270. Uri listenUri = channelDispatcher.Listener.Uri;
  271. ServiceMetadataExtension.WSMexImpl impl = new ServiceMetadataExtension.WSMexImpl(mex, isListeningOnHttps, listenUri);
  272. dispatcher.SingletonInstanceContext = new InstanceContext(host, impl, false);
  273. }
  274. }
  275. }
  276. static EndpointDispatcher GetListenerByID(SynchronizedCollection<ChannelDispatcherBase> channelDispatchers, string id)
  277. {
  278. for (int i = 0; i < channelDispatchers.Count; ++i)
  279. {
  280. ChannelDispatcher channelDispatcher = channelDispatchers[i] as ChannelDispatcher;
  281. if (channelDispatcher != null)
  282. {
  283. for (int j = 0; j < channelDispatcher.Endpoints.Count; ++j)
  284. {
  285. EndpointDispatcher endpointDispatcher = channelDispatcher.Endpoints[j];
  286. if (endpointDispatcher.Id == id)
  287. return endpointDispatcher;
  288. }
  289. }
  290. }
  291. return null;
  292. }
  293. internal static bool IsMetadataDispatcher(ServiceDescription description, ChannelDispatcher channelDispatcher)
  294. {
  295. foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
  296. {
  297. if (IsMetadataTransferDispatcher(description, channelDispatcher)
  298. || IsHttpGetMetadataDispatcher(description, channelDispatcher))
  299. return true;
  300. }
  301. return false;
  302. }
  303. static bool IsMetadataTransferDispatcher(ServiceDescription description, ChannelDispatcher channelDispatcher)
  304. {
  305. if (BehaviorMissingObjectNullOrServiceImplements(description, channelDispatcher))
  306. return false;
  307. foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
  308. {
  309. if (endpointDispatcher.ContractName == ServiceMetadataBehavior.MexContractName
  310. && endpointDispatcher.ContractNamespace == ServiceMetadataBehavior.MexContractNamespace)
  311. return true;
  312. }
  313. return false;
  314. }
  315. private static bool BehaviorMissingObjectNullOrServiceImplements(ServiceDescription description, object obj)
  316. {
  317. if (obj == null)
  318. return true;
  319. if (description.Behaviors != null && description.Behaviors.Find<ServiceMetadataBehavior>() == null)
  320. return true;
  321. if (description.ServiceType != null && description.ServiceType.GetInterface(typeof(IMetadataExchange).Name) != null)
  322. return true;
  323. return false;
  324. }
  325. internal static bool IsHttpGetMetadataDispatcher(ServiceDescription description, ChannelDispatcher channelDispatcher)
  326. {
  327. if (description.Behaviors.Find<ServiceMetadataBehavior>() == null)
  328. return false;
  329. foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
  330. {
  331. if (endpointDispatcher.ContractName == ServiceMetadataExtension.HttpGetImpl.ContractName
  332. && endpointDispatcher.ContractNamespace == ServiceMetadataExtension.HttpGetImpl.ContractNamespace)
  333. return true;
  334. }
  335. return false;
  336. }
  337. internal static bool IsMetadataEndpoint(ServiceDescription description, ServiceEndpoint endpoint)
  338. {
  339. if (BehaviorMissingObjectNullOrServiceImplements(description, endpoint))
  340. return false;
  341. return IsMetadataEndpoint(endpoint);
  342. }
  343. static bool IsMetadataEndpoint(ServiceEndpoint endpoint)
  344. {
  345. return (endpoint.Contract.Name == ServiceMetadataBehavior.MexContractName
  346. && endpoint.Contract.Namespace == ServiceMetadataBehavior.MexContractNamespace);
  347. }
  348. internal static bool IsMetadataImplementedType(ServiceDescription description, Type type)
  349. {
  350. if (BehaviorMissingObjectNullOrServiceImplements(description, type))
  351. return false;
  352. return type == typeof(IMetadataExchange);
  353. }
  354. internal static bool IsMetadataImplementedType(Type type)
  355. {
  356. return type == typeof(IMetadataExchange);
  357. }
  358. internal void AddImplementedContracts(ServiceHostBase.ServiceAndBehaviorsContractResolver resolver)
  359. {
  360. if (!resolver.BehaviorContracts.ContainsKey(MexContractName))
  361. {
  362. resolver.BehaviorContracts.Add(MexContractName, ServiceMetadataBehavior.MexContract);
  363. }
  364. }
  365. static void EnsureMexContractDescription()
  366. {
  367. if (ServiceMetadataBehavior.mexContract == null)
  368. {
  369. lock (thisLock)
  370. {
  371. if (ServiceMetadataBehavior.mexContract == null)
  372. {
  373. ServiceMetadataBehavior.mexContract = CreateMexContract();
  374. }
  375. }
  376. }
  377. }
  378. static ContractDescription CreateMexContract()
  379. {
  380. ContractDescription mexContract = ContractDescription.GetContract(typeof(IMetadataExchange));
  381. foreach (OperationDescription operation in mexContract.Operations)
  382. {
  383. operation.Behaviors.Find<OperationBehaviorAttribute>().Impersonation = ImpersonationOption.Allowed;
  384. }
  385. mexContract.Behaviors.Add(new ServiceMetadataContractBehavior(true));
  386. return mexContract;
  387. }
  388. internal class MetadataExtensionInitializer
  389. {
  390. ServiceMetadataBehavior behavior;
  391. ServiceDescription description;
  392. ServiceHostBase host;
  393. Exception metadataGenerationException = null;
  394. internal MetadataExtensionInitializer(ServiceMetadataBehavior behavior, ServiceDescription description, ServiceHostBase host)
  395. {
  396. this.behavior = behavior;
  397. this.description = description;
  398. this.host = host;
  399. }
  400. internal MetadataSet GenerateMetadata()
  401. {
  402. if (this.behavior.ExternalMetadataLocation == null || this.behavior.ExternalMetadataLocation.ToString() == string.Empty)
  403. {
  404. if (this.metadataGenerationException != null)
  405. throw this.metadataGenerationException;
  406. try
  407. {
  408. MetadataExporter exporter = this.behavior.MetadataExporter;
  409. XmlQualifiedName serviceName = new XmlQualifiedName(this.description.Name, this.description.Namespace);
  410. Collection<ServiceEndpoint> exportedEndpoints = new Collection<ServiceEndpoint>();
  411. foreach (ServiceEndpoint endpoint in this.description.Endpoints)
  412. {
  413. ServiceMetadataContractBehavior contractBehavior = endpoint.Contract.Behaviors.Find<ServiceMetadataContractBehavior>();
  414. // if contract behavior exists, generate metadata when the behavior allows metadata generation
  415. // if contract behavior doesn't exist, generate metadata only for non system endpoints
  416. if ((contractBehavior != null && !contractBehavior.MetadataGenerationDisabled) ||
  417. (contractBehavior == null && !endpoint.IsSystemEndpoint))
  418. {
  419. EndpointAddress address = null;
  420. EndpointDispatcher endpointDispatcher = GetListenerByID(this.host.ChannelDispatchers, endpoint.Id);
  421. if (endpointDispatcher != null)
  422. {
  423. address = endpointDispatcher.EndpointAddress;
  424. }
  425. ServiceEndpoint exportedEndpoint = new ServiceEndpoint(endpoint.Contract);
  426. exportedEndpoint.Binding = endpoint.Binding;
  427. exportedEndpoint.Name = endpoint.Name;
  428. exportedEndpoint.Address = address;
  429. foreach (IEndpointBehavior behavior in endpoint.Behaviors)
  430. {
  431. exportedEndpoint.Behaviors.Add(behavior);
  432. }
  433. exportedEndpoints.Add(exportedEndpoint);
  434. }
  435. }
  436. WsdlExporter wsdlExporter = exporter as WsdlExporter;
  437. if (wsdlExporter != null)
  438. {
  439. // Pass the BindingParameterCollection into the ExportEndpoints method so that the binding parameters can be using to export WSDL correctly.
  440. // The binding parameters are used in BuildChannelListener, during which they can modify the configuration of the channel in ways that might have to
  441. // be communicated in the WSDL. For example, in the case of Multi-Auth, the AuthenticationSchemesBindingParameter is used during BuildChannelListener
  442. // to set the AuthenticationSchemes supported by the virtual directory on the HttpTransportBindingElement. These authentication schemes also need
  443. // to be in the WSDL, so that clients know what authentication schemes are supported by the service. (see CSDMain #180381)
  444. Fx.Assert(this.host != null, "ServiceHostBase field on MetadataExtensionInitializer should never be null.");
  445. wsdlExporter.ExportEndpoints(exportedEndpoints, serviceName, this.host.GetBindingParameters(exportedEndpoints));
  446. }
  447. else
  448. {
  449. foreach (ServiceEndpoint endpoint in exportedEndpoints)
  450. {
  451. exporter.ExportEndpoint(endpoint);
  452. }
  453. }
  454. if (exporter.Errors.Count > 0 && DiagnosticUtility.ShouldTraceWarning)
  455. {
  456. TraceWsdlExportErrors(exporter);
  457. }
  458. return exporter.GetGeneratedMetadata();
  459. }
  460. catch (Exception e)
  461. {
  462. this.metadataGenerationException = e;
  463. throw;
  464. }
  465. }
  466. return null;
  467. }
  468. static void TraceWsdlExportErrors(MetadataExporter exporter)
  469. {
  470. foreach (MetadataConversionError error in exporter.Errors)
  471. {
  472. if (DiagnosticUtility.ShouldTraceWarning)
  473. {
  474. Hashtable h = new Hashtable(2)
  475. {
  476. { "IsWarning", error.IsWarning },
  477. { "Message", error.Message }
  478. };
  479. TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.WsmexNonCriticalWsdlExportError,
  480. SR.GetString(SR.TraceCodeWsmexNonCriticalWsdlExportError), new DictionaryTraceRecord(h), null, null);
  481. }
  482. }
  483. }
  484. }
  485. }
  486. }