wcfwcf-security

WCF One method to execute before every service method's call


I am looking for a way to execute specific method, at the server side, on every request method's call.

This is for security validations but not only.

This is NOT duplicated with this question since we mean to completely different things and. I addition, all the relevant answers there have unavailable links so it's impossible to get to the right answer.

(Sorry I haven't attached any code here, there is no code to specify in this issue).


Solution

  • The best solution is to create WCF custom behavior.

    Here is how you do this by several simple steps:

    Client Side:

    public class FillHeaderDataBehaviourExtension : BehaviorExtensionElement, IEndpointBehavior
    {
        #region BehaviorExtensionElement Implementation
        public override Type BehaviorType
        {
            get
            {
                return typeof(FillHeaderDataBehaviourExtension);
            }
        }
        protected override object CreateBehavior()
        {
            return this;
        }
        #endregion
    
        #region IServiceBehaviour Implementation
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
    
        }
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
    
        public void Validate(ServiceEndpoint endpoint)
        {
        }
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.ClientMessageInspectors.Add(new MessageInspector());
        }
        #endregion
    }
    
    public class MessageInspector : IClientMessageInspector
    {
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            MessageHeader header = MessageHeader.CreateHeader("HeaderData", String.Empty, HeaderDataVM.GetInstance().GetBaseInstance());
            request.Headers.Add(header); // There is no need for checking if exist before adding. Every request has it's own headers.
    
            return null;
        }
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }
    }
    

    Server Side:

    public class ExtractHeadersBehaviourExtension : BehaviorExtensionElement, IServiceBehavior
    {
        #region BehaviorExtensionElement Implementation
        public override Type BehaviorType
        {
            get
            {
                return typeof(ExtractHeadersBehaviourExtension);
            }
        }
        protected override object CreateBehavior()
        {
            return this;
        }
        #endregion
    
        #region IServiceBehavior Implementation
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
            {
                ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
                if (channelDispatcher != null)
                {
                    foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
                    {
                        MessageInspector inspector = new MessageInspector();
                        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
                    }
                }
            }
        }
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
        #endregion
    }
    
    public class MessageInspector : IDispatchMessageInspector
    {
        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            HeaderData headerData = request.Headers.GetHeader<HeaderData>("HeaderData", String.Empty);
    
            if(headerData != null)
            {
                OperationContext.Current.IncomingMessageProperties.Add("HeaderData", headerData);
            }
    
            return null;
        }
    }
    

    And finally, don't forget to configure it in the app.config files (client & server side) as follows:

    <behaviors>
      <endpointBehaviors>
        <behavior name="NewBehavior">
          <fillHeaderDataBehaviourExtension/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
    

    You can also add these lines via the WCF config editor. To do so, look at this answer.

    EDIT: You might get an error in the app config after adding these lines of configuration code:

    enter image description here

    Don't worry about this, your application will run fine. It causes because the GAC (Global Assembly Cache) folder doesn't contain this behavior (since it is a custom behavior). You can fix it by adding this behavior manually to your GAC folder on your computer. However, this error might prevent you from updating service reference. If you try to, you'll get this error message:

    enter image description here

    So just comment out this line (<extractHeadersBehaviourExtension/>) (in client & server side) when you update your service reference.

    Sources: How to add behavior on a specific endpoint? & Adding Custom Message Headers to a WCF Service