Is there a way to create a byte array from a file in JavaScript (or Typescript) that will be sent to a C# WebApi service, and consumable by the C# byte array method parameter? If so, can you provide an example of the JavaScript?
I should mention, this is an Angular 4+ application that will be posting to the service.
I need to upload Word documents, PDFs and images to a C# service, and this is the way the C# service is currently built. It expects a byte array of the file being uploaded.
This is the request object of the C# service:
[DataContract]
public class SaveAttachmentRequest : BaseRequest
{
[RestUrlParameter(Mode = UrlParameterMode.Inline)]
[DataMember(IsRequired = true)] public AttachmentLookupInformation LookupInformation { get; set; } = new AttachmentLookupInformation();
[DataMember(IsRequired = true)] public byte[] Attachment { get; set; } = null;
}
And this is the AttachmentLookupInformation class:
[DataContract]
public class AttachmentLookupInformation
{
[DataMember(IsRequired = true)] public Guid Id { get; set; } = Guid.Empty;
[DataMember(IsRequired = true)] public Guid LinkedToId { get; set; } = Guid.Empty;
///<summary>Not including the path- just the file name and extension.</summary>
[DataMember(IsRequired = true)] public string FileName { get; set; } = string.Empty;
[DataMember(IsRequired = true)] public int FileSizeInBytes { get; set; } = 0;
///<summary>MIME type.</summary>
[DataMember(IsRequired = true)] public string ContentType { get; set; } = string.Empty;
[DataMember(IsRequired = true)] public AttachmentCategories AttachmentCategory { get; set; } = AttachmentCategories.Unknown;
[DataMember(IsRequired = true)] public string DownloadUrl { get; set; } = string.Empty;
[DataMember(IsRequired = true)] public string CreatedBy { get; set; } = string.Empty;
[DataMember(IsRequired = true)] public DateTimeOffset CreatedTimestamp { get; set; } = DateTimeOffset.MinValue;
}
This is so I can upload the file and additional data to the service.
EDIT: including failed Angular code that I used:
const lookupInfo = new AttachmentLookupInformation();
lookupInfo.Id = Helpers.emptyGuid;
lookupInfo.LinkedToId = this.contractId;
lookupInfo.AttachmentCategory = 10;
const request = new SaveAttachmentRequest();
const reader = new FileReader();
reader.onload = function() {
const buffer = reader.result;
let binary = '';
const bytes = new Uint8Array(buffer);
const length = bytes.byteLength;
for (let i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
request.Attachment = binary;
lookupInfo.ContentType = files[0].type;
lookupInfo.FileName = files[0].name;
lookupInfo.FileSizeInBytes = length;
};
reader.readAsArrayBuffer(files[0]);
reader.onloadend = function() {
request.LookupInformation = lookupInfo;
console.log('request: ', request);
that.contractsService
.save(request, 'attachment/saveattachment')
.subscribe(res => {
if (res.Success) {
console.log('upload response: ', res);
}
});
};
Well, you have:
that.contractsService
.save(request, 'attachment/saveattachment')
But your class you're showing is SaveAttachmentRequest, with public byte[] Attachment inside that. You don't have a function showing in your question called saveattachment inside a class called attachment, which is what should be processing the transferring of the data to the byte[], I would think, unless you're somehow just setting it directly into the parameter. Assuming you have such an attachment class, it should be where you'd have an entry point called saveattachment that does all the work. But say that it is failing because you are passing in your JS model and mapping it directly to the .NET one. So then create a string parameter that can accept your binary string, then save it over to your byte[] one.
[DataMember(IsRequired = true)] public string strAttachment { get; set; } = null;
and in your JS,
request.Attachment = binary;
becomes
request.strAttachment = binary;
Then you'd need:
public class attachment : ApiController
{
[System.Web.Http.HttpPost]
public JsonResult saveattachment(SaveAttachmentRequest sar, AttachmentLookupInformation ali)
{
//string bits = "000011110000001000";
string bits = sar.strAttachment;
int numOfBytes = (int)Math.Ceiling(bits.Length / 8m);
byte[] bytes = new byte[numOfBytes];
int chunkSize = 8;
for (int i = 1; i <= numOfBytes; i++)
{
int startIndex = bits.Length - 8 * i;
if (startIndex < 0)
{
chunkSize = 8 + startIndex;
startIndex = 0;
}
bytes[numOfBytes - i] = Convert.ToByte(bits.Substring(startIndex, chunkSize), 2);
}
sar.attachment = bytes;
// ... do your other stuff for saving your model objects to the DB
// using Entity Framework's data context, etc.
}
}
That's just one way of converting a binary string to byte[]. Plenty of other ways here.
Or, have you tried just sending it as a string, making this:
[DataMember(IsRequired = true)] public byte[] Attachment { get; set; } = null;
turn into this:
[DataMember(IsRequired = true)] public string Attachment { get; set; } = null;
in the first place?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With