如何使用Rally REST .NET将附件添加到用户素材

时间:2012-07-09 03:04:29

标签: c# .net rest rally

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

我在尝试复制上传附件的能力时遇到了一件事情。我们遵循与此帖中概述的程序非常相似的程序:

Rally SOAP API - How do I add an attachment to a Hierarchical Requirement

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

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

所有创作活动都很有效。内容对象被创建得很好。然后创建名为“Image.png”的新附件并将其链接到Story。但是当我从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 个答案:

答案 0 :(得分:4)

这个问题也让我困惑了一段时间 - 最终在大约一周前将其整理出来。

两个观察结果:

  1. 虽然Rally的SOAP API会将字节数组序列化为幕后的Base64字符串,但REST不会为您执行此步骤,并且期望将Base64格式的String作为AttachmentContent对象的Content属性传递。 / LI>
  2. 如示例中所示的System.Drawing.Image.Length将无法提供Rally的WSAPI所期望的正确长度。转换回常规字符串后,需要传递Base64格式的字符串的长度。这也与字节数组的长度相同。
  3. 我要包含一个代码示例来说明:

    // 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 = "user@company.com";
                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;
                }
            }
        }
    }