You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不修改现有调用的情况下为WCF服务调用传递HTTP头

问题背景

我们有一个调用WCF服务的ASP.NET Web应用,现有代码结构如下:

AjaxWebService.svc.cs

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
[ServiceContract(Namespace = "", SessionMode = SessionMode.Allowed)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

private Service m_Service;
private Service Service
{
    get
    {
        if (m_Service == null)
        {
            m_Service = new Service();
        }
        return m_Service;
    }
}

[OperationContract]
internal Users[] getUsers()
{
    return this.Service.getUsers();
}
[OperationContract]
internal products[] getproducts()
{
    return this.Service.getproducts();
}

Service.cs

private IServiceClient m_ServiceGateway;
private IServiceClient ServiceGateway
{
    get
    {
        if (m_ServiceGateway == null)
        {
            m_ServiceGateway = new IServiceClient();
        }
        return m_ServiceGateway;
    }
}

internal Users[] getUsers()
{
    return this.ServiceGateway.getUsers(this.RoleId, this.Token);
}

internal products[] getproducts()
{
    return this.ServiceGateway.getproducts(this.RoleId, this.Token);
}

IServiceGateway.cs

[OperationContract]
List<getUsers> getUsers(int RoleId, string Token);
[OperationContract]
List<products> getProducts(int RoleId, string Token);

需求与问题

我们希望不修改现有方法签名(比如return this.ServiceGateway.getUsers(this.RoleId, this.Token);)的前提下,给所有WCF服务调用传递自定义HTTP头(如User-Agent和Accept)。

之前尝试在ServiceGateway属性初始化时设置头,但未成功,代码如下:

private IServiceClient m_ServiceGateway;
private IServiceClient ServiceGateway
{
    get
    {
        if (m_ServiceGateway == null)
        {
            m_ServiceGateway = new IServiceClient();
            using (new OperationContextScope(m_ServiceGateway.InnerChannel))
            {
                // Set HTTP headers
                HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
                httpRequestProperty.Headers["User-Agent"] = "mrt/1.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
                httpRequestProperty.Headers["Accept"] = "application/json";

                OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
            }
        }
        return m_ServiceGateway;
    }
}

想知道:

  1. 是否存在无需修改现有方法调用就能传递头信息的方式?
  2. 如何集中为所有WCF服务调用应用自定义头,不用逐个修改API?

解决方案

问题根源

之前的代码失败是因为OperationContextScope用了using块,作用域结束后上下文会被销毁,后续调用服务时这个上下文已经不存在,所以头信息没被传递。

最优方案:WCF客户端消息拦截器

这是最适合集中处理的方案,不用修改任何现有服务调用代码,所有请求都会自动带上自定义头。

1. 实现客户端消息拦截器

public class CustomHeaderMessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty httpRequestProperty;
        // 检查是否已有请求属性,没有则新建
        if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
        {
            httpRequestProperty = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
        }
        else
        {
            httpRequestProperty = new HttpRequestMessageProperty();
            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestProperty);
        }

        // 添加自定义HTTP头
        httpRequestProperty.Headers["User-Agent"] = "mrt/1.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
        httpRequestProperty.Headers["Accept"] = "application/json";

        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // 不需要处理响应的话留空即可
    }
}

2. 实现行为扩展类

public class CustomHeaderBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        // 将拦截器添加到客户端运行时
        clientRuntime.ClientMessageInspectors.Add(new CustomHeaderMessageInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

3. 给WCF客户端配置行为

有两种配置方式:

方式A:代码配置(修改Service.cs中的ServiceGateway属性)
private IServiceClient m_ServiceGateway;
private IServiceClient ServiceGateway
{
    get
    {
        if (m_ServiceGateway == null)
        {
            m_ServiceGateway = new IServiceClient();
            // 添加自定义行为
            m_ServiceGateway.Endpoint.Behaviors.Add(new CustomHeaderBehavior());
        }
        return m_ServiceGateway;
    }
}
方式B:配置文件(web.config/app.config)

如果偏好配置文件管理,可添加如下配置:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="customHeaderBehavior" type="你的命名空间.CustomHeaderBehavior, 你的程序集名称"/>
        </behaviorExtensions>
    </extensions>
    <behaviors>
        <endpointBehaviors>
            <behavior name="CustomHeaderBehavior">
                <customHeaderBehavior />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <client>
        <endpoint address="你的WCF服务地址" 
                  binding="basicHttpBinding" 
                  contract="IServiceGateway"
                  behaviorConfiguration="CustomHeaderBehavior"/>
    </client>
</system.serviceModel>

备选方案:封装通用服务调用方法

如果不想用拦截器,也可以封装通用方法统一处理头信息,改动极小:

public class ServiceWrapper
{
    private static void SetCustomHeaders(IClientChannel channel)
    {
        using (new OperationContextScope(channel))
        {
            HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
            httpRequestProperty.Headers["User-Agent"] = "mrt/1.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
            httpRequestProperty.Headers["Accept"] = "application/json";
            OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
        }
    }

    public static TResult Execute<TClient, TResult>(Func<TClient, TResult> operation) where TClient : IClientChannel, new()
    {
        var client = new TClient();
        try
        {
            SetCustomHeaders(client);
            return operation(client);
        }
        finally
        {
            // 正确释放客户端资源
            if (client.State == CommunicationState.Faulted)
                client.Abort();
            else
                client.Close();
        }
    }
}

修改Service.cs中的调用代码:

internal Users[] getUsers()
{
    return ServiceWrapper.Execute<IServiceClient, Users[]>(client => client.getUsers(this.RoleId, this.Token));
}

internal products[] getproducts()
{
    return ServiceWrapper.Execute<IServiceClient, products[]>(client => client.getproducts(this.RoleId, this.Token));
}

内容的提问来源于stack exchange,提问作者Shashimk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 15:55:02