基于WinService,开发Restful 风格的Wcf 服务端

2021-07-25 20:55

阅读:513

  开发目的:降低和IIS的耦合,使用Winservice做宿主,迁移方便快捷。

  步骤:

 1.添加WcfService,分别实现 Get 和 Post 方法

  

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Runtime.Serialization;
 5 using System.ServiceModel;
 6 using System.ServiceModel.Web;
 7 using System.Text;
 8 
 9 namespace WcfSelfHost
10 {
11     // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
12     [ServiceContract]
13     public interface IService1
14     {
15         [OperationContract]
16         string  Get();
17 
18         [OperationContract]
19 
20         string Post();
21     }
22 }

 

 

 

2.分别为每个方法添加路由信息,指定请求方式,确定返回信息格式

[ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [WebInvoke(Method = "GET",
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/method/")]
        string  Get();

        [OperationContract]
        [WebInvoke(Method = "Post",
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/method/")]
        string Post();
    }

3.接口实现:

public class Service1 : IService1
    {
        
        #region Implementation of IService1

        public string Get()
        {
            return "this is get method!";
        }

        public string Post()
        {
            return "this is post method";
        }

        #endregion
    }

4.如何解决跨域问题(坑)?

  如果使用ajax来访问,会有跨域问题,api正常返回数据,但是ajax无法接收。

经测试,发现最好用的方法,是通过对请求添加拦截器的方式来处理,可以100%的解决跨域问题:

MessageInspector.cs

public class MessageInspector:IDispatchMessageInspector
    {
        private ServiceEndpoint _serviceEndpoint;

        public MessageInspector(ServiceEndpoint serviceEndpoint)
        {
            _serviceEndpoint = serviceEndpoint;
        }

        /// 
        /// Called when an inbound message been received
        /// 
        /// The request message.
        /// The incoming channel.
        /// The current service instance.
        /// 
        /// The object used to correlate stateMsg. 
        /// This object is passed back in the method.
        /// 
        public object AfterReceiveRequest(ref Message request, 
                                                IClientChannel channel, 
                                                InstanceContext instanceContext)
        {
            StateMessage stateMsg = null;
            HttpRequestMessageProperty requestProperty = null;
            if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
            {
            requestProperty = request.Properties[HttpRequestMessageProperty.Name]
                                as HttpRequestMessageProperty;
            }

            if (requestProperty != null)
            {
            var origin = requestProperty.Headers["Origin"];
            if (!string.IsNullOrEmpty(origin))
            {
                stateMsg = new StateMessage();
                // if a cors options request (preflight) is detected, 
                // we create our own reply message and don‘t invoke any 
                // operation at all.
                if (requestProperty.Method == "OPTIONS")
                {
                stateMsg.Message = Message.CreateMessage(request.Version, null);
                }
                request.Properties.Add("CrossOriginResourceSharingState", stateMsg);
            }
            }

            return stateMsg;
        }

        /// 
        /// Called after the operation has returned but before the reply message
        /// is sent.
        /// 
        /// The reply message. This value is null if the 
        /// operation is one way.
        /// The correlation object returned from
        ///  the method.
        public void BeforeSendReply(ref  Message reply, object correlationState)
        {
            var stateMsg = correlationState as StateMessage;

            if (stateMsg != null)
            {
            if (stateMsg.Message != null)
            {
                reply = stateMsg.Message;
            }

            HttpResponseMessageProperty responseProperty = null;

            if (reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
            {
                responseProperty = reply.Properties[HttpResponseMessageProperty.Name]
                                    as HttpResponseMessageProperty;
            }

            if (responseProperty == null)
            {
                responseProperty = new HttpResponseMessageProperty();
                reply.Properties.Add(HttpResponseMessageProperty.Name,
                                    responseProperty);
            }

            // Access-Control-Allow-Origin should be added for all cors responses
            responseProperty.Headers.Set("Access-Control-Allow-Origin", "*");

            if (stateMsg.Message != null)
            {
                // the following headers should only be added for OPTIONS requests
                responseProperty.Headers.Set("Access-Control-Allow-Methods",
                                            "POST, OPTIONS, GET,DELETE,PUT");
                responseProperty.Headers.Set("Access-Control-Allow-Headers",
                        "Content-Type, Accept, Authorization, x-requested-with");
            }
            }
        }
        }

        class StateMessage
        {
        public Message Message;
        }

 

BehaviorAttribute.cs

public class BehaviorAttribute : Attribute, IEndpointBehavior,
                                 IOperationBehavior
    {
        public void Validate(ServiceEndpoint endpoint) { }

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

        /// 
        /// This service modify or extend the service across an endpoint.
        /// 
        /// The endpoint that exposes the contract.
        /// The endpoint dispatcher to be
        /// modified or extended.
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
                                          EndpointDispatcher endpointDispatcher)
        {
            // add inspector which detects cross origin requests
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
                                                   new MessageInspector(endpoint));
        }

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

        public void Validate(OperationDescription operationDescription) { }

        public void ApplyDispatchBehavior(OperationDescription operationDescription,
                                          DispatchOperation dispatchOperation) { }

        public void ApplyClientBehavior(OperationDescription operationDescription,
                                        ClientOperation clientOperation) { }

        public void AddBindingParameters(OperationDescription operationDescription,
                                  BindingParameterCollection bindingParameters) { }

    }

对请求添加拦截:

      private static ServiceHost host;
        private static ServiceHost crosspolicy;
        public static void Start()
        {
            host = new ServiceHost(typeof(Service1));
            host.Description.Endpoints[0].Behaviors.Add(new BehaviorAttribute());
            host.Opening += (o, e) => {};
            host.Opened += (o, e) =>
            {
                
            };
            host.Closing += (o, e) => { Console.WriteLine(" data server Closing..."); };
            host.Closed += (o, e) => { Console.WriteLine("data setver Closed."); };
            host.Open();
            Console.Read();
        }

 

5.APP.config:

xml version="1.0" encoding="utf-8" ?>
configuration>
  system.web>
    compilation debug="true"/>
  system.web>
  system.serviceModel>
    services>
      service name="WcfSelfHost.Service1">
        endpoint address="" binding="webHttpBinding" contract="WcfSelfHost.IService1" behaviorConfiguration="web">
        endpoint>
        endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        host>
          baseAddresses>
            add baseAddress="http://127.0.0.1:12121/api/" />
          baseAddresses>
        host>
      service>
    services>
    behaviors>
      serviceBehaviors>
        behavior >         
          serviceMetadata httpGetEnabled="True"/>          
          serviceDebug includeExceptionDetailInFaults="False" />
        behavior>
      serviceBehaviors>
      endpointBehaviors>
        behavior name="web">
          webHttp/>
        behavior>
      endpointBehaviors>
    behaviors>
  system.serviceModel>
configuration>

后续步骤:改造成winService,笔者使用批处理脚本来进行服务安装不再赘述。


评论


亲,登录后才可以留言!