Download Image Field - How to get full Image from SDK? #218
-
Hi there, I use "OrganizationServiceContext" to do a Field Select with linq. The documentation is clear, only on the rest API. How can I, via the SDK, make this call? Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 14 comments 1 reply
-
The docs you linked have the SDK Call references as well. Image files are treated as "Files" That said, Here is the actual sample that was written to demonstrate this, note that this sample encompasses the various types of file download that can occur for activities, notes and general-purpose files. Thus, the initiation leg could be simplified substantially for your use case. Also, this sample writes to a file on disk, you could easily modify it to return the byte array you need or form the Image type in the response. Note: samples: public static void Download(Entity e, string downloadLocation, string fileAttributeName = null)
{
// Initialize download
InitializeFileDownload(e, fileAttributeName, out string downloadToken, out long fileSizeDownload, out string downloadFileName);
// Download
DownloadFile(e, downloadToken, fileSizeDownload, downloadLocation, downloadFileName);
}
private static void InitializeFileDownload(Entity e, string fileAttributeName, out string token, out long fileSize, out string downloadFileName)
{
string requestName = null;
OrganizationRequest initializeDownloadRequest = null;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
requestName = "InitializeAttachmentBlocksDownload";
initializeDownloadRequest = new InitializeAttachmentBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else if (e.Attributes.Contains("annotationid"))
{
requestName = "InitializeAnnotationBlocksDownload";
initializeDownloadRequest = new InitializeAnnotationBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else
{
requestName = "InitializeFileBlocksDownload";
initializeDownloadRequest = new InitializeFileBlocksDownloadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName
};
}
Console.WriteLine("Calling {0} ", requestName);
var resp3 = cli.Execute(initializeDownloadRequest);
token = (string)resp3.Results["FileContinuationToken"];
Console.WriteLine("Download token: " + token);
if (string.Equals(requestName, "InitializeFileBlocksDownload"))
{
fileSize = (long)resp3.Results["FileSizeInBytes"];
}
else
{
fileSize = (int)resp3.Results["FileSizeInBytes"];
}
downloadFileName = (string)resp3.Results["FileName"];
}
private static void DownloadFile(Entity e, string downloadToken, long fileSizeDownload, string downloadLocation, string downloadFileName)
{
var requestName = "DownloadBlock";
long offset = 0;
long chunkSizeDownload = 4 * 1024 * 1024; // 4 MB
Console.WriteLine($"File download size: {fileSizeDownload} Bytes. Chunk size: {chunkSizeDownload} MB", ConsoleColor.Cyan);
int chunksCountDownload = (int)(fileSizeDownload / (float)chunkSizeDownload) + 1;
int chunkNumberDownload = 0;
using (FileStream outputFile = new FileStream(downloadLocation + "//" + downloadFileName, FileMode.OpenOrCreate, FileAccess.Write))
{
Console.WriteLine("Calling {0} with chunks for: {1}", requestName, downloadFileName);
List<Task> downloadTasks = new List<Task>();
int counter = 0;
byte[] emptyBytes = new byte[fileSizeDownload];
while (fileSizeDownload > 0)
{
chunkNumberDownload++;
Console.WriteLine("Downloading chunk {0}/{1} from file {2}", chunkNumberDownload, chunksCountDownload, downloadFileName);
if (fileSizeDownload < chunkSizeDownload)
{
chunkSizeDownload = (int)fileSizeDownload;
}
var downloadRequest = new DownloadBlockRequest
{
FileContinuationToken = downloadToken,
Offset = offset,
BlockLength = chunkSizeDownload
};
downloadTasks.Add(Task.Factory.StartNew((object data) =>
{
var data1 = (dynamic)data;
var c = Convert.ToInt32(data1.Item2);
var fileDataOffset = Convert.ToInt32(data1.Item1);
var response3 = cli.Execute(downloadRequest);
var result = (byte[])response3.Results["Data"];
Console.WriteLine($"Counter:{c}; Offset: {fileDataOffset}; Length: {result.Length}", ConsoleColor.Cyan);
Buffer.BlockCopy(result, 0, emptyBytes, fileDataOffset, result.Length);
}, new Tuple<long, int>(offset, counter)));
offset += chunkSizeDownload;
fileSizeDownload -= chunkSizeDownload;
counter++;
}
Task.Run(async () =>
{
await Task.WhenAll(downloadTasks.ToArray()).ConfigureAwait(false);
}).GetAwaiter().GetResult();
outputFile.Write(emptyBytes, 0, emptyBytes.Length);
outputFile.Flush();
Console.WriteLine("Download complete");
}
} To invoke it for an image file, you would do this: Entity ent = new Entity("new_somerecordwithimage");
ent.Id = Guid.Parse("RecordGUID");
Download(ent, fileAttributeName: "ImageAttributeName", downloadLocation: "FileNameAndLocation"); Let me know if what it is doing does not make sense. |
Beta Was this translation helpful? Give feedback.
-
I have this field definitions, (image field, not File Field) /// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("ant_planimetryimage")]
public byte[] ant_PlanimetryImage
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<byte[]>("ant_planimetryimage");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("ant_PlanimetryImage");
this.SetAttributeValue("ant_planimetryimage", value);
this.OnPropertyChanged("ant_PlanimetryImage");
}
}
/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("ant_planimetryimage_timestamp")]
public System.Nullable<long> ant_PlanimetryImage_Timestamp
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<long>>("ant_planimetryimage_timestamp");
}
}
/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("ant_planimetryimage_url")]
public string ant_PlanimetryImage_URL
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<string>("ant_planimetryimage_url");
}
}
/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("ant_planimetryimageid")]
public System.Nullable<System.Guid> ant_PlanimetryImageId
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<System.Guid>>("ant_planimetryimageid");
}
}
/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("ant_startvaliditydate")]
public System.Nullable<System.DateTime> ant_StartValidityDate
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<System.DateTime>>("ant_startvaliditydate");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("ant_StartValidityDate");
this.SetAttributeValue("ant_startvaliditydate", value);
this.OnPropertyChanged("ant_StartValidityDate");
}
}
/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("cr129_imagebase64")]
public string cr129_ImageBase64
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<string>("cr129_imagebase64");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("cr129_ImageBase64");
this.SetAttributeValue("cr129_imagebase64", value);
this.OnPropertyChanged("cr129_ImageBase64");
}
} Exception details: |
Beta Was this translation helpful? Give feedback.
-
The code should be falling though to this case: else
{
requestName = "InitializeFileBlocksDownload";
initializeDownloadRequest = new InitializeFileBlocksDownloadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName
};
} where the FileAttributeName is the name of the Image Attribute. ( ant_planimetryimage ) based on my read... though a few of them will be virtual attributes. You want the one that is tagged as "Image" in the meteadata. |
Beta Was this translation helpful? Give feedback.
-
Yes, it's right.
|
Beta Was this translation helpful? Give feedback.
-
OnPrem or OnLine? and if OnPrem, are you using CMK for security? |
Beta Was this translation helpful? Give feedback.
-
Online. |
Beta Was this translation helpful? Give feedback.
-
Are you using CMK? ( Customer Managed Keys? ) |
Beta Was this translation helpful? Give feedback.
-
Sorry, I connect to wrong environment. public class DownloadImages
{
private static CrmContext cli;
public DownloadImages(CrmContext db)
{
cli = db;
}
public async Task<byte[]> DownloadAsync(Entity e, string fileAttributeName = null)
{
// Initialize download
InitializeFileDownload(e, fileAttributeName, out string downloadToken, out long fileSizeDownload, out string downloadFileName);
// Download
return await DownloadFileAsync(downloadToken, fileSizeDownload, downloadFileName);
}
private void InitializeFileDownload(Entity e, string fileAttributeName, out string token, out long fileSize, out string downloadFileName)
{
string requestName;
OrganizationRequest initializeDownloadRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
requestName = "InitializeAttachmentBlocksDownload";
initializeDownloadRequest = new InitializeAttachmentBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else if (e.Attributes.Contains("annotationid"))
{
requestName = "InitializeAnnotationBlocksDownload";
initializeDownloadRequest = new InitializeAnnotationBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else
{
requestName = "InitializeFileBlocksDownload";
initializeDownloadRequest = new InitializeFileBlocksDownloadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName
};
}
var resp3 = cli.Execute(initializeDownloadRequest);
token = (string)resp3.Results["FileContinuationToken"];
fileSize = string.Equals(requestName, "InitializeFileBlocksDownload") ? (long)resp3.Results["FileSizeInBytes"] : (int)resp3.Results["FileSizeInBytes"];
downloadFileName = (string)resp3.Results["FileName"];
}
private async Task<byte[]> DownloadFileAsync(string downloadToken, long fileSizeDownload, string downloadFileName)
{
long offset = 0;
long chunkSizeDownload = 4 * 1024 * 1024; // 4 MB
int chunksCountDownload = (int)(fileSizeDownload / (float)chunkSizeDownload) + 1;
int chunkNumberDownload = 0;
using (MemoryStream outputFile = new MemoryStream())
{
List<Task> downloadTasks = new List<Task>();
int counter = 0;
byte[] emptyBytes = new byte[fileSizeDownload];
while (fileSizeDownload > 0)
{
chunkNumberDownload++;
if (fileSizeDownload < chunkSizeDownload)
{
chunkSizeDownload = (int)fileSizeDownload;
}
var downloadRequest = new DownloadBlockRequest
{
FileContinuationToken = downloadToken,
Offset = offset,
BlockLength = chunkSizeDownload
};
downloadTasks.Add(DownloadChunk(Convert.ToInt32(offset), downloadRequest));
offset += chunkSizeDownload;
fileSizeDownload -= chunkSizeDownload;
counter++;
}
await Task.WhenAll(downloadTasks.ToArray());
await outputFile.WriteAsync(emptyBytes, 0, emptyBytes.Length);
outputFile.Flush();
return outputFile.ToArray();
async Task DownloadChunk(int fileDataOffset, DownloadBlockRequest downloadRequest)
{
var response3 = cli.Execute(downloadRequest);
var result = (byte[])response3.Results["Data"];
Buffer.BlockCopy(result, 0, emptyBytes, fileDataOffset, result.Length);
await Task.CompletedTask;
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Great ! :) was just retesting this myself to make sure things didn't change. |
Beta Was this translation helpful? Give feedback.
-
I refactor my code: public async Task<byte[]> DownloadImageAsync(Entity e, string fileAttributeName = null)
{
InitializeFileDownload(e, fileAttributeName, out string downloadToken, out long fileSizeDownload, out string downloadFileName);
if (fileSizeDownload == 0 && string.IsNullOrEmpty(downloadFileName))
return null;
return await DownloadFileAsync(downloadToken, fileSizeDownload);
}
private void InitializeFileDownload(Entity e, string fileAttributeName, out string token, out long fileSize, out string downloadFileName)
{
OrganizationRequest initializeDownloadRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
initializeDownloadRequest = new InitializeAttachmentBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else if (e.Attributes.Contains("annotationid"))
{
initializeDownloadRequest = new InitializeAnnotationBlocksDownloadRequest
{
Target = e.ToEntityReference()
};
}
else
{
initializeDownloadRequest = new InitializeFileBlocksDownloadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName
};
}
fileSize = 0;
downloadFileName = string.Empty;
token = string.Empty;
try
{
var initializeDownloadResponse = Execute(initializeDownloadRequest);
if (initializeDownloadResponse.Results.TryGetValue<string>("FileContinuationToken", out token))
{
initializeDownloadResponse.Results.TryGetValue<long>("FileSizeInBytes", out fileSize);
initializeDownloadResponse.Results.TryGetValue<string>("FileName", out downloadFileName);
}
}
catch (System.Exception)
{
}
}
private async Task<byte[]> DownloadFileAsync(string downloadToken, long fileSizeDownload)
{
long offset = 0;
long chunkSizeDownload = 4 * 1024 * 1024; // 4 MB
int chunksCountDownload = (int)(fileSizeDownload / (float)chunkSizeDownload) + 1;
int chunkNumberDownload = 0;
using (MemoryStream outputFile = new MemoryStream())
{
List<Task> downloadTasks = new List<Task>();
int counter = 0;
byte[] emptyBytes = new byte[fileSizeDownload];
while (fileSizeDownload > 0)
{
chunkNumberDownload++;
if (fileSizeDownload < chunkSizeDownload)
{
chunkSizeDownload = (int)fileSizeDownload;
}
var downloadRequest = new DownloadBlockRequest
{
FileContinuationToken = downloadToken,
Offset = offset,
BlockLength = chunkSizeDownload
};
downloadTasks.Add(DownloadChunk(Convert.ToInt32(offset), downloadRequest));
offset += chunkSizeDownload;
fileSizeDownload -= chunkSizeDownload;
counter++;
}
await Task.WhenAll(downloadTasks.ToArray());
await outputFile.WriteAsync(emptyBytes, 0, emptyBytes.Length);
outputFile.Flush();
return outputFile.ToArray();
async Task DownloadChunk(int fileDataOffset, DownloadBlockRequest downloadRequest)
{
var downloadResponse = Execute(downloadRequest);
downloadResponse.Results.TryGetValue<byte[]>("Data", out var result);
Buffer.BlockCopy(result, 0, emptyBytes, fileDataOffset, result.Length);
await Task.CompletedTask;
}
}
} I need to create same methods for Upload file! @MattB-msft |
Beta Was this translation helpful? Give feedback.
-
Where I found BLOCKID? var uploadRequest = new UploadBlockRequest I have this error:
My code: public async Task UploadImageAsync(Entity e, byte[] imageContent, string fileName, string fileAttributeName = null)
{
InitializeFileUpload(e, fileAttributeName, fileName, out string downloadToken);
await UploadFileAsync(e, downloadToken, imageContent, fileName);
}
private void InitializeFileUpload(Entity e, string fileAttributeName, string fileName, out string token)
{
OrganizationRequest initializeUploadRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
initializeUploadRequest = new InitializeAttachmentBlocksUploadRequest
{
Target = e,
};
}
else if (e.Attributes.Contains("annotationid"))
{
initializeUploadRequest = new InitializeAnnotationBlocksUploadRequest
{
Target = e,
};
}
else
{
initializeUploadRequest = new InitializeFileBlocksUploadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName,
FileName = fileName,
};
}
token = string.Empty;
try
{
var initializeUploadResponse = Execute(initializeUploadRequest);
initializeUploadResponse.Results.TryGetValue<string>("FileContinuationToken", out token);
}
catch (System.Exception)
{
}
}
private byte[] SplitArray(byte[] imageContent, int start, int end)
{
var bytes = new Span<byte>(imageContent);
return bytes.Slice(start, end).ToArray();
}
private async Task UploadFileAsync(Entity e, string uploadToken, byte[] imageContent, string fileName)
{
long fileSizeUpload = imageContent.Length;
long offset = 0;
long chunkSizeUpload = 4 * 1024 * 1024; // 4 MB
int chunksCountUpload = (int)(fileSizeUpload / (float)chunkSizeUpload) + 1;
int chunkNumberUpload = 0;
var blockList = new List<string>();
List<Task> uploadTasks = new List<Task>();
int counter = 0;
byte[] emptyBytes = new byte[fileSizeUpload];
while (fileSizeUpload > 0)
{
chunkNumberUpload++;
if (fileSizeUpload < chunkSizeUpload)
{
chunkSizeUpload = (int)fileSizeUpload;
}
var imageChunck = SplitArray(imageContent, (int)offset, (int)chunkSizeUpload);
var blockId = Encoding.UTF8.GetString(imageChunck);
blockList.Add(blockId);
var uploadRequest = new UploadBlockRequest
{
FileContinuationToken = uploadToken,
BlockData = imageChunck,
BlockId = blockId,
};
uploadTasks.Add(UploadChunk(uploadRequest));
offset += chunkSizeUpload;
fileSizeUpload -= chunkSizeUpload;
counter++;
}
await Task.WhenAll(uploadTasks.ToArray());
OrganizationRequest commitUploadCommitRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
commitUploadCommitRequest = new CommitAttachmentBlocksUploadRequest
{
Target = e,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
};
}
else if (e.Attributes.Contains("annotationid"))
{
commitUploadCommitRequest = new CommitAnnotationBlocksUploadRequest
{
Target = e,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
};
}
else
{
commitUploadCommitRequest = new CommitFileBlocksUploadRequest
{
FileName = fileName,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg,
};
}
try
{
var commitUploadResponse = Execute(commitUploadCommitRequest);
}
catch (System.Exception)
{
}
async Task UploadChunk(UploadBlockRequest uploadRequest)
{
var uploadResponse = Execute(uploadRequest);
uploadResponse.Results.TryGetValue<byte[]>("Data", out var result);
await Task.CompletedTask;
}
} |
Beta Was this translation helpful? Give feedback.
-
Ok, I resolve my previous problem: public async Task UploadImageAsync(Entity e, byte[] imageContent, string fileName, string fileAttributeName = null)
{
InitializeFileUpload(e, fileAttributeName, fileName, out string downloadToken);
var result = await UploadFileAsync(e, downloadToken, imageContent, fileName);
if (!result)
throw new ApplicationException("Upload has error");
}
private void InitializeFileUpload(Entity e, string fileAttributeName, string fileName, out string token)
{
OrganizationRequest initializeUploadRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
initializeUploadRequest = new InitializeAttachmentBlocksUploadRequest
{
Target = e,
};
}
else if (e.Attributes.Contains("annotationid"))
{
initializeUploadRequest = new InitializeAnnotationBlocksUploadRequest
{
Target = e,
};
}
else
{
initializeUploadRequest = new InitializeFileBlocksUploadRequest
{
Target = e.ToEntityReference(),
FileAttributeName = fileAttributeName,
FileName = fileName,
};
}
token = string.Empty;
try
{
var initializeUploadResponse = Execute(initializeUploadRequest);
initializeUploadResponse.Results.TryGetValue<string>("FileContinuationToken", out token);
}
catch (System.Exception)
{
}
}
private byte[] SplitArray(byte[] imageContent, int start, int end)
{
var bytes = new Span<byte>(imageContent);
return bytes.Slice(start, end).ToArray();
}
private async Task<bool> UploadFileAsync(Entity e, string uploadToken, byte[] imageContent, string fileName)
{
long fileSizeUpload = imageContent.Length;
long offset = 0;
long chunkSizeUpload = 4 * 1024 * 1024; // 4 MB
int chunksCountUpload = (int)(fileSizeUpload / (float)chunkSizeUpload) + 1;
int chunkNumberUpload = 0;
var blockList = new List<string>();
List<Task> uploadTasks = new List<Task>();
int counter = 0;
byte[] emptyBytes = new byte[fileSizeUpload];
while (fileSizeUpload > 0)
{
chunkNumberUpload++;
if (fileSizeUpload < chunkSizeUpload)
{
chunkSizeUpload = (int)fileSizeUpload;
}
var imageChunck = SplitArray(imageContent, (int)offset, (int)chunkSizeUpload);
var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
blockList.Add(blockId);
var uploadRequest = new UploadBlockRequest
{
FileContinuationToken = uploadToken,
BlockData = imageChunck,
BlockId = blockId,
};
uploadTasks.Add(UploadChunk(uploadRequest));
offset += chunkSizeUpload;
fileSizeUpload -= chunkSizeUpload;
counter++;
}
await Task.WhenAll(uploadTasks.ToArray());
OrganizationRequest commitUploadCommitRequest;
if (e.Attributes.Contains("activitymimeattachmentid"))
{
commitUploadCommitRequest = new CommitAttachmentBlocksUploadRequest
{
Target = e,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
};
}
else if (e.Attributes.Contains("annotationid"))
{
commitUploadCommitRequest = new CommitAnnotationBlocksUploadRequest
{
Target = e,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
};
}
else
{
commitUploadCommitRequest = new CommitFileBlocksUploadRequest
{
FileName = fileName,
BlockList = blockList.ToArray(),
FileContinuationToken = uploadToken,
MimeType = GetMimeType(fileName),
};
}
try
{
var commitUploadResponse = Execute(commitUploadCommitRequest);
}
catch (System.Exception)
{
return false;
}
return true;
async Task UploadChunk(UploadBlockRequest uploadRequest)
{
var uploadResponse = Execute(uploadRequest);
await Task.CompletedTask;
}
}
/// <summary>
/// https://www.iana.org/assignments/media-types/media-types.xhtml#image
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private string GetMimeType(string fileName)
{
var extension = new FileInfo(fileName)?.Extension;
return (extension.ToUpper()) switch
{
".JPG" => System.Net.Mime.MediaTypeNames.Image.Jpeg,
".PNG" => "image/png",
".GIF" => System.Net.Mime.MediaTypeNames.Image.Gif,
".TIFF" => System.Net.Mime.MediaTypeNames.Image.Tiff,
".SVG" => @"image/svg+xml",
".BMP" => "image/bmp",
".JP2" => "image/jp2",
_ => System.Net.Mime.MediaTypeNames.Image.Jpeg
};
} |
Beta Was this translation helpful? Give feedback.
Sorry, I connect to wrong environment.
I change a little code and refactor.
Now WORKS!