主要内容

本页采用了机器翻译。点击此处可查看英文原文。

在 .NET 客户端中使用协议缓冲区进行异步 RESTful 请求

R2026b

此示例展示如何使用 .NET 客户端 API、MATLAB® Production Server™ 用于 MATLAB 函数执行的 RESTful API 和协议缓冲区 (protobuf) 发出异步 RESTful 请求。该示例提供并解释了一个示例 C# 客户端 MagicAsync.cs,用于评估部署在服务器上的 MATLAB 函数。

要在向服务器发出请求时使用 protobuf,请在客户端代码中将 HTTP Content-Type 请求标头设置为 application/x-google-protobuf。.NET 客户端库中的 MathWorks.MATLAB.ProductionServer.Client.REST 命名空间提供了辅助类,用于内部根据 proto 格式创建 protobuf 消息并返回相应的字节数组。在 HTTP 请求正文中使用此字节数组。.NET 客户端库提供了反序列化 protobuf 响应的方法和类。

当向服务器发送POST Asynchronous Request时,客户端必须在查询参数中将 HTTP 请求 mode 设置为 async。请求状态必须是 READY 或 ERROR 才可以检索请求结果。有关 MATLAB Production Server 上异步请求执行的详细信息,请参阅 异步执行。

要使用 .NET 客户端 API,您必须在 C#工程中添加对 MathWorks.MATLAB.ProductionServer.Client.dll 文件的引用。有关为您的工程准备 Microsoft® Visual Studio® 环境的详细信息,请参阅准备您的 Microsoft Visual Studio 环境。

在本地 MATLAB Production Server 安装中,客户端 API 位于 $MPS_INSTALL/client,其中 $MPS_INSTALL 是 MATLAB Production Server 的安装位置。客户端 API 也可从 MATLAB Production Server 客户端库下载。Java® 客户端 API 也托管在 https://mvnrepository.com/artifact/com.mathworks.prodserver/mps_java_client 的 Maven™ 仓库中。

将 MATLAB 函数部署到服务器

编写一个使用 magic (MATLAB) 函数创建幻方的 MATLAB 函数 mymagic,然后将其部署在服务器上。函数 mymagic 接受单个 int32 输入并以二维 double 数组的形式返回一个幻方。该示例假定服务器实例在 http://localhost:9910 上运行。

有关如何部署的信息,请参阅针对 MATLAB Production Server 创建可部署存档。

function m = mymagic(in)

  m = magic(in);
end

向服务器发起异步请求

在 C# 客户端代码中,使用 POST 异步请求向服务器发出初始请求。有关 MATLAB Production Server 中异步请求执行的详细信息,请参阅异步执行。

  1. 创建包含协议缓冲区消息的 HTTP 请求正文。

    使用 MATLAB Production Server .NET 客户端 API 的 Create(arg1, arg2, arg3) 类中定义的 MATLABParams 方法来构建协议缓冲区消息。Create 方法将部署函数的预期输出参量数量、预期输出类型以及表示部署函数输入的对象数组作为输入。由于部署的 mymagic 函数返回单个二维数组,因此将 arg1 设置为 1,将 arg2 设置为 new List<Type> { typeof(double[,]) }。为 arg3 指定一个整数值,它是 mymagic 函数的输入。

    使用 .NET WebRequest.Create 方法创建 POST 异步请求。有关 .NET WebRequest 类的详细信息,请参阅 Microsoft 文档。

    MATLABParams mlParams = MATLABParams.Create(1, new List<Type> { typeof(double[,]) }, 2);
  2. 将请求发送到服务器。

    向服务器发送 POST 异步请求,其中请求正文由 protobuf 消息 (mlParams) 组成。请求 URL 包括服务器实例的地址 (http://localhost:9910)、部署的存档的名称 (mymagic) 和要评估的 MATLAB 函数的名称 (mymagic)。在查询参数中将 HTTP 请求 mode 设置为 async。将 HTTP Content-Type 请求标头设置为 application/x-google-protobuf,因为 API 返回协议缓冲区消息的字节数组。

    使用 .NET WebRequest.getResponse 方法将请求发送到服务器。有关 .NET WebRequest 类的详细信息,请参阅 Microsoft 文档。

    String mpsBaseUrl = "http://localhost:9910";
    var response = MakeHTTPRequest(mpsBaseUrl + "/mymagic/mymagic?mode=async", "POST", mlParams);
    Console.WriteLine("The HTTP status code of the request is " + response.StatusCode + ".\n\n");

    该示例使用辅助方法 MakeHTTPRequest 将 protobuf 消息发送到服务器。该方法以 HTTP URL、HTTP 方法(GET 或 POST)和 MATLABParams 对象作为输入,并返回服务器响应。

    static HttpWebResponse MakeHTTPRequest(String url, String requestType, MATLABParams mlParams)
    {
        var httpRequest = (HttpWebRequest)WebRequest.Create(url);
        httpRequest.Method = requestType;
        httpRequest.ContentType = "application/x-google-protobuf";
        if (requestType.Equals("POST"))
        {
            mlParams.WriteTo(httpRequest.GetRequestStream());
        }
        return (HttpWebResponse)httpRequest.GetResponse();
    }
  3. 接收并解释服务器响应。

    成功执行 HTTP 请求后,服务器将使用协议缓冲区消息进行响应。使用 MATLABRequestHandle 类中的方法解析协议缓冲区消息,以获取请求的状态、请求的 URL 以及请求的最后修改序列值等详细信息。

    MATLABRequestHandle matlabRequestHandle = MATLABRequestHandle.Create(response.GetResponseStream());
    Console.WriteLine("The response body of the initial POST request contains the following values after deserialization using MATLABRequestHandle class: ");
    Console.WriteLine(matlabRequestHandle.ToString() + ".\n\n");

获取请求的状态信息

  1. 发出请求以获取请求状态信息。

    向 GET State Information RESTful API 发出请求。在请求 URL 中,将查询参数 format 设置为 protobuf,以便服务器以协议缓冲区格式返回输出。只有当请求的状态变为 READY 或 ERROR 后,才能获取异步请求的结果。

  2. 解析响应。

    使用 MATLABRequest 类中定义的方法解析响应以获取请求的状态。

示例代码每秒向 GET State Information API 发出一次请求,以查找请求状态是否更改为 READY_STATE 或 ERROR_STATE。

 MATLABRequest mlRequestStatus;
 do
 {
    var statusRequestResponse = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/info?format=protobuf", "GET", null);
    mlRequestStatus = MATLABRequest.Create(statusRequestResponse.GetResponseStream());
    Console.WriteLine("State: " + mlRequestStatus.State);
    Thread.Sleep(1000);
}while (mlRequestStatus.State < MATLABRequestState.READY_STATE);

在异步模式下,客户端能够向服务器发送多个请求。要获取每个 POST 请求的状态信息,必须向 GET State Information RESTful API 发出相应的请求。

检索请求结果

  1. 发出请求以获取响应。

    当请求状态变为 READY 或 ERROR 后,使用GET Result of Request RESTful API 获取请求结果。在请求 URL 中,将查询参数 format 设置为 protobuf,以便服务器以协议缓冲区格式返回输出。

    response = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/result?format=protobuf", "GET", null);

  2. 解析响应。

    如果请求状态为 READY,则使用 MATLABResult 类中定义的方法来解析响应。要创建 MATLABResult 对象,请使用 Create 方法,并将 MATLABParams mlParams 对象和请求的响应主体作为输入传递给请求 API 的 GET 结果。

    如果部署的 MATLAB 函数执行时出现错误,则对 Result 方法的调用将抛出包含来自 MATLAB 的错误消息的 MATLABException。

    如果请求状态为 ERROR,则使用 HTTPErrorInfo 类而不是 MATLABResult 类来解析响应。使用 HTTPErrorInfo 类中定义的方法获取有关错误的信息。

    if (mlRequestStatus.State == MATLABRequestState.READY_STATE)
    {
        MATLABResult mlResult;
        try
        {
             mlResult = MATLABResult.Create(mlParams, response.GetResponseStream());
             double[,] result = mlResult.Result<double[,]>();
             Console.WriteLine("Printing the 2-D array...\n");
             PrintMagic(result);
        }
        catch (MATLABException e)
        {
            Console.WriteLine(e.Message);
        }
    }
    else if (mlRequestStatus.State == MATLABRequestState.ERROR_STATE)
    {    
        HTTPErrorInfo httpErrorInfo = HTTPErrorInfo.Create(response.GetResponseStream());
        Console.WriteLine("Error:");
        Console.WriteLine(httpErrorInfo.HttpErrorCode);
        Console.WriteLine(httpErrorInfo.HttpErrorMessage);
    }
  3. 显示结果。

    该示例使用辅助方法 PrintMagic,该方法将从请求 API 调用的 GET 结果的响应主体中解析的结果作为输入,并打印相应的二维幻方数组。

    static void PrintMagic(double[,] magic)
    {
        int numDims = magic.Rank;
        int[] dims = new int[numDims];
    
        for (int i = 0; i < numDims; i++)
        {
            dims[i] = magic.GetLength(i);
        }
        
        for (int j = 0; j < dims[0]; j++)
        {    
            for (int k = 0; k < dims[1]; k++)
            {
                Console.Write(magic[j, k]);
                if (k < dims[1] - 1)
                {
                    Console.Write(",");
                }
            }
            Console.WriteLine();
        }
    }

运行 C# 应用程序将生成以下输出。

Printing the 2-D array...

1,3
4,2

以下是 MagicAsync.cs C# 客户端的示例代码。

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.IO;
using MathWorks.MATLAB.ProductionServer.Client;
using MathWorks.MATLAB.ProductionServer.Client.REST;
using System.Threading;

namespace MagicSquareExample
{
    class MagicAsync
    {
        static void Main(string[] args)
        {
            //Async request using RESTful API and protobuf

            //URL of the MATLAB Production Server
            String mpsBaseUrl = "http://localhost:9910";
            MATLABParams mlParams = MATLABParams.Create(1, new List<Type> { typeof(double[,]) }, 2);

            Console.WriteLine("Sending initial HTTP POST request to the URL " + mpsBaseUrl + "/mymagic/mymagic?mode=async.");
            var response = MakeHTTPRequest(mpsBaseUrl + "/mymagic/mymagic?mode=async", "POST", mlParams);
            Console.WriteLine("The HTTP status code of the request is " + response.StatusCode + ".\n\n");

            // Parse the response body using the MATLABRequestHandle class
            // to retrieve the request URL, last modified sequence value and state of the request.
            MATLABRequestHandle matlabRequestHandle = MATLABRequestHandle.Create(response.GetResponseStream());
            Console.WriteLine("The response body of initial POST request contains the following values after deserialzation using MATLABRequestHandle class: ");
            Console.WriteLine(matlabRequestHandle.ToString() + ".\n\n");

            Console.WriteLine("Send GET status request every 1 second to look for state change of the request to either READY_STATE or ERROR_STATE.");
            MATLABRequest mlRequestStatus;
            do
            {
                var statusRequestResponse = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/info?format=protobuf", "GET", null);
                mlRequestStatus = MATLABRequest.Create(statusRequestResponse.GetResponseStream());
                Console.WriteLine("State: " + mlRequestStatus.State);
                Thread.Sleep(1000);
            } while (mlRequestStatus.State < MATLABRequestState.READY_STATE);
            //-----------
            // Once the state changes to READY_STATE or ERROR_STATE, make a GET call to /result. If the state is ERROR_STATE, 
            //use HTTPErrorInfo class, else use MATLABResult class to parse the response body.
            Console.Write("\n\n");
            Console.WriteLine("Now send GET request to fetch the result using the URL " + mpsBaseUrl + matlabRequestHandle.RequestURL + "/result?format=protobuf");
            response = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/result?format=protobuf", "GET", null);

            if (mlRequestStatus.State == MATLABRequestState.READY_STATE)
            {
                // Parse the response body with the help of MATLABResult class. The Create function
                // takes as input the MATLABParams object that was initially created.
                // If there is any error in MATLAB, call to Result<>() throws MATLABException which contains the error message
                // displayed in MATLAB.

                MATLABResult mlResult;
                try
                {
                    mlResult = MATLABResult.Create(mlParams, response.GetResponseStream());
                    double[,] result = mlResult.Result<double[,]>();
                    Console.WriteLine("Printing the 2-D array...\n");
                    PrintMagic(result);
                }
                catch (MATLABException e)
                {
                    Console.WriteLine(e.Message);
                }
            }
            else if (mlRequestStatus.State == MATLABRequestState.ERROR_STATE)
            {
                HTTPErrorInfo httpErrorInfo = HTTPErrorInfo.Create(response.GetResponseStream());
                Console.WriteLine("Error:");
                Console.WriteLine(httpErrorInfo.HttpErrorCode);
                Console.WriteLine(httpErrorInfo.HttpErrorMessage);
            }
            Console.ReadKey();
            //------------

        }

        static void PrintMagic(double[,] magic)
        {
            int numDims = magic.Rank;
            int[] dims = new int[numDims];

            for (int i = 0; i < numDims; i++)
            {
                dims[i] = magic.GetLength(i);
            }

            for (int j = 0; j < dims[0]; j++)
            {
                for (int k = 0; k < dims[1]; k++)
                {
                    Console.Write(magic[j, k]);
                    if (k < dims[1] - 1)
                    {
                        Console.Write(",");
                    }
                }
                Console.WriteLine();
            }
        }

        //This function takes URL and HTTP request type and sends the HTTP request
        static HttpWebResponse MakeHTTPRequest(String url, String requestType, MATLABParams mlParams)
        {
            var httpRequest = (HttpWebRequest)WebRequest.Create(url);
            httpRequest.Method = requestType;
            httpRequest.ContentType = "application/x-google-protobuf";
            if (requestType.Equals("POST"))
            {
                mlParams.WriteTo(httpRequest.GetRequestStream());

            }
            return (HttpWebResponse)httpRequest.GetResponse();
        }

    }
}

另请参阅

| |

主题