내보내기(0) 인쇄
모두 확장

ListenUriEndpointBehavior

업데이트 날짜: 2014년 3월

다음 단계는 ListenUriEndpointBehavior를 만드는 것입니다. 이 항목에서는 ListenUriEndpointBehavior를 만드는 코드를 설명합니다.

이 백서에서는 Service Bus 큐 또는 구독에서 메시지를 읽기 위한 WCF 사용자 지정 수신 위치를 정의하는 방법을 보여줍니다. 구독의 메시지를 사용하기 위한 WCF 서비스 끝점을 정의할 때는 항목 URL을 서비스 끝점 주소로, 구독 URL을 해당 listenUri로 지정합니다. WCF 사용자 지정 어댑터를 사용하여 WCF 수신 위치를 구성할 때 일반 탭에 서비스 끝점 주소를 지정하기 위한 텍스트 상자가 있습니다. 그러나 listenUriListenUriMode 속성을 지정하는 필드는 없습니다. 이러한 이유로 사용자 지정 끝점 동작이 만들어지므로 런타임에 WCF 사용자 지정 수신 위치에 대한 이러한 값을 설정할 수 있습니다. 첫 번째 시도에서, 사용자 지정 끝점 동작에 의해 노출되는 AddBindingParametersApplyDispatchBehavior 메서드가 두 메서드에 매개 변수로 전달되는 서비스 끝점의 listenUriListenUriMode를 설정하는 데 사용됩니다. 그러나 이 기술은 예상대로 작동하지 않았습니다.

다음으로, machine.config 파일에 사용자 지정 끝점 동작을 등록하기 위한 ListenUriBehaviorExtensionElement라는 바인딩 확장 요소 클래스가 만들어집니다. 이 구성 요소는 WCF 사용자 지정 수신 위치를 구성할 때 사용자가 구독 URL을 지정할 수 있게 해주는 listenUri라는 속성을 노출합니다. 런타임에 ListenUriBehaviorExtensionElement 구성 요소는 ListenUriEndpointBehavior 클래스의 인스턴스를 만듭니다. 사용자 지정 끝점 동작의 AddBindingParameters 메서드는 원래 바인딩을 동일한 바인딩 요소를 포함하고 바인딩의 맨 위에 ListenUriBindingElement의 인스턴스를 삽입하는 CustomBinding으로 바꿉니다. 이 방법은 런타임에 사용자 지정 바인딩을 먼저 실행합니다. 마지막으로, ListenUriBindingElementBuildChannelListener 메서드는 수신 위치 구성에 지정된 URL을 BindingContextListenUriBaseAddress 속성에 할당하고 해당 ListenUriMode 속성 값을 Explicit로 설정합니다. 사용자 편의를 위해 이러한 세 클래스의 코드를 아래에 포함시켰습니다. 솔루션 후반부에서 Service Bus 구독에서 메시지를 받는 WCF 사용자 지정 수신 위치를 정의할 때 이 구성 요소를 사용하는 방법을 보여줍니다.

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
}

구성 요소 추적을 사용하도록 설정하고 DebugView를 사용하여 런타임 동작을 모니터링할 수 있습니다.

참고 항목

표시:
© 2014 Microsoft