如何使用 Rally REST .NET 将附件添加到用户故事

2023-12-10

我们正在将 .NET Rally 代码从 SOAP 移植到 REST .NET API。到目前为止,REST API 似乎更快并且更易于使用,因为每次工作产品自定义字段在 Rally 工作区中发生更改时都不会破坏 WSDL。

不过,当我们尝试复制上传附件的功能时,我遇到了一件事。我们正在遵循与这篇文章中概述的非常相似的程序:

Rally SOAP API - 如何向分层需求添加附件

由此图像被读入 System.Drawing.Image。我们使用 ImageToByteArray 函数将图像转换为字节数组,然后将其分配给首先创建的 AttachmentContent。

然后,创建附件,并将其连接到 AttachmentContent 和 HierarchicalRequirement。

所有的创作活动都进展顺利。内容对象创建得很好。然后,将创建名为“Image.png”的新附件并将其链接到故事。但是当我从 Rally 下载生成的附件时,Image.png 的字节为零!我已经用不同的图像、JPEG、PNG 等进行了尝试,结果都相同。

下面是显示我们流程的代码摘录。我是否缺少一些明显的东西?提前致谢。

    // .... Read content into a System.Drawing.Image called imageObject ....

    // Convert Image to byte array
    byte[] imageBytes = ImageToByteArray(imageObject, System.Drawing.Imaging.ImageFormat.Png);
    var imageLength = imageBytes.Length;

    // AttachmentContent
    DynamicJsonObject attachmentContent = new DynamicJsonObject();
    attachmentContent["Content"] = imageBytes ;

    CreateResult cr = restApi.Create("AttachmentContent", myAttachmentContent);
    String contentRef = cr.Reference;
    Console.WriteLine("Created: " + contentRef);

    // Set up attachment
    DynamicJsonObject newAttachment = new DynamicJsonObject();
    newAttachment["Artifact"] = story;
    newAttachment["Content"] = attachmentContent;
    newAttachment["Name"] = "Image.png";
    newAttachment["ContentType"] = "image/png";
    newAttachment["Size"] = imageLength;
    newAttachment["User"] = user;


    // Create the attachment in Rally
    cr = restApi.Create("Attachment", newAttachment);

    String attachRef = cr.Reference;
    Console.WriteLine("Created: " + attachRef);

}

public static byte[] ImageToByteArray(Image image, System.Drawing.Imaging.ImageFormat format)
{
    using (MemoryStream ms = new MemoryStream())
    {
        image.Save(ms, format);

        // Convert Image to byte[]                
        byte[] imageBytes = ms.ToArray();
        return imageBytes;
    }
}

这个问题也让我困惑了一段时间——大约一周前终于解决了。

两个观察结果:

  1. 虽然 Rally 的 SOAP API 会在后台将字节数组序列化为 Base64 字符串,但 REST 不会为您执行此步骤,并且会期望将 Base64 格式的字符串作为 AttachmentContent 对象的 Content 属性传递。
  2. 示例中所示的 System.Drawing.Image.Length 不会提供 Rally 的 WSAPI 期望的正确长度。您需要在转换回常规字符串后传递 Base64 格式字符串的长度。这也与字节数组的长度相同。

我提供了一个代码示例来说明:

// System Libraries
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using System.Web;

// Rally REST API Libraries
using Rally.RestApi;
using Rally.RestApi.Response;

namespace RestExample_CreateAttachment
{
    class Program
    {
        static void Main(string[] args)
        {
            // Set user parameters
            String userName = "[email protected]";
            String userPassword = "password";

            // Set Rally parameters
            String rallyURL = "https://rally1.rallydev.com";
            String rallyWSAPIVersion = "1.36";

            //Initialize the REST API
            RallyRestApi restApi;
            restApi = new RallyRestApi(userName,
                                       userPassword,
                                       rallyURL,
                                       rallyWSAPIVersion);

            // Create Request for User
            Request userRequest = new Request("user");
            userRequest.Fetch = new List<string>()
                {
                    "UserName",
                    "Subscription",
                    "DisplayName",
                };

            // Add a Query to the Request
            userRequest.Query = new Query("UserName",Query.Operator.Equals,userName);

            // Query Rally
            QueryResult queryUserResults = restApi.Query(userRequest);

            // Grab resulting User object and Ref
            DynamicJsonObject myUser = new DynamicJsonObject();
            myUser = queryUserResults.Results.First();
            String myUserRef = myUser["_ref"];

            //Set our Workspace and Project scopings
            String workspaceRef = "/workspace/12345678910";
            String projectRef = "/project/12345678911";
            bool projectScopingUp = false;
            bool projectScopingDown = true;

            // Find User Story that we want to add attachment to

            // Tee up Story Request
            Request storyRequest = new Request("hierarchicalrequirement");
            storyRequest.Workspace = workspaceRef;
            storyRequest.Project = projectRef;
            storyRequest.ProjectScopeDown = projectScopingDown;
            storyRequest.ProjectScopeUp = projectScopingUp;

            // Fields to Fetch
            storyRequest.Fetch = new List<string>()
                {
                    "Name",
                    "FormattedID"
                };

            // Add a query
            storyRequest.Query = new Query("FormattedID", Query.Operator.Equals, "US43");

            // Query Rally for the Story
            QueryResult queryResult = restApi.Query(storyRequest);

            // Pull reference off of Story fetch
            var storyObject = queryResult.Results.First();
            String storyReference = storyObject["_ref"];

            // Read In Image Content
            String imageFilePath = "C:\\Users\\username\\";
            String imageFileName = "image1.png";
            String fullImageFile = imageFilePath + imageFileName;
            Image myImage = Image.FromFile(fullImageFile);

            // Get length from Image.Length attribute - don't use this in REST though
            // REST expects the length of the image in number of bytes as converted to a byte array
            var imageFileLength = new FileInfo(fullImageFile).Length;
            Console.WriteLine("Image File Length from System.Drawing.Image: " + imageFileLength);

            // Convert Image to Base64 format
            string imageBase64String = ImageToBase64(myImage, System.Drawing.Imaging.ImageFormat.Png);           

            // Length calculated from Base64String converted back
            var imageNumberBytes = Convert.FromBase64String(imageBase64String).Length;

            // This differs from just the Length of the Base 64 String!
            Console.WriteLine("Image File Length from Convert.FromBase64String: " + imageNumberBytes);

            // DynamicJSONObject for AttachmentContent
            DynamicJsonObject myAttachmentContent = new DynamicJsonObject();
            myAttachmentContent["Content"] = imageBase64String;

            try
            {
                CreateResult myAttachmentContentCreateResult = restApi.Create("AttachmentContent", myAttachmentContent);
                String myAttachmentContentRef = myAttachmentContentCreateResult.Reference;
                Console.WriteLine("Created: " + myAttachmentContentRef);

                // DynamicJSONObject for Attachment Container
                DynamicJsonObject myAttachment = new DynamicJsonObject();
                myAttachment["Artifact"] = storyReference;
                myAttachment["Content"] = myAttachmentContentRef;
                myAttachment["Name"] = "AttachmentFromREST.png";
                myAttachment["Description"] = "Attachment Desc";
                myAttachment["ContentType"] = "image/png";
                myAttachment["Size"] = imageNumberBytes;
                myAttachment["User"] = myUserRef;

                CreateResult myAttachmentCreateResult = restApi.Create("Attachment", myAttachment);

                List<string> createErrors = myAttachmentContentCreateResult.Errors;
                for (int i = 0; i < createErrors.Count; i++)
                {
                    Console.WriteLine(createErrors[i]);
                }

                String myAttachmentRef = myAttachmentCreateResult.Reference;
                Console.WriteLine("Created: " + myAttachmentRef);

            }
            catch (Exception e)
            {
                Console.WriteLine("Unhandled exception occurred: " + e.StackTrace);
                Console.WriteLine(e.Message);
            }
        }

        // Converts image to Base 64 Encoded string
        public static string ImageToBase64(Image image, System.Drawing.Imaging.ImageFormat format)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                image.Save(ms, format);
                // Convert Image to byte[]                
                byte[] imageBytes = ms.ToArray();

                // Convert byte[] to Base64 String
                string base64String = Convert.ToBase64String(imageBytes);

                return base64String;
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Rally REST .NET 将附件添加到用户故事 的相关文章

随机推荐

  • 如何在 Windows 上仅在批处理文件中设置一次 PATH 环境变量?

    我有一个设置用户路径的批处理文件 并作为 Visual Studio IDE 构建步骤的一部分运行 ECHO OFF ECHO PATH set COMSPEC VCINSTALLDIR vcvarsall bat amd64 setx P
  • pyclipper 安装错误:“tp_print 不是 _typeobject 的成员”

    我正在尝试安装 pyclipper 以与 nototools 一起使用 https github com googlefonts nototools但我无法安装 pyclipper 我认为 Visual Studio 构建工具有一些东西 C
  • NSMutableArray-removeObject 结果删除对象和 nil 元素

    首先 我是 Objective C 的新手 我的班级 Song 有一对属性 在我的主类中 我有一个变量 allSongs 它是一个 NSMutableArray 在这个数组中我添加了所有歌曲对象 我的问题出现在尝试调用 self allSo
  • 使用委托、操作和队列

    我正在使用AWS SDK用于 iOS 将文件上传到本地硬盘到 Amazon S3 存储以及从本地硬盘下载文件 我有能力完成这项工作 但我无法让 S3 委托做出正确响应 以便在操作完成或导致错误时提醒我 我有一系列要上传的文件 对于每个文件
  • 在 R (ggplot) 中注释公式(使用 bqoute 或替代)给出错误

    我想添加一个包含变量的公式作为我的 ggplot 上的注释 regline1 lt 0 00 slope1 lt 1 00 dat lt as data frame c 0 1 dat 2 lt c 0 1 names dat lt c f
  • 如何将 /Home 301 重定向到 root?

    这是我在 Global asax 中删除 Home 的路线 routes MapRoute Root action id new controller Home action Index id UrlParameter Optional 好
  • 如何通过降低特征维数来改进LBP算子

    我在用LBP用MATLAB提取特征但精度太低 如何减少LBP中的特征箱 非常感谢 Use the pcares函数来做到这一点 pcares代表主成分分析残差 residuals reconstructed pcares X ndim re
  • 无法使用 Bottomnavigationview 正确加载片段

    我已经遵循了下面的教程 但我一生都无法让它从收藏夹片段 底部导航视图上的中间图标 开始加载 我已经尝试了一切并到处寻找 我的应用程序将始终加载最喜欢的文本 但底部导航视图将始终突出显示主页图标 直到我选择一个图标 如何解决此问题 让应用程序
  • 对一组值进行排序

    我有这样的价值观 x set 0 000000000 0 009518000 10 277200999 0 030810999 0 018384000 4 918560000 y set 4 918859000 0 060758000 4
  • 如何使用 PHP 将 mysql 转换为 sqlite3

    我在 mysql 服务器上有一个数据库 我想将其转换为 sqlite3 数据库without使用 shell 或 perl 脚本 我需要一些使用 PHP 转换相同内容的帮助 任何帮助 将不胜感激 仅使用 PHP 会相当麻烦 您必须从 mys
  • 将带有位置、颜色等的 networkx 图写入 gexf

    我使用 networkx 构建了一个图表 并使用 spring 布局函数生成了一个漂亮的图 不幸的是 这没有传输到 gexf 文件 我认为networkx工具的重点是能够编写可读的图形文件 所以如果python中有一个简单的解决方案 我会犹
  • 无法在 CentOS 7 上安装 mpi4py

    我有 CentOS 7 并且已经安装了 mpicc 它可以在 C 语言中为 openmpi 工作和编译 我也有 python 2 7 5 并且刚刚安装了 pip 我正在运行此命令并收到以下错误 sudo pip install mpi4py
  • RestKit 核心数据 NSError dealloc 崩溃

    试图找出我在生产版本中看到的问题的根源 并最终能够在测试时重现它 使用 RestKit v0 23 1 当使用以下代码 插入仪器时 执行 RKManagedObjectRequestOperation 时 我收到 一条 Objective
  • 如何用C语言解析HTTP响应?

    我正在编写一个小项目 它使用 HTTP 1 1 GET 和 POST 与一组服务器进行交互 服务器在一些标题行后给了我响应 所以我想使用strtok 函数使用 n作为分隔符 但每当我尝试这样做时就会发生崩溃 有没有简单的方法可以用 C 语言
  • Android:无法在防火墙后面发出 httprequest

    当没有防火墙时 标准 getUrlContent 可以很好地工作 但当我尝试在防火墙后面执行此操作时 我遇到了例外 我尝试在 AVD 管理器中设置 http 代理服务器 但没有成功 知道如何正确设置它吗 顺便说一句 来自 android 文
  • 浮动比较给出不同的结果

    看下面两个代码 告诉我答案差异很大的原因 include
  • 将 cumsum 应用于二元向量

    我有一个简单的二元向量a我尝试将其转换为向量b使用 R 函数cumsum 然而 cumsum不完全返回向量b 这是一个例子 a lt c 1 0 0 0 1 1 1 1 0 0 1 0 0 0 1 1 b lt c 1 2 2 2 3 4
  • 在 Asp.net MVC 网站中生成 Excel XML 文档

    我有一个 ASP Net MVC 站点 可以生成 Microsoft Excel 2003 XML 格式的电子表格 电子表格看起来不错 控制器和视图都可以工作 但文件无法在 Excel 中打开 它在浏览器中打开 因为它是 XML 文档 我尝
  • 我在 Android studio 中找不到“图像资源”选项

    我开始使用 Flutter UI 工具包在 Android Studio 中学习应用程序开发 一切看起来都很好 但是当我想创建一个新图像资源要编辑我的应用程序的图标 我找不到它 当我右键单击安卓 应用程序 src main res文件夹 它
  • 如何使用 Rally REST .NET 将附件添加到用户故事

    我们正在将 NET Rally 代码从 SOAP 移植到 REST NET API 到目前为止 REST API 似乎更快并且更易于使用 因为每次工作产品自定义字段在 Rally 工作区中发生更改时都不会破坏 WSDL 不过 当我们尝试复制