0

I have a standalone C# WCF service running as a Windows service. I have the requirement to add custom headers like X-Frame-Options to all responses. I have tried to add an instance of the following class to ServiceEndpoint.Behaviors

internal class ServerInterceptor : IDispatchMessageInspector, IEndpointBehavior
{
    object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        return null;
    }

    void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
    {
        reply.Properties.Add("X-Frame-Options", "deny");
    }

    void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
    }

    void IEndpointBehavior.Validate(ServiceEndpoint endpoint) { }

    void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }

    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
}

This doesn't add any HTTP header to the response although the class gets called as the debugger can step into the BeforeSendReply function. Furthermore if I replace reply.Properties with reply.Headers then the header is added, but not to the HTTP headers but to the SOAP headers.

How can I add a HTTP header like X-Frame-Options to the response?

2
  • Dİd you try HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty(); requestMessage.Headers["X-Frame-Options"] = "deny"; OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;? Commented Mar 11, 2020 at 5:24
  • I also found this code snippet and it doesn't work (cannot work, to be exact), as there's no "X-Frame-Options" header. Commented Mar 11, 2020 at 8:18

1 Answer 1

1

I made an example, which is used to add extra CORS HTTP header, wish it is instrumental for you.
Message Inspector.

        public class CustomHeaderMessageInspector : IDispatchMessageInspector
        {
            Dictionary<string, string> requiredHeaders;
            public CustomHeaderMessageInspector(Dictionary<string, string> headers)
            {
                requiredHeaders = headers ?? new Dictionary<string, string>();
            }
            public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                string displayText = $"Server has received the following message:\n{request}\n";
                Console.WriteLine(displayText);
                return null;
            }

            public void BeforeSendReply(ref Message reply, object correlationState)
            {
                if (!reply.Properties.ContainsKey("httpResponse")) 
                reply.Properties.Add("httpResponse", new HttpResponseMessageProperty());

                var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
                foreach (var item in requiredHeaders)
                {
                    httpHeader.Headers.Add(item.Key, item.Value);
                }

                string displayText = $"Server has replied the following message:\n{reply}\n";
                Console.WriteLine(displayText);

            }
    }

Custom Contract Attribute.

public class MyBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
    {
        public Type TargetContract => typeof(MyBehaviorAttribute);

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            var requiredHeaders = new Dictionary<string, string>();

            requiredHeaders.Add("Access-Control-Allow-Origin", "*");
            requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
            requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");

            dispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {

        }
}

Apply the contract behavior.

[ServiceContract(Namespace = "mydomain")]
[MyBehavior]
public interface IService
{
    [OperationContract]
    [WebGet]
    string SayHello();
}

Result.
enter image description here

Feel free to let me know if there is anything I can help with.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks but the line var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty; throws this exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: A property with the name 'httpResponse' is not present.
If you modify your code and add if (!reply.Properties.ContainsKey("httpResponse")) reply.Properties.Add("httpResponse", new HttpResponseMessageProperty()); to the beginning of BeforeSendReply() then I'll accept your answer.
My bad. I forget the binding type used in WCF, if the WCF isn’t created by Webhttpbinding, we should add your code segment. It will work perfectly. I have updated it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.