WCF拦截

Posted 布雷客·希

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WCF拦截相关的知识,希望对你有一定的参考价值。

WCF经常会有一些性能检测,全局异常,跨域设置,动态路由设置等,可以通过以下类实现

(1)拦截类,可以实现性能检测和全局异常处理

 /// <summary>
    /// 使用消息提取的对象以及参数数组,并利用对该对象调用方法,然后返回该方法的返回值和输出参数
    /// </summary>
    public class OperationInvoker : IOperationInvoker
    {
        private string _operationMethod;//方法名称
        private IOperationInvoker _invoker;//原invoker

        public OperationInvoker(IOperationInvoker oldInvoker, string operationMethod)
        {
            this._invoker = oldInvoker;
            this._operationMethod = operationMethod;
        }

        public object[] AllocateInputs()
        {
            return this._invoker.AllocateInputs();
        }

        //System.ServiceModel.Channels.Message HandlePreflight(System.ServiceModel.Channels.Message input, string operationName)
        //{
        //    System.ServiceModel.Channels.Message reply = System.ServiceModel.Channels.Message.CreateMessage(MessageVersion.None, operationName);
        //    HttpResponseMessageProperty httpResponse = new HttpResponseMessageProperty();
        //    httpResponse.SuppressEntityBody = true;
        //    httpResponse.StatusCode = System.Net.HttpStatusCode.OK;

        //    httpResponse.Headers.Set("Access-Control-Allow-Origin", "*");
        //    httpResponse.Headers.Set("Access-Control-Allow-Methods", string.Join(",", new List<string>() { "POST", "GET", "OPTIONS" }));
        //    reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
        //    return reply;
        //}

        /// <summary>
        /// 从一个实例和输入对象的集合返回一个对象和输出对象的集合
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="inputs"></param>
        /// <param name="outputs"></param>
        /// <returns></returns>
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            this.PreInvoke(instance, inputs);
            object returnValue = null;
            object invokeValue;
            object[] objArray = new object[0];
            try
            {
                string operationName = "";
                if (OperationContext.Current.IncomingMessageHeaders.Action != null)
                {
                    operationName = OperationContext.Current.IncomingMessageHeaders.Action.ToString();
                }
                if (OperationContext.Current.IncomingMessageProperties.Keys.Contains("HttpOperationName"))
                {
                    operationName = OperationContext.Current.IncomingMessageProperties["HttpOperationName"].ToString();
                }

                HttpRequestMessageProperty request =
                    System.ServiceModel.OperationContext.Current.IncomingMessageProperties["httpRequest"] as
                        HttpRequestMessageProperty;
                if (request != null
                    && request.Method == "OPTIONS")
                {
                    System.ServiceModel.Channels.Message input = (System.ServiceModel.Channels.Message)inputs[0];
                    outputs = null;
                    return returnValue;
                }
                else
                {
                    invokeValue = this._invoker.Invoke(instance, inputs, out objArray);
                    returnValue = invokeValue;
                    outputs = objArray;
                }
            }
            catch (System.Exception exception)
            {
                returnValue = HandleException(exception, instance);
                outputs = null;
            }
            return returnValue;
        }

        /// <summary>
        /// 处理异常
        /// </summary>
        /// <returns></returns>
        private ResultInfo HandleException(System.Exception exception, object instance)
        {
            var res = new ResultInfo();
            res.Success = false;
            res.Message = exception.Message;
            res.Excetion = new WcfGlobalException(exception.Message, exception.StackTrace, instance, _operationMethod);
            PackageServiceLib.Helper.EventManager.WriteOutput(exception.Message + exception.StackTrace, LogType.Error);
            //if (exception != null)
            //{
            //    throw exception;
            //}
            return res;
        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            this.PreInvoke(instance, inputs);
            return this._invoker.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            object returnValue = null;
            object invokeValue;
            object[] objArray = new object[0];
            try
            {
                invokeValue = this._invoker.InvokeEnd(instance, out outputs, result);
                returnValue = invokeValue;
                outputs = objArray;
            }
            catch (System.Exception exception)
            {
                returnValue = HandleException(exception, instance);
                outputs = null;
            }
            return returnValue;
        }

        public bool IsSynchronous
        {
            get { return this._invoker.IsSynchronous; }
        }

        private void PreInvoke(object instance, object[] inputs)
        {

        }


    }

  

(2)异常类

[DataContract]
    public class WcfGlobalException
    {
        /// <summary>
        /// 调用方法的实例
        /// </summary>
        [DataMember(Name = "instance")]
        
        public string Instance { set; get; }
        /// <summary>
        /// 调用的方法名称
        /// </summary>
        [DataMember(Name = "operationMethod")]
        public string OperationMethod { set; get; }
        /// <summary>
        /// 异常信息
        /// </summary>
        [DataMember(Name = "message")]
        public string Message { set; get; }
        /// <summary>
        /// 异常trace信息
        /// </summary>
        [DataMember(Name = "stackTrace")]
        public string StackTrace { set; get; }

        public WcfGlobalException(string message, string trace, object instance, string operationName)
        {
            this.Instance = instance.ToString();
            this.OperationMethod = operationName;
            this.Message = message;
            this.StackTrace = trace;
        }
    }

  (3)行为特性标签

 //BehaviorExtensionElement
    public class WcfGlobalExceptionOpreationBehaviorAttribute:Attribute,IServiceBehavior
    {
        //public override Type BehaviorType
        //{
        //    get { return typeof (WcfGlobalExceptionOpreationBehavior); }
        //}

        //protected override object CreateBehavior()
        //{
        //    return new WcfGlobalExceptionOpreationBehavior();
        //}

        private readonly Type _errorHandlerType;
        public WcfGlobalExceptionOpreationBehaviorAttribute(Type handlerType)
        {
            _errorHandlerType = handlerType;
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
           
        }
        /// <summary>
        /// 注入自定义异常处理程序
        /// </summary>
        /// <param name="serviceDescription"></param>
        /// <param name="serviceHostBase"></param>
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            var handler = (IErrorHandler) Activator.CreateInstance(_errorHandlerType);
            foreach (ChannelDispatcher dis in serviceHostBase.ChannelDispatchers)
            {
                dis.ErrorHandlers.Add(handler);
            }
        }

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

    }

  (4)操作的拦截特性

 public class WcfGlobalOperationInterceptorAttribute:Attribute,IOperationBehavior
    {
        private string _operationMethod;

        public WcfGlobalOperationInterceptorAttribute(string methodName)
        {
            this._operationMethod = methodName;
        }

        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
        {
            
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
        {
            IOperationInvoker invoke = dispatchOperation.Invoker;
            dispatchOperation.Invoker = CreateInvoker(invoke);
        }

        public void Validate(OperationDescription operationDescription)
        {
            
        }

        protected OperationInvoker CreateInvoker(IOperationInvoker oldInvoker)
        {
            return new OperationInvoker(oldInvoker, this._operationMethod);
        }
    }

  

(5)服务类的拦截特性

 [AttributeUsage(AttributeTargets.Class)]
    public class WcfGlobalServiceInterceptorAttribute:Attribute,IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            EnableCrossOriginResourceSharingBehavior crossOriginBehavior = new EnableCrossOriginResourceSharingBehavior();
            foreach (var endpoint in serviceDescription.Endpoints)
            {
                endpoint.Behaviors.Add(crossOriginBehavior);
                foreach (var operation in endpoint.Contract.Operations)
                {

if (!operation.Behaviors.Any(d => d is WebGetAttribute)
&& !operation.Behaviors.Any(d => d is WebInvokeAttribute))
{
WebInvokeAttribute wia = new WebInvokeAttribute();
wia.UriTemplate = operation.Name;
wia.Method = "*";
operation.Behaviors.Add(wia);
}

                    bool flag = false;
                    foreach (var operationBehavior in operation.Behaviors)
                    {
                        if (operationBehavior is WcfGlobalOperationInterceptorAttribute)
                        {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag)
                    {
                        operation.Behaviors.Add(CreateOperationInterceptor(operation.Name));
                    }
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            
        }
        protected WcfGlobalOperationInterceptorAttribute CreateOperationInterceptor(string operationMethod)
        {
            return new WcfGlobalOperationInterceptorAttribute(operationMethod);
        }
    }

    public class CustomHeaderMessageInspector : IDispatchMessageInspector
    {
        Dictionary<string, string> requiredHeaders;
        public CustomHeaderMessageInspector(Dictionary<string, string> headers)
        {
            requiredHeaders = headers ?? new Dictionary<string, string>();
        }

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            return null;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
            foreach (var item in requiredHeaders)
            {
                httpHeader.Headers.Add(item.Key, item.Value);
            }
        }
    }

    public class EnableCrossOriginResourceSharingBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {

        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {

        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            var requiredHeaders = new Dictionary<string, string>();
            var allOrigin= ConfigurationManager.AppSettings["allowOrigin"].ToString();
            requiredHeaders.Add("Access-Control-Allow-Origin", allOrigin);
            requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
            requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
            requiredHeaders.Add("Access-Control-Allow-Credentials", "true");
           
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
        }

        public void Validate(ServiceEndpoint endpoint)
        {

        }

        public override Type BehaviorType
        {
            get { return typeof(EnableCrossOriginResourceSharingBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new EnableCrossOriginResourceSharingBehavior();
        }
    }

  

文件下载:http://files.cnblogs.com/files/caiyongxi/WCFHelper.zip

以上是关于WCF拦截的主要内容,如果未能解决你的问题,请参考以下文章

使用拦截器进行 WCF 参数验证

如何使 WCF 数据服务查询拦截器以 JSON 格式返回结果?

C# 中 WCF 和 MVC Web API 的通用请求响应拦截器

ASP.Net WCF 服务的 Thread.CurrentPrincipal 被联邦 (WIF) 环境中的某些拦截器丢弃

OkHttpInterceptor 从 kotlin 拦截器导航到登录片段

METAL顶点/片段着色器“拦截”结果的最佳方法