65.9K
CodeProject 正在变化。 阅读更多。
Home

开发 REST Web 服务(使用 C#)- 演练

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (124投票s)

2010 年 9 月 24 日

CPOL

17分钟阅读

viewsIcon

1300548

downloadIcon

42027

本文重点介绍如何使用 HttpHandlers 从头开始构建 Web 服务,并将详细介绍“幕后”的操作。

目标

本文的目的是使用 C# 创建一个 REST Web 服务,该服务将支持对暴露的对象执行 CRUD 操作。本文重点介绍如何使用 HttpHandlers 从头开始构建 Web 服务,并将详细介绍“幕后”的操作。有很多文档讨论 REST Web 服务,但几乎没有提供完整的代码演练。这正是我打算做的。在后续版本中,我们将了解如何使用内置项目模板来实现相同的目标。

引言

REST 代表“Representational State Transfer”(表述性状态转移)。该术语由 Roy Fielding 在其博士论文中提出。REST 是一种用于设计网络应用程序的架构风格。它是替代 COBRA、RPC 和 SOAP 等复杂机制来连接客户端和服务器的一种方式。REST 通过使用简单的 HTTP 协议(支持对服务器执行 CRUD(创建、读取、更新和删除)操作)使远程计算机之间的通信变得容易。某种程度上,我们的万维网也基于 REST 架构。

简而言之,REST 基于资源的表述。资源是我们可以在万维网上访问的对象。它可以是文档、图像或任何东西。当我们从服务器请求资源(对象)时,服务器会返回该资源的表述。在 REST 架构中,客户端请求在服务器上的对象(资源)上执行操作(CRUD),服务器根据需要返回数据。

示例 - 让我们考虑一个返回员工信息的 Web 服务。Web 服务通过轮询数据库并返回结果来响应客户端调用。在传统的 Web 服务或 WCF 服务中,我们将有一个暴露给客户端的方法,例如 GetEmployee()。REST 架构与此不同,因为它不处理方法,而是处理名词(资源/对象)并允许动词(HTTP 方法)对其进行操作。

因此,如果我们想获取员工信息,我们将对 Employee 对象执行 HTTP GET 请求,而不是调用 GetEmployee() 方法。这种方式有很多优点,其中最重要的优点是我们获得了在对象上进行操作的强大功能和灵活性。

有关更多信息,请参阅文章末尾的“参考文献”部分。我不会详细解释 REST,而是专注于如何从头开始编写一个。

为什么使用 REST?

让我们来看一个实际示例。假设您需要构建一个具有跨功能性且可以被任何客户端使用的 Web 服务。传统的 .NET Web 服务必须使用代理来消费。如果客户端不知道如何创建代理怎么办?试想一下,您的 Web 服务需要由运行在 iPhone 或 Android 上的客户端来消费。据我所知,Objective C 不知道如何创建代理。它只知道向服务器发送基本的 HTTP 动词 - GET、PUT、POST 和 DELETE - 并期望 XML 或字符串作为响应。这就是 REST 的用武之地!!

HTTP 动词

此时,值得回顾一下我们基本的 HTTP 动词。我只会做简要介绍。详细信息很容易在网上找到。

GET – GET 是最简单的 HTTP 方法之一。它的主要作用是向服务器请求资源。该资源可以是 HTML 页面、音频文件、图像文件(JPEG)等。我们可以说 GET 方法用于从服务器获取内容。在 GET 方法中,我们发送的数据会附加到 URL。

示例

GET /path/file.html HTTP/1.0
From: someuser@jmarshall.com
User-Agent: HTTPTool/1.0

POST – POST 方法用于将数据提交给已识别的资源进行处理(例如,来自HTML 表单)。数据包含在请求正文中。这可能会导致创建新资源,或更新现有资源,或两者兼有。

示例

POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

PUT – PUT 方法用于将数据提交给已识别的资源进行更新(例如,来自HTML 表单)。与 POST 方法一样,数据包含在请求正文中。

DELETE - DELETE 方法用于删除特定资源。

HTTP 处理程序

我们将使用 HTTP 处理程序来配置我们的 REST Web 服务。HTTP 处理程序使我们能够通过配置 IIS 中的 ISAPI 过滤器来配置自己的 Web 扩展。简单来说,幕后发生的事情如下:

IIS 监听端口 80(默认)上的任何传入请求。当它收到网页请求时,它会调用一个 Web 应用程序。此请求到 Web 应用程序的路由通过 ISAPI 过滤器完成。例如,如果它收到对 Default.aspx 页面的请求,则名为 aspnet_isapi.dll 的 DLL 会实际调用 Default.aspx 页面。Machine.Config 文件将包含一个映射,该映射将告诉 IIS 如何处理 .aspx Web 请求。用户可以通过配置 IIS 的 ISAPI 过滤器来拥有自己的调用,例如 .codeproject。这是通过 HTTP 处理程序完成的。因此,如果我想发出一个调用,比如 Default.codeproject,而不是 Default.aspx,则必须通过 HTTP 处理程序完成。有关更多信息,请参阅本文的“参考文献”部分。HTTP 处理程序是构建 REST Web 服务的关键。稍后我们将看到如何使用 HTTP 处理程序来公开我们的 Employee 对象。

项目

为了理解 REST,让我们深入研究一个示例项目,看看幕后发生了什么。该项目涉及构建一个示例客户端-服务器数据库应用程序,该应用程序返回员工信息。从上面的 REST 定义,我们可以得出以下结论:

  1. 这里的资源将是暴露给客户端的员工(对象)。
  2. 客户端应该能够对资源执行 CRUD 操作(基本的 HTTP 动词)。

我们必须设计一个系统来完成上述任务。该项目可以分为以下几部分:

  1. 创建一个包含 Employee 表的简单数据库。
  2. 创建一个简单的 Employee 类作为数据库员工信息的占位符。
  3. Employee 编写基本的数据库操作,如读取、更新、删除、插入。
  4. 通过将 Employee 对象暴露给 HTTP 动词来创建 REST Web 服务。
  5. 部署应用程序。
  6. 测试应用程序。

现在是时候定义客户端与服务器通信的方式了。数据交换通过 XML 格式进行,因为它在所有平台之间被广泛接受。

  1. 获取员工信息 - HTTP GET 方法。服务器期望一个 HTTP GET 方法,并将员工代码作为查询字符串参数传递。然后,它从数据库中以 XML 形式返回该特定员工的员工信息。
  2. 示例:https:///RestWebService/employee?id=3550

  3. 插入新员工 - HTTP POST 方法。服务器期望一个 HTTP POST 方法来创建一个新员工。客户端需要将员工信息作为 XML 传递到消息正文中。然后,服务器读取消息正文并在数据库中创建新的员工信息。
  4. 示例 - POST/employeeHTTP/1.1 Host: https:///RestWebService

    <Employee>
      <FirstName>Anshu</FirstName>
      <LastName>Dutta</LastName>
      <EmpCode>3550</EmpCode>
      <Designation>SSE</Designation>
    </Employee>
  5. 更新现有员工 - HTTP PUT 方法。服务器期望一个 HTTP PUT 方法来更新现有员工。客户端需要将正在更新的员工信息作为 XML 传递到消息正文中。然后,服务器读取消息正文并在数据库中更新该特定员工。
  6. 删除现有员工 - HTTP DELETE 方法。服务器期望一个 HTTP DELETE 方法来从数据库中删除特定员工。服务器期望要删除的员工的员工代码作为 URL 的查询字符串参数。
  7. 示例:https:///RestWebService/employee?id=3550

因此,我们可以看到,通过上述设计,我们已成功将一个对象的状态(在本例中为 Employee)暴露给调用它的客户端应用程序。如上所述,REST 的目标是使 HTTP 动词作用于名词。这里,HTTP 动词是 GET、POST、PUT 和 DELETE(CRUD),如上所述。这里的名词是 Employee 资源。如果我们能做到这一点,我们就创建了一个基本的 REST Web 服务。

代码

第 1 部分 - 创建一个包含 Employee 表的简单数据库

这个很简单。您需要创建一个名为 Company 的简单数据库,并创建一个名为 Employee 的表,如下所示。在提供的源代码中,我包含了创建数据库和 Employee 表所需的脚本。我还提供了插入一些虚拟数据的脚本,以便我们开始。请查看 EmployeeDataBase 项目下的脚本文件夹。您只需要复制并运行脚本,一切就绪。

注意:这适用于 SQL Server 2008。如果您使用其他版本的 SQL Server 或任何其他数据库,则需要进行调整。

我们还可以看看将保存员工信息的表的结构。下面是快照。

第 2 部分 - 创建一个 Employee 类作为数据库员工信息的占位符

我在一个名为 Company 的类库项目中包含了这个。我有一个 Employee 类,它具有以下属性:

  • FirstName
  • LastName
  • EmpCode
  • Designation

让我们看看 Employee 类的结构。

<Employee>
  <FirstName>Anshu</FirstName>
  <LastName>Dutta</LastName>
  <EmpCode>3550</EmpCode>
  <Designation>SSE</Designation>
</Employee>

XML 内容相当直观。它具有以下属性:名字、姓氏、员工代码和职位。

请参考下面的代码。代码同样直观。我们定义了类的公共属性。

public string FirstName
{
    get { return _firstName; }
    set { _firstName = value; }
}
public string LastName
{
    get { return _lastName; }
    set { _lastName = value; }
}
public int EmpCode
{
    get { return _empCode; }
    set { _empCode = value; }
}
public string Designation
{
    get { return _designation; }
    set {_designation = value;}
}
public string getEmployeeName()
{
    string fullName = FirstName + ‘ ‘ + LastName;
    return fullName;
}

第 3 部分 - 为 Employee 编写基本的数据库操作,如读取、更新、删除、插入

这一部分包括基本的数据库操作编码,即更新、插入、选择、删除。

我为此专门有一个数据访问层。它称为 DAL,它也是一组类库。它有一个 DAL 类,其中包含数据库操作的代码。

类的构造函数接受连接字符串并连接到数据库。

public DAL(string _connString)
{
    err = new ErrorHandler.ErrorHandler();
    connString = _connString;
}

数据库操作

我在所有情况下都使用了参数化查询,因为它们效率很高。

插入操作的代码

try
{
    using (conn)
    {
        //using parametirized query
        string sqlInserString =
           "INSERT INTO Employee (FirstName, LastName, ID, " + 
           "Designation) VALUES (@firstName, @lastName, @ID, @designation)";
       
        conn = new SqlConnection(connString);
        
        command = new SqlCommand();
        command.Connection = conn;
        command.Connection.Open();
        command.CommandText = sqlInserString;
                    
        SqlParameter firstNameparam = new   SqlParameter("@firstName", emp.FirstName);
        SqlParameter lastNameparam = new SqlParameter("@lastName", emp.LastName);
        SqlParameter IDparam = new SqlParameter("@ID", emp.EmpCode);
        SqlParameter designationParam = new SqlParameter("@designation", emp.Designation);

        command.Parameters.AddRange(new SqlParameter[]{
                firstNameparam,lastNameparam,IDparam,designationParam});
        command.ExecuteNonQuery();
        command.Connection.Close();
    }
}
catch (Exception ex)
{
    err.ErrorMessage = ex.Message.ToString();
    throw;
}

我有一个查询字符串,它接受一个参数化查询。对于插入语句,参数是名字、姓氏、员工代码和职位。然后,我为这些参数声明 SQL 参数并将它们添加到命令参数集合中。然后,我使用 command.ExecuteNonQuery() 执行命令。

更新、删除和选择等其他操作类似。对于选择操作,GetEmployees() 方法返回一个 Employee 类。

值得一提的是,DAL 类有一个名为 GetException() 的方法。该方法将方法遇到的任何异常传递给调用客户端。我将在后续阶段解释此方法的重要性。

public string GetException()
{
    return err.ErrorMessage.ToString();
}

第 4 部分 - 创建 REST Web 服务

现在我们已经为 Web 服务打好了基础,让我们深入研究实际实现 REST 架构的代码。如前所述,REST 涉及将名词(对象)暴露给动词。对 ASP.NET Web 服务器的任何常规请求看起来都像这样:https:///myWbPage.aspx

请记住,我们要暴露的是 Employee 对象,而不是页面。请注意,也可以通过客户端调用一个 .aspx 网页然后将其重定向到执行 CRUD 操作来完成此操作。但这并不是 REST 的意义所在。我们必须将 Employee 对象暴露给调用客户端,而不是 .aspx 网页。这如何实现?这时就需要 HTTP 处理程序了!!

我们将不得不配置 IIS 来处理 **employee** Web 请求。让我们为此创建一个 HTTP 处理程序。请参阅 RestWebService 项目中的 Service 类。该类实现了 IHTTPHandler 接口。

public class Service:IHttpHandler

该接口实现了以下两个方法:

  • bool IHttpHandler.IsReusable
  • 调用此属性以确定 HTTP 处理程序的此实例是否可用于满足同类型的其他请求。HTTP 处理程序可以返回 truefalse 来指定它们是否可重用。

  • void IHttpHandler.ProcessRequest(HttpContext context)
  • 暂时,我们将重点关注 ProcessRequest() 方法。这是 IIS 在收到客户端请求后调用 ISAPI 过滤器时调用的方法。这可以看作是任何使用 HTTP 处理程序的应用程序的入口点。代码的核心就在这里。

我们首先要做的是确定我们收到了什么类型的请求并采取相应措施。我们将执行以下操作:

  1. GET 方法 - 从数据库读取员工信息
  2. PUT 方法 - 更新数据库
  3. POST 方法 - 插入数据库
  4. DELETE 方法 - 删除数据库

HTTPContext 类具有 RequestResponse 对象。下面的代码使用了它们:

//Handling CRUD
switch (context.Request.HttpMethod)
{
    case "GET":
        //Perform READ Operation
        READ(context);
        break;
    case "POST":
        //Perform CREATE Operation
        CREATE(context);
        break;
           case "PUT":
        //Perform UPDATE Operation
        UPDATE(context);
        break;
    case "DELETE":
        //Perform DELETE Operation
        DELETE(context);
        break;
    default:
        break;
}

READ() 方法

  1. 从 URL 的查询字符串中获取员工代码。
  2. 使用上面讨论的数据访问层轮询数据库以获取该特定员工。
  3. Employee 类序列化为 XML 并写入 Response 对象。
int employeeCode = Convert.ToInt16(context.Request["id"]);
                
emp = dal.GetEmployee(employeeCode);
if (emp==null)               
    context.Response.Write(employeeCode + "No Employee Found");

string serializedEmployee = Serialize(emp);
    context.Response.ContentType = "text/xml";
WriteResponse(serializedEmployee);

CREATE() 方法

  1. 从 POST 请求的消息正文中提取 Employee 类。这是通过使用 Request 类的 BinaryRead() 方法实现的,该方法将消息正文读取为字节。
  2. 将员工信息从 bytes[] 反序列化为 Employee 类。
  3. 使用数据访问层在数据库中执行插入操作。
// Extract the content of the Request and make a employee class
// The message body is posted as bytes. read the bytes
byte[] PostData = context.Request.BinaryRead(context.Request.ContentLength);
//Convert the bytes to string using Encoding class
string str = Encoding.UTF8.GetString(PostData);
// deserialize xml into employee class
Company.Employee emp = Deserialize(PostData);
// Insert data in database
dal.AddEmployee(emp);

UPDATE() 方法

  1. 从 PUT 请求的消息正文中提取 Employee 类。这是通过使用 Request 类的 BinaryRead() 方法实现的,该方法将消息正文读取为字节。
  2. 将员工信息从 bytes[] 反序列化为 Employee 类。
  3. 使用数据访问层在数据库中执行更新操作。
byte[] PUTRequestByte = context.Request.BinaryRead(context.Request.ContentLength);
context.Response.Write(PUTRequestByte);

// Deserialize Employee
Company.Employee emp = Deserialize(PUTRequestByte);
dal.UpdateEmployee(emp);

DELETE() 方法

  1. 从 URL 的查询字符串中获取员工代码。
  2. 在数据库中执行删除操作。
int EmpCode = Convert.ToInt16(context.Request["id"]);
dal.DeleteEmployee(EmpCode);
WriteResponse("Employee Deleted Successfully");

Service 类与 DAL 类关联以处理数据库操作。我将连接字符串存储在项目属性中,并通过以下代码行访问它:

connString = Properties.Settings.Default.ConnectionString;

此外,我将简要解释负责 XML 序列化和反序列化的方法。

Serialize() 方法负责 XML 序列化。它使用 XmlSerializer 类,该类使用 Serialize() 方法将 XML 写入内存流。然后,它使用内存流的 ToArray() 方法以字符串形式返回 XML Employee。请参阅下面的代码:

private String Serialize(Company.Employee emp)
{
    try
    {
        String XmlizedString = null;
        XmlSerializer xs = new XmlSerializer(typeof(Company.Employee));
        //create an instance of the MemoryStream class since we intend to keep the XML string 
        //in memory instead of saving it to a file.
        MemoryStream memoryStream = new MemoryStream();
        //XmlTextWriter - fast, non-cached, forward-only way of generating streams or files 
        //containing XML data
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        //Serialize emp in the xmlTextWriter
        xs.Serialize(xmlTextWriter, emp);
        //Get the BaseStream of the xmlTextWriter in the Memory Stream
        memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
        //Convert to array
        XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
        return XmlizedString;
    }
    catch (Exception ex)
    {
        errHandler.ErrorMessage = ex.Message.ToString();
        throw;
    }
}

Deserialize() 方法负责反序列化。它接受员工信息作为字节数组,使用 XmlSerializer 类对其进行反序列化,并返回 Employee 对象。

private Company.Employee Deserialize(byte[] xmlByteData)
{
    try
    {
        XmlSerializer ds = new XmlSerializer(typeof(Company.Employee));
        MemoryStream memoryStream = new MemoryStream(xmlByteData);
        Company.Employee emp = new Company.Employee();
        emp = (Company.Employee)ds.Deserialize(memoryStream);
        return emp;
    }
    catch (Exception ex)
    {
        errHandler.ErrorMessage = dal.GetException();
        errHandler.ErrorMessage = ex.Message.ToString();
        throw;
    }
}

异常处理

处理和检测错误可能是一个挑战,因为 Web 服务中的所有内容都将在后台进行。没有办法使用断点调试代码。我使用了一个名为 ErrorHandler 的项目库,其中有一个名为 ErrorHandler 的类。

public class ErrorHandler
{
    static StringBuilder errMessage = new StringBuilder();

    static ErrorHandler()
    {
    }
    public string ErrorMessage
    {
        get {return errMessage.ToString();}
        set
        {
            errMessage.AppendLine(value);
        }
    }
}

它有一个公共属性,用于存储错误消息并在被调用时返回。每当发生异常时,错误消息属性就会被设置为异常消息。由于它是一个 StringBuilder,它可以存储各个级别的错误消息。最后,可以在最终级别调用它来获取代码中遇到的所有错误消息。

另一种方法是使用跟踪和侦听器。您可以跟踪代码的流程并将其记录在 XML 或文本文件中。

catch (Exception ex)
{
    errHandler.ErrorMessage = dal.GetException();
    errHandler.ErrorMessage = ex.Message.ToString();
}

第 5 部分 - 部署应用程序

现在代码已经就位,让我们来谈谈部署应用程序。我在 Windows 7 中的 IIS 7.5 中进行了测试。如果您使用其他版本,请相应地进行调整。

  1. 在默认 Web 站点的根目录中创建一个虚拟目录。将其转换为 Web 应用程序。在 IIS 7.5 中,右键单击 inetmgr 中的虚拟目录,然后选择“转换为应用程序”。
  2. 示例:C:\inetpub\wwwroot\RestWebService

  3. 在虚拟目录内创建一个 Bin 文件夹,使其看起来像这样:C:\inetPub\wwwroot\RestWebService\Bin
  4. 编译您的应用程序并将 DLL 放入 Bin 文件夹。您应该有三个 DLL:
    1. Company.dll - Employee
    2. DAL.dll - 数据访问层
    3. RestWebService.dll - REST Web 服务
  5. 在 Web 站点的根目录(即 RestWebService 文件夹)中放置一个 Web.config 文件。
  6. <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.web>
        <httpHandlers>
          <add type="RestWebService.Service, RestWebService" verb="*" path="employee" />
        </httpHandlers>
      </system.web>
        <system.webServer>
            <handlers>
                <add name="employee" path="employee" verb="*" modules="IsapiModule" 
                   scriptProcessor="C:\Windows\Microsoft.NET\Framework\
                                    v2.0.50727\aspnet_isapi.dll" 
                   resourceType="Unspecified" requireAccess="Script" 
                   preCondition="classicMode,runtimeVersionv2.0,bitness32" />
            </handlers>
            <directoryBrowse enabled="false" />
        </system.webServer>
    </configuration>

    httpHandler 部分:

    1. type 表示完全限定的类名 - RestWebService.Service 和程序集名称 RestWebService.dll - 命名空间.类, 程序集。
    2. verb 表示允许在服务上使用的 HTTP 动词。* 表示允许所有动词。
    3. path - 这是我们公开 Employee 对象的地方。路径指定 IIS 将为此应用程序处理的调用。换句话说,任何带有 **employee** 的请求都将定向到我们的 RestWebService.dll

    在 handlers 部分,我们将一个 DLL(aspnet_isapi.dll)映射到执行上述工作。

    也可以通过 inetmgr 完成此操作,如下所示:

    1. 在 inetmgr 中,选择您的目录,然后双击“处理程序映射”。
    2. 点击“添加脚本映射”并执行以下操作:
    3. 您应该已映射 HTTP 处理程序。
  7. 为了测试一切是否正常工作,请在数据库中插入一些数据,然后在 Web 浏览器中键入以下内容:https:///RestWebService/employee?id=3550。如果您有一个员工代码为 3550 的员工,您将看到以下内容:

    注意:有关部署问题,请参阅文章末尾的“参考文献”部分。

第 6 部分 - 测试应用程序

GET 方法可以通过浏览器进行测试,但要测试其他 HTTP 方法,我们需要编写自己的代码。我为此创建了一个名为 TestHarness 的控制台应用程序。

请注意,此应用程序还执行项目中各个部分的测试。我编写了代码来测试数据库操作,以检查我的数据访问层是否正常工作。

下面我将解释 GET、POST、PUT 和 DELETE 方法的测试。

  1. GenerateGetRequest() - 测试 GET 方法。
    1. 使用 HTTPWEbRequest.Create(Url) 创建 HTTPWebRequest 实例。
    2. Method 属性设置为 GET,并使用 GetResponse() 方法接收服务器的响应流。
    3. 将结果打印到控制台以检查结果。
    4. string url = "https:///RestWebService/employee?id=3550";
      HttpWebRequest GETRequest = (HttpWebRequest)WebRequest.Create(url);
      GETRequest.Method = "GET";
      
      Console.WriteLine("Sending GET Request");
      HttpWebResponse GETResponse = (HttpWebResponse)GETRequest.GetResponse();
      Stream GETResponseStream = GETResponse.GetResponseStream();
      StreamReader sr = new StreamReader(GETResponseStream);
      
      Console.WriteLine("Response from Server");
      Console.WriteLine(sr.ReadToEnd());
  2. GeneratePOSTRequest() - 测试 POST 方法。
    1. 创建消息正文。消息正文应包含序列化后的 Employee 类 XML。我正在使用一个名为 GenerateXMLEmployee() 的方法,该方法创建一个包含员工信息的字节流。我使用 XmlTextWriter 在内存流中创建 XML,并从该流返回一个字节数组。
    2. private static byte[] GenerateXMLEmployee(string strFirstName, 
              string strLastName, int intEmpCode, string strDesignation)
      {
          // Create the xml document in a memory stream - Recommended
          MemoryStream mStream = new MemoryStream();
          //XmlTextWriter xmlWriter =
          //         new XmlTextWriter(@"C:\Employee.xml", Encoding.UTF8);
          XmlTextWriter xmlWriter = new XmlTextWriter(mStream, Encoding.UTF8);
          xmlWriter.Formatting = Formatting.Indented;
          xmlWriter.WriteStartDocument();
          xmlWriter.WriteStartElement("Employee");
          xmlWriter.WriteStartElement("FirstName");
          xmlWriter.WriteString(strFirstName);
          xmlWriter.WriteEndElement();
          xmlWriter.WriteStartElement("LastName");
          xmlWriter.WriteString(strLastName);
          xmlWriter.WriteEndElement();
          xmlWriter.WriteStartElement("EmpCode");
          xmlWriter.WriteValue(intEmpCode);
          xmlWriter.WriteEndElement();
          xmlWriter.WriteStartElement("Designation");
          xmlWriter.WriteString(strDesignation);
          xmlWriter.WriteEndElement();
          xmlWriter.WriteEndElement();
          xmlWriter.WriteEndDocument();
          xmlWriter.Flush();
          xmlWriter.Close();
          return mStream.ToArray();
      }
    3. 一旦创建了消息正文(包含员工信息的字节数组),我们就可以以相同的方式创建 POST 请求。唯一的补充是我们必须将数据字节写入请求对象的流中,并获取服务器响应。请参阅下面的代码:
    4. string strURL = "https:///RestWebService/employee";
      byte[] dataByte = 
        GenerateXMLEmployee(strFirstName,strLastName,EmpCode,strDesignation);
      
      HttpWebRequest POSTRequest = (HttpWebRequest)WebRequest.Create(strURL);
      //Method type
      POSTRequest.Method = "POST";
      // Data type - message body coming in xml
      POSTRequest.ContentType = "text/xml";
      POSTRequest.KeepAlive = false;
      POSTRequest.Timeout = 5000;
      //Content length of message body
      POSTRequest.ContentLength = dataByte.Length;
      
      // Get the request stream
      Stream POSTstream = POSTRequest.GetRequestStream();
      // Write the data bytes in the request stream
      POSTstream.Write(dataByte, 0, dataByte.Length);
      
      //Get response from server
      HttpWebResponse POSTResponse = (HttpWebResponse)POSTRequest.GetResponse();
      StreamReader reader = 
        new StreamReader(POSTResponse.GetResponseStream(),Encoding.UTF8) ;
      Console.WriteLine("Response");
      Console.WriteLine(reader.ReadToEnd().ToString());
  3. GeneratePUTRequest() - 测试 PUT 方法。
  4. 这与 POST 请求相同。此处作为 XML 发送的员工信息是一个现有员工,而不是新员工。

  5. GenerateDELETERequest() - 测试 DELETE 方法。
  6. 这与上面解释的 POST 方法相同。

摘要

在本文中,我们学习了如何使用 C# 和 HTTP 处理程序创建 REST Web 服务,并理解了幕后发生的操作。有更简单的方法可以实现相同的功能。Microsoft 在 WCF 中发布了内置模板,可以帮助我们编写 REST Web 服务。这些模板已经配置好了一切,我们只需编写业务逻辑。我们还可以使用断点调试这些模板。缺点是您将不了解幕后发生的事情,因此在需要进行任何修改时将无能为力。此外,尽管它们实现了 REST 的功能,但它们并不完全遵循其将名词暴露给动词的标准。WCF REST Web 服务仍然公开 Service.svc 文件。根据您的项目需求,您可以选择使用哪种方式。请记住 - REST 是一种架构风格,而不是一种指导方针。

参考文献

为了更好地理解上面提到的一些概念,请参考以下链接:

  1. 在 IIS 中部署应用程序时遇到的问题 - https://codeproject.org.cn/KB/ISAPI/Curious-Case-IIS.aspx
  2. HTTP 处理程序 - http://msdn.microsoft.com/en-us/library/bb398986.aspx
  3. REST - https://codeproject.org.cn/KB/architecture/RESTWebServicesPart1.aspx
  4. REST - http://tomayko.com/writings/rest-to-my-wife
© . All rights reserved.