1. WCF与ASP.NET的共生关系解析
在.NET生态系统中,WCF(Windows Communication Foundation)和ASP.NET作为两大核心技术框架,它们的交互方式一直是开发者关注的焦点。让我们从一个实际的场景切入:假设你正在维护一个既包含传统ASP.NET页面又需要提供Web服务的IIS应用,这时理解两者的协作机制就显得尤为重要。
WCF服务在IIS中与ASP.NET内容共存时,采用的是"并行处理"模型。这意味着虽然它们共享同一个应用域(AppDomain),但请求处理路径却完全不同。当HTTP请求到达IIS时,服务器会根据文件扩展名(.svc或.aspx)决定由哪个运行时处理——.svc交给WCF运行时,.aspx则交给ASP.NET运行时。这种设计带来了几个关键特性:
- 资源共享:两者可以共享AppDomain级别的状态,包括静态变量、事件等
- 独立处理管道:WCF有自己的消息拦截和路由机制,不依赖ASP.NET的HTTP管道
- 环境一致性:WCF服务在不同宿主环境(IIS、Windows服务等)中表现一致
重要提示:在并行模式下,ASP.NET的HttpContext.Current在WCF服务中始终为null,这是许多迁移项目遇到的第一个坑。正确的替代方案是使用WCF的OperationContext。
2. 构建ASP.NET模拟WCF的基础框架
2.1 项目结构与核心组件
要实现用ASP.NET模拟WCF基础架构,我们需要建立以下项目结构:
WcfSimulation ├── Contracts (类库) │ ├── IService.cs ├── Services (类库) │ ├── Service.cs ├── Host (ASP.NET Web应用) │ ├── ServiceHandler.ashx │ ├── Web.config └── Client (控制台应用) ├── Program.cs关键组件说明:
- 契约接口(IService.cs):
[ServiceContract] public interface IService { [OperationContract] string GetData(int value); }- 服务实现(Service.cs):
public class Service : IService { public string GetData(int value) { return $"You entered: {value}"; } }2.2 自定义请求处理器实现
在ASP.NET中,我们通过泛型处理器(ASHX)来模拟WCF的终结点行为:
public class ServiceHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { // 1. 解析请求 var request = context.Request; var response = context.Response; // 2. 模拟WCF的消息格式化 var serializer = new DataContractSerializer(typeof(ServiceRequest)); var requestData = (ServiceRequest)serializer.ReadObject(request.InputStream); // 3. 服务调用 var service = new Service(); var result = service.GetData(requestData.Value); // 4. 构建响应 response.ContentType = "text/xml"; var responseData = new ServiceResponse { Result = result }; serializer.WriteObject(response.OutputStream, responseData); } public bool IsReusable => false; }2.3 配置路由映射
在Web.config中配置处理器映射,模拟.svc终结点:
<system.webServer> <handlers> <add name="ServiceHandler" path="Service.svc" verb="*" type="WcfSimulation.Host.ServiceHandler" resourceType="Unspecified" /> </handlers> </system.webServer>3. 消息处理管道的深度模拟
3.1 请求/响应消息契约
WCF的核心在于其基于消息的通信模型。我们需要定义模拟的消息结构:
[DataContract] public class ServiceRequest { [DataMember] public int Value { get; set; } } [DataContract] public class ServiceResponse { [DataMember] public string Result { get; set; } }3.2 消息编码与序列化
WCF支持多种编码格式,这里我们模拟最常用的Text/XML编码:
public class MessageFormatter { public static T Deserialize<T>(Stream stream) { var serializer = new DataContractSerializer(typeof(T)); return (T)serializer.ReadObject(stream); } public static void Serialize<T>(Stream stream, T obj) { var serializer = new DataContractSerializer(typeof(T)); serializer.WriteObject(stream, obj); } }3.3 操作选择器实现
WCF根据消息内容决定调用哪个服务操作,我们的模拟实现:
public class OperationSelector { public MethodInfo SelectOperation(string action) { var serviceType = typeof(Service); return serviceType.GetMethods() .FirstOrDefault(m => m.GetCustomAttribute<OperationContractAttribute>()?.Action == action); } }4. 客户端代理的模拟实现
4.1 客户端信道工厂
在WCF中,ChannelFactory负责创建服务代理,我们的简化版本:
public class ServiceProxy : ClientBase<IService>, IService { public ServiceProxy(string endpointUrl) : base(new BasicHttpBinding(), new EndpointAddress(endpointUrl)) { } public string GetData(int value) { return Channel.GetData(value); } }4.2 实际调用示例
客户端使用方式与真实WCF高度相似:
class Program { static void Main() { var proxy = new ServiceProxy("http://localhost:5000/Service.svc"); var result = proxy.GetData(42); Console.WriteLine(result); } }5. 兼容性模式下的特殊处理
5.1 ASP.NET兼容模式模拟
当需要访问ASP.NET上下文时,我们可以创建兼容层:
public class AspNetCompatibilityContext { public static HttpContext Current => HttpContext.Current; public static void EnsureCompatibility() { if (Current == null) throw new InvalidOperationException( "ASP.NET compatibility mode required"); } }5.2 兼容性检查属性
模拟WCF的AspNetCompatibilityRequirementsAttribute:
[AttributeUsage(AttributeTargets.Class)] public class AspNetCompatibilityRequirementsAttribute : Attribute { public CompatibilityRequirementsMode RequirementsMode { get; } public AspNetCompatibilityRequirementsAttribute( CompatibilityRequirementsMode requirementsMode) { RequirementsMode = requirementsMode; } } public enum CompatibilityRequirementsMode { Allowed, Required, NotAllowed }6. 安全模型的模拟实现
6.1 基本认证流程
public class SecurityInterceptor { public void Authenticate(HttpContext context) { var authHeader = context.Request.Headers["Authorization"]; if (string.IsNullOrEmpty(authHeader)) { context.Response.StatusCode = 401; context.Response.AddHeader("WWW-Authenticate", "Basic"); context.Response.End(); } else { var credentials = Encoding.UTF8.GetString( Convert.FromBase64String(authHeader.Substring(6))); // 验证逻辑... } } }6.2 授权策略
模拟WCF的ServiceAuthorizationBehavior:
public class ServiceAuthorizationManager { public bool CheckAccess(OperationContext operationContext) { var context = HttpContext.Current; // 实现自定义授权逻辑 return context.User.Identity.IsAuthenticated; } }7. 异常处理与错误传递
7.1 错误契约定义
[DataContract] public class ServiceFault { [DataMember] public string Message { get; set; } [DataMember] public DateTime Timestamp { get; set; } }7.2 全局异常处理器
public class ErrorHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { try { // 正常处理流程 } catch (Exception ex) { context.Response.StatusCode = 500; context.Response.ContentType = "text/xml"; var fault = new ServiceFault { Message = ex.Message, Timestamp = DateTime.Now }; new DataContractSerializer(typeof(ServiceFault)) .WriteObject(context.Response.OutputStream, fault); } } }8. 性能优化关键点
8.1 实例管理策略
模拟WCF的InstanceContextMode:
public enum InstanceMode { PerCall, PerSession, Single } public class ServiceHost { private readonly InstanceMode _instanceMode; private object _singletonInstance; public ServiceHost(InstanceMode instanceMode) { _instanceMode = instanceMode; } public object GetServiceInstance(Type serviceType) { switch (_instanceMode) { case InstanceMode.PerCall: return Activator.CreateInstance(serviceType); case InstanceMode.Single: return _singletonInstance ??= Activator.CreateInstance(serviceType); default: throw new NotSupportedException(); } } }8.2 消息缓冲优化
public class BufferedMessage { private MemoryStream _stream; public BufferedMessage(Stream inputStream) { _stream = new MemoryStream(); inputStream.CopyTo(_stream); _stream.Position = 0; } public Stream GetStream() => _stream; }通过这个完整的模拟实现,我们不仅深入理解了WCF的基础架构,也掌握了如何在必要时用ASP.NET构建类似的通信框架。这种理解对于调试复杂场景、进行框架迁移或性能优化都有极大帮助。