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

如何通过编程实现WCF的web.config重写规则替代方案

用C#代码实现WCF的URL重写逻辑替代web.config规则

我原本在web.config中配置了两条URL重写规则来处理WCF服务的请求:

<system.webServer>
    <rewrite>
      <rules>
        <!-- Rewrite requests to /MyService to /MyService.svc -->
        <rule name="MyService" stopProcessing="false">
          <match url="MyService/(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
          </conditions>
          <action type="Rewrite" url="/MyService.svc/{R:1}" />
        </rule>
        <!-- Remove path /MoreServices from url -->
        <rule name="example" stopProcessing="true">
          <match url=".*(MoreServices)(.+)" ignoreCase="true" />
          <action type="Rewrite" url="{R:2}" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

规则说明

  • 第一条规则:将不带.svc后缀的请求(如/MyService/xxx)重写为对应的服务地址/MyService.svc/xxx,同时排除实际存在的文件或目录请求。
  • 第二条规则:移除URL中的/MoreServices路径段(如/abc/MoreServices/def会被重写为/def),且匹配后停止后续规则处理。

现在部署的站点不允许在web.config中使用<rule>标签,以下是两种C#代码实现方案:


方案一:自定义HttpModule(IIS托管场景)

通过ASP.NET管道拦截请求,手动处理URL重写,适配IIS托管的WCF服务:

  1. 创建自定义HttpModule类:
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;

namespace YourNamespace
{
    public class WcfUrlRewriteModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += OnBeginRequest;
        }

        private void OnBeginRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            var request = app.Context.Request;
            var originalUrl = request.Url.AbsolutePath;

            // 优先处理第二条规则:移除/MoreServices路径,匹配后停止后续处理
            var moreServicesRegex = new Regex(@".*(MoreServices)(.+)", RegexOptions.IgnoreCase);
            var moreServicesMatch = moreServicesRegex.Match(originalUrl);
            if (moreServicesMatch.Success)
            {
                var newUrl = moreServicesMatch.Groups[2].Value;
                app.Context.RewritePath(newUrl);
                return;
            }

            // 处理第一条规则:重写MyService请求到MyService.svc
            var myServiceRegex = new Regex(@"^/MyService/(.*)$", RegexOptions.IgnoreCase);
            var myServiceMatch = myServiceRegex.Match(originalUrl);
            if (myServiceMatch.Success)
            {
                var filePath = app.Context.Server.MapPath(originalUrl);
                // 排除实际存在的文件或目录
                if (!File.Exists(filePath) && !Directory.Exists(filePath))
                {
                    var newUrl = $"/MyService.svc/{myServiceMatch.Groups[1].Value}";
                    app.Context.RewritePath(newUrl);
                }
            }
        }

        public void Dispose()
        {
            // 按需清理资源
        }
    }
}
  1. 在web.config中注册模块(此配置不涉及<rule>标签,多数托管环境允许):
<system.webServer>
    <modules>
        <add name="WcfUrlRewriteModule" type="YourNamespace.WcfUrlRewriteModule" />
    </modules>
</system.webServer>

方案二:自定义ServiceHostFactory(自托管/深度WCF扩展场景)

通过扩展WCF的ServiceHostFactory实现地址映射,适用于自托管或需要贴近WCF运行时的场景:

  1. 创建自定义Factory及相关扩展类:
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Text.RegularExpressions;

namespace YourNamespace
{
    public class CustomServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var host = base.CreateServiceHost(serviceType, baseAddresses);
            host.Description.Behaviors.Add(new UrlRewriteBehavior());
            return host;
        }
    }

    public class UrlRewriteBehavior : IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (var channelDispatcher in serviceHostBase.ChannelDispatchers)
            {
                if (channelDispatcher is WebHttpDispatcher webDispatcher)
                {
                    webDispatcher.DispatchRuntime.MessageInspectors.Add(new UrlRewriteInspector());
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
    }

    public class UrlRewriteInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            var httpProp = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
            var originalUrl = httpProp.RequestUri.AbsolutePath;

            // 处理第二条规则
            var moreServicesRegex = new Regex(@".*(MoreServices)(.+)", RegexOptions.IgnoreCase);
            var moreServicesMatch = moreServicesRegex.Match(originalUrl);
            if (moreServicesMatch.Success)
            {
                var newUri = new Uri(httpProp.RequestUri.AbsoluteUri.Replace(moreServicesMatch.Value, moreServicesMatch.Groups[2].Value));
                httpProp.RequestUri = newUri;
                return null;
            }

            // 处理第一条规则
            var myServiceRegex = new Regex(@"^/MyService/(.*)$", RegexOptions.IgnoreCase);
            var myServiceMatch = myServiceRegex.Match(originalUrl);
            if (myServiceMatch.Success)
            {
                var filePath = System.Web.HttpContext.Current?.Server.MapPath(originalUrl);
                if (filePath != null && !File.Exists(filePath) && !Directory.Exists(filePath))
                {
                    var newPath = $"/MyService.svc/{myServiceMatch.Groups[1].Value}";
                    var newUri = new Uri(httpProp.RequestUri.AbsoluteUri.Replace(originalUrl, newPath));
                    httpProp.RequestUri = newUri;
                }
            }

            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
    }
}
  1. 在.svc文件中指定自定义Factory:
<%@ ServiceHost Language="C#" Debug="true" Service="YourNamespace.MyService" Factory="YourNamespace.CustomServiceHostFactory" %>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 02:55:16