2012-07-09 131 views
2

我們正在將我們的.NET Rally代碼從SOAP移植到REST .NET API。到目前爲止,REST API似乎更快,更易於使用,因爲每次在Rally Workspace中工作產品自定義字段發生更改時都不會有WSDL中斷。如何使用Rally REST .NET向用戶故事添加附件

雖然我們嘗試複製上傳附件的功能,但我遇到了一件麻煩事。我們一直遵循一個非常類似的過程作爲一個在此公告概述:

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

從而使圖像讀入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; 
    } 
} 

回答

4

這個問題也讓我感到困惑了一段時間 - 最後在一週前把它整理出來了。

兩個意見:

  1. 雖然拉力賽的SOAP API將字節數組序列化到幕後Base64編碼字符串,REST沒有做到這一步了,你並期待一個Base64格式的字符串傳遞作爲AttachmentContent對象的Content屬性。
  2. 如您的示例中所示的System.Drawing.Image.Length不會提供拉力賽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; 
      } 
     } 
    } 
} 
+0

謝謝!這一直在擾亂我! – user1373451 2012-07-10 13:20:51

相關問題