From f4112894918edcd4d6c52ca012ada1f21ba99446 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 14 Apr 2012 14:49:15 +0100 Subject: [PATCH] Support discovering services using metadata exchange. --- .../Project/ICSharpCode.SharpDevelop.csproj | 2 + .../AddServiceReferenceViewModel.cs | 94 +++++++++---------- .../ServiceReferenceDiscoveryClient.cs | 90 ++++++++++++++++++ .../ServiceReferenceDiscoveryEventArgs.cs | 57 +++++++++++ 4 files changed, 191 insertions(+), 52 deletions(-) create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryClient.cs create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryEventArgs.cs diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index cc17ed5a4e..0e8f4c245b 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -280,6 +280,8 @@ + + diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/AddServiceReferenceViewModel.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/AddServiceReferenceViewModel.cs index 604b12b38f..8da3b889a1 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/AddServiceReferenceViewModel.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/AddServiceReferenceViewModel.cs @@ -43,9 +43,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference ServiceItem myItem; Uri discoveryUri; - ServiceDescriptionCollection serviceDescriptionCollection = new ServiceDescriptionCollection(); CredentialCache credentialCache = new CredentialCache(); WebServiceDiscoveryClientProtocol discoveryClientProtocol; + ServiceReferenceDiscoveryClient serviceReferenceDiscoveryClient; delegate DiscoveryDocument DiscoverAnyAsync(string url); delegate void DiscoveredWebServicesHandler(DiscoveryClientProtocol protocol); @@ -121,13 +121,32 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference AsyncCallback callback = new AsyncCallback(DiscoveryCompleted); discoveryClientProtocol.Credentials = credential; IAsyncResult result = asyncDelegate.BeginInvoke(uri.AbsoluteUri, callback, new AsyncDiscoveryState(discoveryClientProtocol, uri, credential)); + + serviceReferenceDiscoveryClient.DiscoveryComplete += ServiceReferenceDiscoveryComplete; + serviceReferenceDiscoveryClient.Discover(uri); + } + + void ServiceReferenceDiscoveryComplete(object sender, ServiceReferenceDiscoveryEventArgs e) + { + if (Object.ReferenceEquals(serviceReferenceDiscoveryClient, sender)) { + if (e.HasError) { + OnWebServiceDiscoveryError(e.Error); + } else { + DiscoveredWebServices(e.Services); + } + } + } + + void OnWebServiceDiscoveryError(Exception ex) + { + ServiceDescriptionMessage = ex.Message; + ICSharpCode.Core.LoggingService.Debug("DiscoveryCompleted: " + ex.ToString()); } /// /// Called after an asynchronous web services search has /// completed. /// - /// void DiscoveryCompleted(IAsyncResult result) { AsyncDiscoveryState state = (AsyncDiscoveryState)result.AsyncState; @@ -144,20 +163,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference try { DiscoverAnyAsync asyncDelegate = (DiscoverAnyAsync)((AsyncResult)result).AsyncDelegate; DiscoveryDocument handlerdoc = asyncDelegate.EndInvoke(result); - if (!state.Credential.IsDefaultAuthenticationType) { - AddCredential(state.Uri, state.Credential); - } handler(protocol); } catch (Exception ex) { - if (protocol.IsAuthenticationRequired) { - HttpAuthenticationHeader authHeader = protocol.GetAuthenticationHeader(); - AuthenticationHandler authHandler = new AuthenticationHandler(AuthenticateUser); -// trouble Invoke(authHandler, new object[] {state.Uri, authHeader.AuthenticationType}); - } else { - ServiceDescriptionMessage = ex.Message; - ICSharpCode.Core.LoggingService.Error("DiscoveryCompleted", ex); -// trouble Invoke(handler, new object[] {null}); - } + OnWebServiceDiscoveryError(ex); } } } @@ -180,47 +188,30 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference discoveryClientProtocol.Dispose(); } discoveryClientProtocol = new WebServiceDiscoveryClientProtocol(); + serviceReferenceDiscoveryClient = new ServiceReferenceDiscoveryClient(); } } - void AuthenticateUser(Uri uri, string authenticationType) - { - DiscoveryNetworkCredential credential = (DiscoveryNetworkCredential)credentialCache.GetCredential(uri, authenticationType); - if (credential != null) { - StartDiscovery(uri, credential); - } else { - using (UserCredentialsDialog credentialsForm = new UserCredentialsDialog(uri.ToString(), authenticationType)) { -// if (DialogResult.OK == credentialsForm.ShowDialog(WorkbenchSingleton.MainWin32Window)) { -// StartDiscovery(uri, credentialsForm.Credential); -// } - } - } - } - - void AddCredential(Uri uri, DiscoveryNetworkCredential credential) + void DiscoveredWebServices(DiscoveryClientProtocol protocol) { - NetworkCredential matchedCredential = credentialCache.GetCredential(uri, credential.AuthenticationType); - if (matchedCredential != null) { - credentialCache.Remove(uri, credential.AuthenticationType); + if (protocol != null) { + ServiceDescriptionCollection services = ServiceReferenceHelper.GetServiceDescriptions(protocol); + DiscoveredWebServices(services); } - credentialCache.Add(uri, credential.AuthenticationType, credential); } - void DiscoveredWebServices(DiscoveryClientProtocol protocol) + void DiscoveredWebServices(ServiceDescriptionCollection services) { - if (protocol != null) { - serviceDescriptionCollection = ServiceReferenceHelper.GetServiceDescriptions(protocol); - ServiceDescriptionMessage = String.Format( - "{0} service(s) found at address {1}", - serviceDescriptionCollection.Count, - discoveryUri); - if (serviceDescriptionCollection.Count > 0) { - AddUrlToHistory(discoveryUri); - } - DefaultNameSpace = GetDefaultNamespace(); - FillItems(serviceDescriptionCollection); - string referenceName = ServiceReferenceHelper.GetReferenceName(discoveryUri); + ServiceDescriptionMessage = String.Format( + "{0} service(s) found at address {1}", + services.Count, + discoveryUri); + if (services.Count > 0) { + AddUrlToHistory(discoveryUri); } + DefaultNameSpace = GetDefaultNamespace(); + FillItems(services); + string referenceName = ServiceReferenceHelper.GetReferenceName(discoveryUri); } void AddUrlToHistory(Uri discoveryUri) @@ -312,14 +303,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference void UpdateListView() { - ServiceDescription desc = null; TwoValues.Clear(); - if(ServiceItem.Tag is ServiceDescription) { - desc = (ServiceDescription)ServiceItem.Tag; + if (ServiceItem.Tag is ServiceDescription) { + ServiceDescription desc = (ServiceDescription)ServiceItem.Tag; var tv = new ImageAndDescription(PresentationResourceService.GetBitmapSource("Icons.16x16.Interface"), desc.RetrievalUrl); TwoValues.Add(tv); - } else if(ServiceItem.Tag is PortType) { + } else if (ServiceItem.Tag is PortType) { PortType portType = (PortType)ServiceItem.Tag; foreach (Operation op in portType.Operations) { TwoValues.Add(new ImageAndDescription(PresentationResourceService.GetBitmapSource("Icons.16x16.Method"), @@ -330,7 +320,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference void FillItems(ServiceDescriptionCollection descriptions) { - foreach(ServiceDescription element in descriptions) { + foreach (ServiceDescription element in descriptions) { Add(element); } } @@ -342,7 +332,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference var rootNode = new ServiceItem(null, name); rootNode.Tag = description; - foreach(Service service in description.Services) { + foreach (Service service in description.Services) { var serviceNode = new ServiceItem(null, service.Name); serviceNode.Tag = service; items.Add(serviceNode); diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryClient.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryClient.cs new file mode 100644 index 0000000000..fb7620e2b6 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryClient.cs @@ -0,0 +1,90 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ServiceModel.Description; + +namespace ICSharpCode.SharpDevelop.Gui +{ + public class ServiceReferenceDiscoveryClient + { + const int DiscoveryClientsUsed = 2; + + Uri discoveryUrl; + BackgroundWorker mexDiscoveryBackgroundWorker = new BackgroundWorker(); + BackgroundWorker mexRelativePathDiscoveryBackgroundWorker = new BackgroundWorker(); + List errors = new List(); + + public ServiceReferenceDiscoveryClient() + { + } + + public event EventHandler DiscoveryComplete; + + protected virtual void OnDiscoveryComplete(ServiceReferenceDiscoveryEventArgs e) + { + if (DiscoveryComplete != null) { + DiscoveryComplete(this, e); + } + } + + public void Discover(Uri url) + { + this.discoveryUrl = url; + DiscoverMexMetadata(); + } + + void DiscoverMexMetadata() + { + DiscoverMexMetadata(mexDiscoveryBackgroundWorker, discoveryUrl); + DiscoverMexMetadata(mexRelativePathDiscoveryBackgroundWorker, GetRelativeUrl("mex")); + } + + Uri GetRelativeUrl(string relativeUrl) + { + return new Uri(GetDiscoveryUrlWithTrailingSlash(), relativeUrl); + } + + Uri GetDiscoveryUrlWithTrailingSlash() + { + if (discoveryUrl.AbsoluteUri.EndsWith("/")) { + return discoveryUrl; + } + return new Uri(discoveryUrl.AbsoluteUri + "/"); + } + + void DiscoverMexMetadata(BackgroundWorker worker, Uri url) + { + worker.DoWork += DiscoverMexMetadata; + worker.RunWorkerCompleted += DiscoveryCompleted; + worker.RunWorkerAsync(url); + } + + void DiscoverMexMetadata(object sender, DoWorkEventArgs e) + { + Uri url = (Uri)e.Argument; + var client = new MetadataExchangeClient(url, MetadataExchangeClientMode.MetadataExchange); + MetadataSet metadata = client.GetMetadata(); + e.Result = new ServiceReferenceDiscoveryEventArgs(metadata); + } + + void DiscoveryCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (e.Error != null) { + OnDiscoveryError(e.Error); + } else { + OnDiscoveryComplete((ServiceReferenceDiscoveryEventArgs)e.Result); + } + } + + void OnDiscoveryError(Exception ex) + { + errors.Add(ex); + if (errors.Count == DiscoveryClientsUsed) { + OnDiscoveryComplete(new ServiceReferenceDiscoveryEventArgs(errors)); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryEventArgs.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryEventArgs.cs new file mode 100644 index 0000000000..07bfde247f --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceDiscoveryEventArgs.cs @@ -0,0 +1,57 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.ServiceModel.Description; +using System.Text; +using System.Web.Services.Description; +using WebServices = System.Web.Services.Description; + +namespace ICSharpCode.SharpDevelop.Gui +{ + public class ServiceReferenceDiscoveryEventArgs : EventArgs + { + ServiceDescriptionCollection services = new ServiceDescriptionCollection(); + + public ServiceReferenceDiscoveryEventArgs(IEnumerable errors) + { + GenerateAggregateError(errors); + } + + void GenerateAggregateError(IEnumerable errors) + { + var message = new StringBuilder(); + foreach (Exception ex in errors) { + message.AppendLine(ex.Message); + message.AppendLine(); + } + Error = new AggregateException(message.ToString(), errors); + } + + public ServiceReferenceDiscoveryEventArgs(MetadataSet metadata) + { + GetServices(metadata); + } + + void GetServices(MetadataSet metadata) + { + foreach (MetadataSection section in metadata.MetadataSections) { + var service = section.Metadata as WebServices.ServiceDescription; + if (service != null) { + Services.Add(service); + } + } + } + + public ServiceDescriptionCollection Services { + get { return services; } + } + + public Exception Error { get; private set; } + + public bool HasError { + get { return Error != null; } + } + } +}