2

現在、.NET Rally コードを SOAP から REST .NET API に移植中です。これまでのところ、Rally ワークスペースでワーク プロダクトのカスタム フィールドが変更されるたびに WSDL を壊す必要がないため、REST API の方が高速で使いやすいようです。

ただし、添付ファイルをアップロードする機能を複製しようとしているときに、1 つの問題があります。この投稿で概説されている手順と非常によく似た手順に従っています。

Rally SOAP API - 階層要件に添付ファイルを追加する方法

これにより、イメージが System.Drawing.Image に読み込まれます。ImageToByteArray 関数を使用して、イメージをバイト配列に変換し、最初に作成された AttachmentContent に割り当てます。

次に、Attachment が作成され、AttachmentContent と HierarchicalRequirement の両方に接続されます。

すべての作成イベントはうまく機能します。コンテンツ オブジェクトが正常に作成されます。次に、「Image.png」という新しい添付ファイルが作成され、ストーリーにリンクされます。しかし、結果の添付ファイルを Rally からダウンロードすると、Image.png のバイト数は 0 バイトです。さまざまな画像、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 に答える 1

4

この問題もしばらく頭を悩ませていましたが、最終的には約 1 週間前に解決しました。

2 つの観察:

  1. Rally の SOAP API はバックグラウンドでバイト配列を Base64 文字列にシリアル化しますが、REST はこの手順を実行せず、AttachmentContent オブジェクトの Content 属性として Base64 形式の文字列が渡されることを期待します。
  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 = "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;
            }
        }
    }
}
于 2012-07-09T15:55:08.373 に答える