Esporta (0) Stampa
Espandi tutto

ListenUriEndpointBehavior

Aggiornamento: marzo 2014

Il passaggio successivo consiste nel creare ListenUriEndpointBehavior. In questo argomento è riportato il codice necessario per creare tale comportamento.

In questo white paper viene mostrato come definire un percorso di ricezione WCF-Custom per leggere i messaggi di una sottoscrizione o di una coda di Service Bus. Quando si definisce un endpoint servizio WCF per l'utilizzo dei messaggi di una sottoscrizione, si specifica l'URL dell'argomento come indirizzo dell'endpoint servizio e l'URL della sottoscrizione come relativo listenUri. Durante la configurazione di un percorso di ricezione WCF con l'adapter WCF-Custom, nella scheda Generale è disponibile una casella di testo in cui specificare l'indirizzo dell'endpoint servizio. Non sono invece presenti campi per specificare le proprietà listenUri e ListenUriMode. Viene pertanto creato un comportamento endpoint personalizzato in modo che, in fase di runtime, sia possibile impostare tali valori per un percorso di ricezione WCF-Custom. Nel primo tentativo i metodi AddBindingParameters e ApplyDispatchBehavior esposti dal comportamento endpoint personalizzato vengono utilizzati per impostare le proprietà listenUri e ListenUriMode dell'endpoint servizio passato come parametro a entrambi i metodi. Questa tecnica tuttavia non ha funzionato come previsto.

Viene quindi creata una classe elemento estensione binding denominata ListenUriBehaviorExtensionElement per registrare il comportamento endpoint personalizzato nel file machine.config. Questo componente espone una proprietà denominata listenUri che consente a un utente di specificare l'URL di una sottoscrizione durante la configurazione di un percorso di ricezione WCF-Custom. In fase di runtime il componente ListenUriBehaviorExtensionElement crea un'istanza della classe ListenUriEndpointBehavior. Il metodo AddBindingParameters del comportamento endpoint personalizzato sostituisce il binding originale con una classe CustomBinding contenente gli stessi elementi di binding e inserisce un'istanza di ListenUriBindingElement all'inizio del binding. In questo modo, in fase di runtime, il binding personalizzato viene eseguito per primo. Il metodo BuildChannelListener di ListenUriBindingElement infine assegna l'URL specificato nella configurazione del percorso di ricezione alla proprietà ListenUriBaseAddress di BindingContext e imposta il valore della relativa proprietà ListenUriMode su Explicit. Per praticità, di seguito è riportato il codice per queste tre classi. Più avanti nella soluzione verrà mostrato come utilizzare questo componente per la definizione di un percorso di ricezione WCF-Custom che riceve messaggi da una sottoscrizione di Service Bus.

public class ListenUriBehaviorExtensionElement : IEndpointBehavior
{
#region Private Constants
    //***************************
    // Constants
    //***************************

    private const string ListenUriName = "listenUri";
    private const string IsTrackingEnabledName = "isTrackingEnabled";
    private const string ListenUriDescription = "Gets or sets the URI at which the service endpoint listens.";
    private const string IsTrackingEnabledDescription = "Gets or sets a value indicating whether tracking is enabled.";
    #endregion

    #region BehaviorExtensionElement Members
    //***************************
    // Protected Methods
    //***************************

    /// <summary>
    /// Creates a behavior extension based on the current configuration settings.
    /// </summary>
    /// <returns>The behavior extension.</returns>
    protected override object CreateBehavior()
    {
        return new ListenUriEndpointBehavior(ListenUri, IsTrackingEnabled);
    }

    /// <summary>
    /// Gets the type of behavior.
    /// </summary>
    public override Type BehaviorType
    {
        get
        {
            return typeof(ListenUriEndpointBehavior);
        }
    }      
    #endregion

    #region Public Properties
    /// <summary>
    /// Gets or sets the URI at which the service endpoint listens.
    /// </summary>
    [ConfigurationProperty(ListenUriName, IsRequired = true)]
    [SettingsDescription(ListenUriDescription)]
    public string ListenUri
    {
        get
        {
            return (string)base[ListenUriName];
        }
        set
        {
            base[ListenUriName] = value;
        }
    }

    /// <summary>
    /// Gets or sets a value indicating whether the message inspector is enabled.
    /// </summary>
    [ConfigurationProperty(IsTrackingEnabledName, DefaultValue = true, IsRequired = false)]
    [SettingsDescription(IsTrackingEnabledDescription)]
    public bool IsTrackingEnabled
    {
        get
        {
            return (bool)base[IsTrackingEnabledName];
        }
        set
        {
            base[IsTrackingEnabledName] = value;
        }
    }
    #endregion
}

public class ListenUriEndpointBehavior : IEndpointBehavior
{
    #region Private Constants
    //***************************
    // Constants
    //***************************

    private const string ListerUriMessageFormat = "[ListenUriEndpointBehavior] ListenUri = [{0}].";
    #endregion

    #region Public Constructors
    private readonly string listenUri;
    private readonly bool isTrackingEnabled;
    #endregion

    #region Public Constructors
    /// <summary>
    /// Initializes a new instance of the ListenUriEndpointBehavior class.
    /// </summary>
    /// <param name="listenUri">The URI at which the service endpoint listens</param>
    /// <param name="isTrackingEnabled">A boolean value indicating whether tracking is enabled</param>
    public ListenUriEndpointBehavior(string listenUri, bool isTrackingEnabled)
    {
        this.listenUri = listenUri;
        this.isTrackingEnabled = isTrackingEnabled;
    }
    #endregion

    #region IEndpointBehavior Members
    /// <summary>
    /// Implement to pass data at runtime to bindings to support custom behavior.
    /// </summary>
    /// <param name="endpoint">The endpoint to modify.</param>
    /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
    void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        if (endpoint != null &&
            !String.IsNullOrEmpty(listenUri))
        {
            // Read the binding elements from the original binding
            var bindingElementCollection = endpoint.Binding.CreateBindingElements();
            // Create an array of binding elements
            var bindingElementArray = new BindingElement[bindingElementCollection.Count + 1];
            // Add an instance of the ListenUriBindingElement as first binding element of the array
            bindingElementArray[0] = new ListenUriBindingElement(listenUri);
            // Copy the binding elements of the original binding to the array
            bindingElementCollection.CopyTo(bindingElementArray, 1);
            // Create a custom binding with the same binding elements as the original
            // binding with the addition of the custom binding as first item
            var customBinding = new CustomBinding(bindingElementArray)
                                    {
                                        CloseTimeout = endpoint.Binding.CloseTimeout,
                                        OpenTimeout = endpoint.Binding.OpenTimeout,
                                        ReceiveTimeout = endpoint.Binding.ReceiveTimeout,
                                        SendTimeout = endpoint.Binding.SendTimeout,
                                        Name = endpoint.Binding.Name,
                                        Namespace = endpoint.Binding.Namespace
                                    };
            //Replace the original binding with the newly created binding
            endpoint.Binding = customBinding;
            Trace.WriteLineIf(isTrackingEnabled,
                                string.Format(ListerUriMessageFormat,
                                              listenUri));
        }
    }

    /// <summary>
    /// Implements a modification or extension of the client across an endpoint.
    /// </summary>
    /// <param name="endpoint">The endpoint that is to be customized.</param>
    /// <param name="clientRuntime">The client runtime to be customized.</param>
    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    /// <summary>
    /// Implements a modification or extension of the service across an endpoint.
    /// </summary>
    /// <param name="endpoint">The endpoint that exposes the contract.</param>
    /// <param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param>
    void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    /// <summary>
    /// Implement to confirm that the endpoint meets some intended criteria.
    /// </summary>
    /// <param name="endpoint">The endpoint to validate.</param>
    void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
    {
    }
    #endregion
}

public class ListenUriBindingElement : BindingElement
{
    #region Private Fields
    private readonly string listenUri;
    #endregion

    #region Public Constructor
    /// <summary>
    /// Initializes a new instance of the ListenUriBindingElement class.
    /// </summary>
    /// <param name="listenUri">A BindingElement object that is a deep clone of the original.</param>
    public ListenUriBindingElement(string listenUri)
    {
        this.listenUri = listenUri;
    }
    #endregion

    #region BindingElement Members
    /// <summary>
    /// returns a copy of the binding element object.
    /// </summary>
    /// <returns></returns>
    public override BindingElement Clone()
    {
        return new ListenUriBindingElement(listenUri);
    }

    /// <summary>
    /// Returns a typed object requested, if present, from the appropriate layer in the binding stack.
    /// </summary>
    /// <typeparam name="T">The typed object for which the method is querying.</typeparam>
    /// <param name="context">The BindingContext for the binding element.</param>
    /// <returns>The typed object T requested if it is present or nullif it is not present.</returns>
    public override T GetProperty<T>(BindingContext context)
    {
        return context.GetInnerProperty<T>();
    }

    /// <summary>
    /// Returns a value that indicates whether the binding element can build a 
    /// channel factory for a specific type of channel.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel the channel factory produces.</typeparam>
    /// <param name="context">The BindingContext that provides context for the binding element.</param>
    /// <returns>true if the IChannelFactory<TChannel/>of type TChannel can be built by 
    ///          the binding element; otherwise, false.</returns>
    public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
    {
        return false;
    }

    /// <summary>
    /// Initializes a channel factory for producing channels of a specified type from the binding context.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel the factory builds.</typeparam>
    /// <param name="context">The BindingContext that provides context for the binding element.</param>
    /// <returns>The IChannelFactory<TChannel/>of type TChannel initialized from the context. </returns>
    public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
    {
        throw new NotSupportedException();
    }

    /// <summary>
    /// Returns a value that indicates whether the binding element can build a channel 
    /// listener for a specific type of channel.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel listener to build.</typeparam>
    /// <param name="context">The BindingContext for the binding element.</param>
    /// <returns>true if a channel listener of the specified type can be built; 
    ///          otherwise, false. The default is false. </returns>
    public override bool CanBuildChannelListener<TChannel>(BindingContext context)
    {
        return context.CanBuildInnerChannelListener<TChannel>();
    }

    /// <summary>
    /// Initializes a channel listener for producing channels of a specified type from the binding context.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel that the listener is built to accept.</typeparam>
    /// <param name="context">The BindingContext for the binding element.</param>
    /// <returns>The IChannelListener<TChannel/>of type IChannel initialized from the context.</returns>
    public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
    {
        if (!string.IsNullOrEmpty(listenUri))
        {
            context.ListenUriBaseAddress = new Uri(listenUri);
            context.ListenUriMode = ListenUriMode.Explicit;
        }
        return context.BuildInnerChannelListener<TChannel>();
    } 
    #endregion
}

È possibile abilitare il rilevamento del componente e utilizzare DebugView per monitorarne il comportamento in fase di runtime.

Vedere anche

Mostra:
© 2015 Microsoft