3

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).

Jacob
  • 3,598
  • 4
  • 35
  • 56
  • 2
    possible duplicate of [Force WCF to call a method on every request before entering actual function](http://stackoverflow.com/questions/1798574/force-wcf-to-call-a-method-on-every-request-before-entering-actual-function) – Matthieu Sep 04 '15 at 22:30
  • This might be duplicate but there are no answers there that help me and almost every link, there, unavalible. – Jacob Sep 04 '15 at 22:41
  • Could you explain why the link @Matthieu mentioned doesn't help you, so we can provide other ideas? That is a easy way to intercept the requests and where you can execute any code you need. – Ricardo Pontual Sep 05 '15 at 01:43
  • See also: https://stackoverflow.com/questions/39773448/wcf-add-header-issue-with-addressheader-createaddressheader-method/41131918#41131918 – Ian Kemp Jun 03 '17 at 11:33

1 Answers1

4

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

Jacob
  • 3,598
  • 4
  • 35
  • 56
  • Keep in mind, that `request.Headers.GetHeader` will throw exception, when `"HeaderData"` header is not found. – Gh61 Jan 04 '23 at 12:12