搭建WebRTC视频会议服务01

本系列主要是描述了,在虚拟机中通过CentOS7+Intel Collaboration Suite4.1实现WebRTC视频的基本步骤。

1、安装CentOS7,并配置网络信息
A、通过网卡1(HostOnly),实现主机与虚拟机的通讯
B、通过网卡2(NAT),实现虚拟机的外网访问

2、下载Intel Collaboration Suite4.1,并解压,将需要的组件上传到虚拟机
https://software.intel.com/en-us/webrtc-sdk

3、安装中间件
3.1、Node.js
https://nodejs.org/dist/8.12.0/

#官方文档上要的版本为node-v6.9.5-linux-x64,但实际要求v8以上
tar -xf node-v8.12.0-linux-x64.tar.gz
mv node-v8.12.0-linux-x64 /home/neohope/
ln -s /home/neohope/webrtc/node-v8.12.0-linux-x64/bin/node /usr/bin/node
ln -s /home/neohope/webrtc/node-v8.12.0-linux-x64/bin/npm /usr/bin/npm

3.2、Erlang
https://bintray.com/rabbitmq/rpm/erlang/19.3.6.11-2

#前两步骤主要是为了偷懒,安装依赖包
yum install erlang
yum erase erlang-erts
rpm -ivh erlang-19.3.6.11-2.el7.centos.x86_64.rpm

3.3、Rabbitmq
http://www.rabbitmq.com/download.html

#注意Erlang版本依赖
rpm -ivh erlang-19.3.6.11-2.el7.centos.x86_64.rpm
#配置为自动启动
chkconfig rabbitmq-server on
#开启服务
service rabbitmq-server start

3.4、MongoDB
http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/RPMS/

#官方要的mongodb版本很低
rpm -ivh mongo-10gen-2.4.9-mongodb_1.x86_64.rpm
rpm -ivh mongo-10gen-server-2.4.9-mongodb_1.x86_64.rpm

4、安装Peer Server
4.1、安装

tar –zxvf CS_WebRTC_Conference_Server_Peer.v4.1.tgz
mv PeerServer-Release-4.1 /home/neohope/
cd /home/neohope/PeerServer-Release-4.1
npm install

4.2、测试

cd /home/neohope/PeerServer-Release-4.1
node peerserver.js
#测试完毕后ctrl+c退出

编译ss-qt5

1、安装依赖

sudo apt-get install qt5-default
sudo apt-get install cmake
sudo apt-get install libbotan-2-dev
sudo apt-get install libqrencode-dev
sudo apt-get install libzbar-dev

2、编译libQtShadowsocks

wget https://github.com/shadowsocks/libQtShadowsocks/archive/v2.1.0.tar.gz
tar -xvf libQtShadowsocks-2.1.0.tar.gz
cd libQtShadowsocks-2.1.0
make build
cd build
cmake .. -DCMAKE_INATALL_PREFIX=/usr -DUSE_BOTAN2=ON
make -j4
make
sudo make install

3、编译shadowsocks-qt5

git clone https://github.com/shadowsocks/shadowsocks-qt5.git
cd shadowsocks-qt5
make build
cd build
cmake .. -DCMAKE_INATALL_PREFIX=/usr
make -j4
make

4、运行

ss-qt5

jekyll环境搭建

大家都知道github pages是用了jekyll,我们自己如何搭建一个网站呢?

#安装依赖环境
apt-get install ruby ruby-dev

#安装jekyll
gem install bundler jekyll

#新建网站
jekyll new mysite

#开启网站
cd mysite
bundle exec jekyll serve --host 0.0.0.0

#浏览网站
http://172.16.172.80:4000

好API的6个特质


好API的6个特质

API之于程序员就如同图形界面之于普通用户(end-user)。API中的『P』实际上指的是『程序员』(Programmer),而不是『程序』(Program),强调的是API是给程序员使用的这一事实。

在第13期Qt季刊,Matthias 的关于API设计的文章中提出了观点:API应该极简(minimal)且完备(complete)、语义清晰简单(have clear and simple semantics)、符合直觉(be intuitive)、易于记忆(be easy to memorize)和引导API使用者写出可读代码(lead to readable code)。

1 极简
极简的API是指每个class的public成员尽可能少,public的class也尽可能少。这样的API更易理解、记忆、调试和变更。

2 完备
完备的API是指期望有的功能都包含了。这点会和保持API极简有些冲突。如果一个成员函数放在错误的类中,那么这个函数的潜在用户就会找不到,这也是违反完备性的。

3 语义清晰简单
就像其他的设计一样,我们应该遵守最少意外原则(the principle of least surprise)。好的API应该可以让常见的事完成的更简单,并有可以完成不常见的事的可能性,但是却不会关注于那些不常见的事。解决的是具体问题;当没有需求时不要过度通用化解决方案。

4 符合直觉
就像计算机里的其他事物一样,API应该符合直觉。对于什么是符合直觉的什么不符合,不同经验和背景的人会有不同的看法。API符合直觉的测试方法:经验不很丰富的用户不用阅读API文档就能搞懂API,而且程序员不用了解API就能看明白使用API的代码。

5 易于记忆
为使API易于记忆,API的命名约定应该具有一致性和精确性。使用易于识别的模式和概念,并且避免用缩写。

6 引导API使用者写出可读代码
代码只写一次,却要多次的阅读(还有调试和修改)。写出可读性好的代码有时候要花费更多的时间,但对于产品的整个生命周期来说是节省了时间的。

最后,要记住的是,不同的用户会使用API的不同部分。尽管简单使用单个Qt类的实例应该符合直觉,但如果是要继承一个类,让用户事先看好文档是个合理的要求。

转载自coolshell

几种常见的微服务编排模式

随着需要管理服务的增多,如何编排服务,成了一个很迫切的问题。本文就介绍几种常见的微服务编排方式:

1、Orchestration
这种方式,和BPM、ESB的思想很相似,实现方案多是同步的。
首先要有一个流程控制服务,该服务接收请求,依照业务逻辑规则,依次调用各个微服务,并最终完成处理逻辑。
这种方法的好处是,流程控制服务时时刻刻都知道每一笔业务究竟进行到了什么地步,监控业务成了相对简单的事情。
这种方法的坏处是,流程控制服务很容易控制了太多的业务逻辑,耦合度过高,变得臃肿,而各个微服务退化为单纯的增删改查,容易失去自身价值。

为了便于理解,您可以把控制服务看作BPM、ESB引擎,微服务为BPM、ESB的各种组件。

2、Choreography
这种方式,可以看作一种消息驱动模式,或者说是订阅发布模式,实现方案多是异步的。
每笔业务到来后,各个监听改事件的服务,会主动获取消息,处理,并可以按需发布自己的消息。
这种方法的好处是,耦合度低,每个服务都可以各司其职。
这种方法的坏处是,业务流程是通过订阅的方式来体现的,很难直接监控每笔业务的处理,因此需要增加相应的监控系统,来保证业务顺畅进行。

为了便于理解,您可以把不同队列看作不同种类的消息,微服务看作消息处理函数。

3、API网关
API网关,可以看作一种简单的接口聚合/拆分的方式。
每笔业务到来后,先到达网关,网关调用各微服务,并最终聚合/拆分需反馈的结果。
这种方法的好处是,对外接口相对稳定,可以利用LAN的带宽,弥补因特网的不足。
这种方法的坏处是,只适合业务逻辑较为简单的场景,业务逻辑过于复杂时,网关接口耦合度及复杂度会急剧升高,变得臃肿。

其实就是一个适配网关,比如对于Web端,可以一个页面同时发起几十个请求,而对于移动端,最好是一个页面就几个请求
。而采用API网关,后面的微服务可以是相同的。

微软MVC实现REST风格编程

1、总体来说很简单,首先新建一个MVC框架的项目,模板选择WebAPI,这样就搞定80%了。

2、WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace UrlToPngWebAPI
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.EnableSystemDiagnosticsTracing();
        }
    }
}

3、RouteConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace UrlToPngWebAPI
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

4、请求结构
Web2PNGRequest.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Newtonsoft.Json;

namespace UrlToPngWebAPI.Models
{
    public class Web2PNGRequest
    {
        [JsonProperty]
        public String WebURL { get; set; }
        [JsonProperty]
        public String HeaderPath { get; set; }
        [JsonProperty]
        public String FooterPath { get; set; }
    }
}

5、返回结构
Web2PNGResponse.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;

namespace UrlToPngWebAPI.Models
{
    public class Web2PNGResponse
    {
        [JsonProperty]
        public int ErrorCode { get; set; }
        [JsonProperty]
        public String ErrorInfo { get; set; }
        [JsonProperty]
        public String PNGPath { get; set; }
    }
}

6、Controller
Url2PNGController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Helpers;
using System.Web.Http;
using Newtonsoft.Json;
using UrlToPngCsTest;
using UrlToPngWebAPI.Models;
using UrlToPngWebAPI.Pulgins;

namespace UrlToPngWebAPI.Controllers
{
    public class Url2PNGController : ApiController
    {
        // 返回输入参数示例
        public HttpResponseMessage Get()
        {
            Web2PNGRequest req = new Web2PNGRequest();
            req.WebURL = "webURL";
            req.HeaderPath = "headerPath";
            req.FooterPath = "footerPath";

            String jsonString = JsonConvert.SerializeObject(req);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }

        // GET
        public HttpResponseMessage Get(String WebURL, String HeaderPath, String FooterPath)
        {
            UrlToPng4Web.InitUrlTOPng4CS();

            Web2PNGRequest req = new Web2PNGRequest();
            req.WebURL = WebURL;
            req.HeaderPath = HeaderPath;
            req.FooterPath = FooterPath;
            Web2PNGResponse rsp = UrlToPng4Web.UrlToPNG(req);
            
            String jsonString = JsonConvert.SerializeObject(rsp);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }

        // POST
        public HttpResponseMessage Post(Web2PNGRequest req)
        {
            UrlToPng4Web.InitUrlTOPng4CS();

            Web2PNGResponse rsp = UrlToPng4Web.UrlToPNG(req);

            String jsonString = JsonConvert.SerializeObject(rsp);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }
    }
}

Jersey实现REST风格编程

首先是服务端:
1、增加服务类

package com.neohope.jessery.test;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

/**
 * Created by Hansen
*/
@Path("neotest")
@Produces(MediaType.APPLICATION_JSON)
public class NeoTest {
    @GET
    @Path("/Add")
    public String Add(@QueryParam("a") int a,@QueryParam("b") int b) {
        return "{\"c\":" + (a+b) + "}";
    }

    @GET
    @Path("/SayHiTo")
    public String sayHiTo(@QueryParam("name") String name) {
        return "{\"msg\":\"hi " + name + "\"}";
    }
}

2、在web.xml里增加配置

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.neohope.jessery.test</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/Rest/*</url-pattern>
    </servlet-mapping>

3、然后是客户端

package com.neohope.jessery.test;

import org.glassfish.jersey.client.ClientConfig;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

/**
 * Created by Hansen
 */
public class ClientTest {
    public static void main(String[] args) {
        ClientConfig clientConfig = new ClientConfig();
        Client client = ClientBuilder.newClient(clientConfig);

        WebTarget target = client.target("http://localhost:8080/Rest/neotest/" + "Add");
        Response response = target.queryParam("a", 1).queryParam("b", 2).request().get();
        System.out.println(response.getStatus());
        System.out.println(response.readEntity(String.class));
        response.close();

        WebTarget target1 = client.target("http://localhost:8080/Rest/neotest/" + "SayHiTo");
        Response response1 = target1.queryParam("name", "neohope").request().get();
        System.out.println(response1.getStatus());
        System.out.println(response1.readEntity(String.class));
        response1.close();
    }
}

WCF自托管服务

一般有两种方式实现:

1、通过代码设置直接实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using WcfTest;

namespace WcfHosting
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof (SoapService)))
            {
                host.AddServiceEndpoint(typeof(ISoapService), new WSHttpBinding(), "http://127.0.0.1:1234/neohope");

                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                {
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;
                    behavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/neohope/metadata");
                    host.Description.Behaviors.Add(behavior);
                }

                host.Opened += delegate
                {
                    Console.WriteLine("service started, press enter to exit.");
                };
                host.Open();
                Console.Read();
            }
        }
    }
}

2、通过配置文件实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using WcfTest;

namespace WcfHosting
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof (SoapService)))
            {
                host.Opened += delegate
                {
                    Console.WriteLine("service started, press enter to exit.");
                };
                host.Open();
                Console.Read();
            }
        }
    }
}

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadataBehavior">
          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:9999/neohope/metadata" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="metadataBehavior" name="WcfTest.SoapService">
        <endpoint address="http://127.0.0.9999/neohope" binding="wsHttpBinding"
                  contract="WcfTest.ISoapService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

WCF修改SOAP命名空间

有三个地方可以修改SOAP的命名空间:

1、ServiceContract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web.Configuration;

namespace WcfTest
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract(Name="SoapService",Namespace="http://wcftest.neohope.org")]
    public interface ISoapService
    {
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "User/Get/{uid}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        NUser GetUser(String uid);

        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string UpdateUser(NUser newuser);


        [OperationContract]
        [WebInvoke(Method = "PUT", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string AddUser(NUser newuser);


        [OperationContract]
        [WebInvoke(Method = "DELETE", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string DeleteUser(String uid);
    }

    [ServiceBehavior(Name = "SoapService", Namespace = "http://wcftest.neohope.org")]
    [DataContract]
    public class NUser
    {
        string uid = "";
        string uname = "";
        string usex = "";

        [DataMember]
        public String Uid
        {
            get { return uid; }
            set { uid = value; }
        }

        [DataMember]
        public string UName
        {
            get { return uname; }
            set { uname = value; }
        }

        [DataMember]
        public string USex
        {
            get { return usex; }
            set { usex = value; }
        }
    }
}

2、服务实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfTest
{
    [ServiceBehavior(Name = "SoapService", Namespace = "http://wcftest.neohope.org")]
   public class SoapService : ISoapService
    {
        static List<NUser> users = new List<NUser>();

        static SoapService()
        {
            NUser aNUser = new NUser();
            aNUser.Uid = "001";
            aNUser.UName = "张三";
            aNUser.USex = "男";
            users.Add(aNUser);
        }

        public NUser GetUser(string uid)
        {
            foreach (NUser nuser in users)
            {
                if (nuser.Uid == uid)
                {
                    return nuser;
                }
            }

            return null;
        }

        public string UpdateUser(NUser newuser)
        {
            if (newuser == null)
            {
                return "nuewuser is null";
            }

            foreach (NUser nuser in users)
            {
                if (nuser.Uid == newuser.Uid)
                {
                    nuser.UName = newuser.UName;
                    newuser.USex = nuser.USex;
                    return "User updated";
                }
            }

            return "User not found";
        }

        public string AddUser(NUser newuser)
        {
            if (newuser == null)
            {
                return "nuewuser is null";
            }

            foreach (NUser nuser in users)
            {
                if (nuser.Uid == newuser.Uid)
                {
                    nuser.UName = newuser.UName;
                    newuser.USex = nuser.USex;
                    return "User updated";
                }
            }

            users.Add(newuser);

            return "User added";
        }

        public string DeleteUser(String uid)
        {
            bool bFound = false;
            for(int i=users.Count-1;i>=0;i--)
            {
                if (users[i].Uid == uid)
                {
                    bFound = true;
                    users.RemoveAt(i);
                }
            }

            if (!bFound)
            {
                return "User Not Found";
            }
            else
            {
                return "User Deleted";
            }
        }
    }
}

3、Web.config

<?xml version="1.0"?>
<configuration>
  
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  
  <system.serviceModel>

    <services>
      <service name="WcfTest.SoapService">
        <endpoint binding="webHttpBinding" contract="WcfTest.ISoapService" bindingNamespace="http://wcftest.neohope.org"/>
      </service>
    </services>
 
    <behaviors>
      <endpointBehaviors>
      </endpointBehaviors>
      
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

WCF实现REST风格编程

1、首先需要一个ServiceContract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfTest
{
    [ServiceContract]
    public interface IRestService
    {
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "User/Get/{uid}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        NUser GetUser(String uid);


        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string UpdateUser(NUser newuser);


        [OperationContract]
        [WebInvoke(Method = "PUT", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string AddUser(NUser newuser);


        [OperationContract]
        [WebInvoke(Method = "DELETE", UriTemplate = "/User", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        string DeleteUser(String uid);
    }

    [DataContract]
    public class NUser
    {
        string uid = "";
        string uname = "";
        string usex = "";

        [DataMember]
        public String Uid
        {
            get { return uid; }
            set { uid = value; }
        }

        [DataMember]
        public string UName
        {
            get { return uname; }
            set { uname = value; }
        }

        [DataMember]
        public string USex
        {
            get { return usex; }
            set { usex = value; }
        }
    }
}


2、然后需要实现服务

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace WcfTest
{
    public class RestService : IRestService
    {
        static List<NUser> users = new List<NUser>();

        static RestService()
        {
            NUser aNUser = new NUser();
            aNUser.Uid = "001";
            aNUser.UName = "张三";
            aNUser.USex = "男";
            users.Add(aNUser);
        }

        public NUser GetUser(string uid)
        {
            foreach (NUser nuser in users)
            {
                if (nuser.Uid == uid)
                {
                    return nuser;
                }
            }

            return null;
        }

        public string UpdateUser(NUser newuser)
        {
            if (newuser == null)
            {
                return "nuewuser is null";
            }

            foreach (NUser nuser in users)
            {
                if (nuser.Uid == newuser.Uid)
                {
                    nuser.UName = newuser.UName;
                    newuser.USex = nuser.USex;
                    return "User updated";
                }
            }

            return "User not found";
        }

        public string AddUser(NUser newuser)
        {
            if (newuser == null)
            {
                return "nuewuser is null";
            }

            foreach (NUser nuser in users)
            {
                if (nuser.Uid == newuser.Uid)
                {
                    nuser.UName = newuser.UName;
                    newuser.USex = nuser.USex;
                    return "User updated";
                }
            }

            users.Add(newuser);

            return "User added";
        }

        public string DeleteUser(String uid)
        {
            bool bFound = false;
            for(int i=users.Count-1;i>=0;i--)
            {
                if (users[i].Uid == uid)
                {
                    bFound = true;
                    users.RemoveAt(i);
                }
            }

            if (!bFound)
            {
                return "User Not Found";
            }
            else
            {
                return "User Deleted";
            }
        }
    }
}

3、修改服务的Markup

<%@ ServiceHost Language="C#" Debug="true" Service="WcfTest.RestService" CodeBehind="RestService.svc.cs" 
    Factory="System.ServiceModel.Activation.WebServiceHostFactory"%>

4、修改服务配置
添加serviceBehaviors、endpointBehaviors、service、endpoint

<?xml version="1.0"?>
<configuration>
  
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="RestSvcBehavior" name="WcfTest.RestService">
        <endpoint binding="webHttpBinding" contract="WcfTest.IRestService" address="" behaviorConfiguration="RestEPBehavior"/>
      </service>
    </services>
 
    <behaviors>
      <endpointBehaviors>
        <behavior name="RestEPBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      
      <serviceBehaviors>
        <behavior name="RestSvcBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

5、访问服务

http://ip:port/RestService.svc/User/Get/001