Click here to Skip to main content
15,892,965 members
Articles / Programming Languages / C#

WS-Discovery for WCF

Rate me:
Please Sign up or sign in to vote.
4.95/5 (31 votes)
27 Nov 2008CPOL12 min read 139.8K   3.3K   86  
This article describes the design, implementation, and usage of WS-Discovery for Windows Communication Foundation (WCF).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel.Description;
using Masieri.ServiceModel.WSDiscovery.Helpers;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Masieri.ServiceModel.WSDiscovery.Messages;

//*****************************************************************************
//    Description.....WS-Discovey for WCF
//                                
//    Author..........Claudio Masieri, claudio@claudiomasieri.it
//    Copyright © 2008 ing.Masieri Claudio. (see included license.rtf file)    
//                        
//    Date Created:    06/06/06
//
//    Date        Modified By     Description
//-----------------------------------------------------------------------------
//    01/10/08    Claudio Masieri     First Release
//*****************************************************************************
namespace Masieri.ServiceModel.WSDiscovery.Client
{
  /// <summary>
  /// Memento of a service
  /// </summary>
  public class ClientMemento
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="ClientMemento"/> class.
    /// </summary>
    public ClientMemento()
    {
      ScopeMatchBy = Constants.ScopesMatchBy;
      Scopes = new List<string>();
      _mexWaiting = new System.Threading.ManualResetEvent(false);
    }


    //endpoint recuperato con il mex e mantenuto per evitare duplicazioni di richiesta
    private ServiceEndpoint _endpoint = null;
    System.Threading.ManualResetEvent _mexWaiting;

    /// <summary>
    /// Gets or sets the name of the endpoint.
    /// </summary>
    /// <value>The name of the endpoint.</value>
    public string EndpointName { get; set; }
    /// <summary>
    /// Gets or sets the address.
    /// </summary>
    /// <value>The address.</value>
    public string Address { get; set; }
    /// <summary>
    /// Gets or sets the type.
    /// </summary>
    /// <value>The type.</value>
    public string Type { get; set; }
    /// <summary>
    /// Gets or sets the scope match by.
    /// </summary>
    /// <value>The scope match by.</value>
    public string ScopeMatchBy { get; set; }
    /// <summary>
    /// Gets or sets the scopes.
    /// </summary>
    /// <value>The scopes.</value>
    public List<string> Scopes { get; set; }
    string _XAddrs;
    /// <summary>
    /// Gets or sets the Metadata Address
    /// </summary>
    /// <value>The Metadata Address</value>
    public string XAddrs
    {
      get { return _XAddrs; }
      set
      {
        _XAddrs = value;
        if (_endpoint == null)
        { GetMetadata(); }
      }

    }
    /// <summary>
    /// Gets or sets the endpoint.
    /// </summary>
    /// <value>The endpoint.</value>
    public ServiceEndpoint Endpoint
    {
      get
      {
        if (_endpoint == null)
        {
          _mexWaiting.WaitOne(5000, true);
          return _endpoint;
        }
        else
          return _endpoint;
      }
      set
      {
        if (value != null)
          _mexWaiting.Set();
        _endpoint = value;
      }
    }
    /// <summary>
    /// Gets or sets the metadata version.
    /// </summary>
    /// <value>The metadata version.</value>
    public long MetadataVersion { get; set; }
    
    /// <summary>
    /// Get a string with a unique Hashcode for the memento
    /// </summary>
    /// <returns>string unique identifier for memento</returns>
    public  string GetUniqueIdentifier()
    {
      //I sort the scopes befor join it
      Scopes.Sort();
      return string.Format("{0}|{1}|{2}|{3}", this.Address, this.Type, ScopeMatchBy, string.Join(",", Scopes.ToArray())).ToLower();
    }
    private void GetMetadata()
    {
      Thread threadMex = new Thread(new ThreadStart(delegate()
      {
        MetadataExchangeClient resolver;
        //return if there isn't Metadata Address
        if (string.IsNullOrEmpty(_XAddrs))
          return;
        resolver = new MetadataExchangeClient(new Uri(_XAddrs), MetadataExchangeClientMode.HttpGet);
        MetadataSet metadata;
        try
        {
          DiscoveryLogger.Debug("GetMetadata from address: " + _XAddrs);
          metadata = resolver.GetMetadata();
          DiscoveryLogger.Info(String.Format("GetMetadata from {0} works correctly", _XAddrs));
        }
        catch (Exception ex)
        {
          DiscoveryLogger.Error(String.Format("Can't connect to metadata endpoint {0}", _XAddrs), ex);
          throw new Exception(String.Format("Can't connect to metadata endpoint {0}", _XAddrs));
        }
        WsdlImporter importer = new WsdlImporter(metadata);
        ServiceEndpointCollection serviceCollection = importer.ImportAllEndpoints();
        if (importer.Errors.Count > 0)
        {
          foreach (MetadataConversionError err in importer.Errors)
          {
            DiscoveryLogger.Warn("Exception during metatada import: " + err.Message);
          }
        }
        string contractName = Type.Substring(Type.LastIndexOf("/") + 1, Type.Length - Type.LastIndexOf("/") - 1);
        string contractNamespace = Type.Substring(0, Type.LastIndexOf("/") + 1);
        foreach (ServiceEndpoint se in serviceCollection)
        {

          if (se.Contract.Name == contractName && se.Contract.Namespace == contractNamespace)
          {
            Endpoint = se;
            break;
          }
        }
      }));
      threadMex.IsBackground = true;
      threadMex.Start();
    }
    /// <summary>
    /// Determines whether the specified scope contains scope.
    /// </summary>
    /// <param name="scope">The scope.</param>
    /// <param name="scopeMatchBy">The scope match by.</param>
    /// <returns>
    /// 	<c>true</c> if the specified scope contains scope; otherwise, <c>false</c>.
    /// </returns>
    public bool ContainsScope(string scope, string scopeMatchBy)
    {
      if (this.ScopeMatchBy != scopeMatchBy)
        return false;
      foreach (string s in Scopes)
      {
        if (new Uri(scope).IsSameUri(new Uri(s)))
          return true;
      }
      return false;
    }
    /// <summary>
    /// Sets the endpoint from endpoint reference value.
    /// </summary>
    /// <param name="epr">The epr.</param>
    /// <param name="contractType">Type of the contract.</param>
    /// <returns>true if operation successful</returns>
    internal bool SetEndpointFromEndpointReferenceValue(EndpointReference epr, Type contractType)
    {
      if (epr.ReferenceParameters != null && epr.ReferenceParameters is CustomBinding)
      {
        //devo costruire l'endpoint
        Binding binding = epr.ReferenceParameters as CustomBinding;
        EndpointAddress address = new EndpointAddress(epr.Address);
        this._endpoint = new ServiceEndpoint(ContractDescription.GetContract(contractType), binding, address);
        return true;
      }
      else
        return false;
    }
    /// <summary>
    /// Get the ClientMemento form the ProbeMatch.
    /// </summary>
    /// <typeparam name="TChannel">The type of the channel.</typeparam>
    /// <param name="pm">The pm.</param>
    /// <returns></returns>
    internal static ClientMemento FromProbeMatch<TChannel>(Masieri.ServiceModel.WSDiscovery.Messages.ProbeMatches.ProbeMatch pm)
    {
      ClientMemento mem = new ClientMemento();
      mem.Type = pm.Types;
      mem.Scopes.AddRange(pm.Scopes.Split(new string[] { Constants.ScopesSeparator }, StringSplitOptions.RemoveEmptyEntries));
      mem.ScopeMatchBy = (string.IsNullOrEmpty(pm.ScopeMatchBy)) ? Constants.ScopesMatchBy : pm.ScopeMatchBy;
      mem.Address = pm.EndpointReferenceValue.Address;
      mem.MetadataVersion = Convert.ToInt64(pm.MetadataVersion);
      mem.SetEndpointFromEndpointReferenceValue(pm.EndpointReferenceValue, typeof(TChannel));
      mem.XAddrs = pm.XAddrs;
      return mem;
    }
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions