152

I have a REST service that reads a file and sends it to another console application after converting it to Byte array and then to Base64 string. This part works, but when the same stream is received at the application, it gets manipulated and is no longer a valid Base64 string. Some junk characters are getting introduced into the stream.

The exception received when converting the stream back to Byte is

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters

At Service:

[WebGet(UriTemplate = "ReadFile/Convert", ResponseFormat = WebMessageFormat.Json)]  
public string ExportToExcel()
  {
      string filetoexport = "D:\\SomeFile.xls";
      byte[] data = File.ReadAllBytes(filetoexport);
      var s = Convert.ToBase64String(data);
      return s;
  }

At Application:

       var client = new RestClient("http://localhost:56877/User/");
       var request = new RestRequest("ReadFile/Convert", RestSharp.Method.GET);
       request.AddHeader("Accept", "application/Json");
       request.AddHeader("Content-Type", "application/Json");
       request.OnBeforeDeserialization = resp => {resp.ContentType =    "application/Json";};
       var result = client.Execute(request);
       byte[] d = Convert.FromBase64String(result.Content); 
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Rohit Verma
  • 1,669
  • 2
  • 11
  • 10
  • 5
    Probably this has to do with `Encoding`. – Alex Filipovici Feb 27 '13 at 14:08
  • 2
    Do you know what "junk characters" are being inserted? – Jim Mischel Feb 27 '13 at 14:10
  • The updated code is helpful. Now we need to see the string that you send (i.e. `s` on the service) and the content that's received (i.e. `result.content`. You don't need to post the entire string, just up to the first mangled character (or, if that's still too long, some substrings that show what was sent and what was received). – Jim Mischel Feb 27 '13 at 14:21
  • @JimMischel yeah, i noticed that '/' is getting replaced with '\/' – Rohit Verma Feb 27 '13 at 14:22
  • @RohitVerma For the slash getting replaced, is that in the raw HTML contents (Fiddler will tell you), or in `result.Content`? That will tell you if the problem is with the server or the client. – Joe Enos Feb 27 '13 at 15:13
  • The error could also be related to a padding issue @see : https://stackoverflow.com/a/50525594/5102373 – Marc_Alx Sep 27 '19 at 15:21

13 Answers13

155

Check if your image data contains some header information at the beginning:

imageCode = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkC...

This will cause the above error.

Just remove everything in front of and including the first comma, and you good to go.

imageCode = "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkC...
bendecko
  • 2,643
  • 1
  • 23
  • 33
  • 1
    Had this exact issue somehow. Logic is to remove everything after `,` if `data:` is present. Bam. Working now. – Maxime Rouiller Jun 14 '16 at 13:14
  • var cleanerBase64 = imageCode.Substring(22); // remove data:image/png;base64 – mejiamanuel57 Nov 08 '18 at 21:22
  • 4
    Just a little bit of code to help...... if (this.imageCode.Contains(',')) this.imageCode = this.imageCode.Substring(this.imageCode.IndexOf(",") + 1, this.imageCode.Length - (this.imageCode.IndexOf(",") + 1)); – Toby Simmerling Jul 16 '19 at 09:15
  • 3
    I would use: .Split(',')[1] – Verthosa Jul 22 '19 at 11:35
  • 5
    `str.Substring(str.LastIndexOf(',') + 1)` should do it. – Alisson Reinaldo Silva Oct 29 '19 at 13:08
  • solved my problem. I was trying to save the base64 string to azure endpoint. After removed the header str, it worked. works like magic, thank you! – RainCast May 07 '20 at 07:42
  • this worked for me as well. I'm wondering if there's any reason why Convert.FromBase64String doesn't handle this scenario – kurdemol94 May 21 '21 at 10:27
  • I came here but had this message but with smtp issue on login. Turns out the office365 user email account was not licensed/mail setup with the right options. So there error for me was a red herring. – MTMDev Jun 15 '23 at 12:02
95

Very possibly it's getting converted to a modified Base64, where the + and / characters are changed to - and _. See http://en.wikipedia.org/wiki/Base64#Implementations_and_history

If that's the case, you need to change it back:

string converted = base64String.Replace('-', '+');
converted = converted.Replace('_', '/');
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 1
    I got this done ....Thanks to you!! Replacing the characters with the appropriate ones. But is this a concrete solution ? i mean how can i guarantee that for all the files this will be the character to be replaced ? – Rohit Verma Feb 27 '13 at 14:52
  • 2
    @RohitVerma: I don't know. You need to find out where those characters are getting changed, and determine if it's likely to change any other characters. I'm not familiar with RestSharp, so I can't offer any advice there. If my response answered your question, it's customary to mark it as the accepted answer. (Click the checkmark next to the answer on the left.) – Jim Mischel Feb 27 '13 at 15:14
  • OMG Thank you! This and adding the necessary padding "=" characters solved my problem. The decrypt function in Azure's Key Vault REST API needs this process and doesn't document it. – Brian Jul 08 '19 at 23:42
42

We can remove unnecessary string input in front of the value.

string convert = hdnImage.Replace("data:image/png;base64,", String.Empty);

byte[] image64 = Convert.FromBase64String(convert);
Hasan Tuna Oruç
  • 1,656
  • 15
  • 16
  • This solution worked for me. But this is specifically for png images. Is there any generalized syntax which replaces all kinds of image extensions? – Karan Desai Sep 01 '16 at 07:25
  • 1
    i read your comment now. i dont try this but you can use this: hdnImage.Replace("data:image/png;base64,", String.Empty).Replace("data:image/jpg;base64,", String.Empty).Replace("data:image/bmp;base64,", String.Empty); again, i dont try this. please try and write for me. i will change. – Hasan Tuna Oruç Sep 05 '16 at 11:32
15

Remove the unnecessary string through Regex

Regex regex=new Regex(@"^[\w/\:.-]+;base64,");
base64File=regex.Replace(base64File,string.Empty);
Amro Mustafa
  • 589
  • 4
  • 15
7

Since you're returning a string as JSON, that string will include the opening and closing quotes in the raw response. So your response should probably look like:

"abc123XYZ=="

or whatever...You can try confirming this with Fiddler.

My guess is that the result.Content is the raw string, including the quotes. If that's the case, then result.Content will need to be deserialized before you can use it.

Joe Enos
  • 39,478
  • 11
  • 80
  • 136
  • you are correct, this includes " " but the point here is that apart from the addition of these quotation marks other characters are also getting replaced. – Rohit Verma Feb 27 '13 at 14:57
  • Deserializing that string using a JSON serializer will take care of both the quotes and the escaped slash. Escaping your forward slashes with a backslash is something that some JSON serializers do - using a deserializer will turn \/ back into just plain / so that you'll get valid base-64. Since you're receiving JSON, it's always a good idea to parse that JSON properly, even if it is just a simple string. – Joe Enos Feb 27 '13 at 16:32
6

Just in case you don't know the type of uploaded image, and you just you need to remove its base64 header:

 var imageParts = model.ImageAsString.Split(',').ToList<string>();
 //Exclude the header from base64 by taking second element in List.
 byte[] Image = Convert.FromBase64String(imageParts[1]);
Mahdi Alkhatib
  • 1,954
  • 1
  • 29
  • 43
6

Probably the string would be like this data:image/jpeg;base64,/9j/4QN8RXh... First split for / and get the second token.

var StrAfterSlash = Face.Split('/')[1];

Then Split for ; and get the first token which will be the format. In my case it's jpeg.

var ImageFormat =StrAfterSlash.Split(';')[0];

Then remove the line data:image/jpeg;base64, for the collected format

CleanFaceData=Face.Replace($"data:image/{ImageFormat };base64,",string.Empty);
DevLoverUmar
  • 11,809
  • 11
  • 68
  • 98
3

I arranged a similar context as you described and I faced the same error. I managed to get it working by removing the " from the beginning and the end of the content and by replacing \/ with /.

Here is the code snippet:

var result = client.Execute(request);
var response = result.Content
    .Substring(1, result.Content.Length - 2)
    .Replace(@"\/","/");
byte[] d = Convert.FromBase64String(response);

As an alternative, you might consider using XML for the response format:

[WebGet(UriTemplate = "ReadFile/Convert", ResponseFormat = WebMessageFormat.Xml)]  
public string ExportToExcel() { //... }

On the client side:

request.AddHeader("Accept", "application/xml");
request.AddHeader("Content-Type", "application/xml");
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/xml"; };

var result = client.Execute(request);
var doc = new System.Xml.XmlDocument();
doc.LoadXml(result.Content);
var xml = doc.InnerText;
byte[] d = Convert.FromBase64String(xml);
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
3
var spl = item.Split('/')[1];
var format =spl.Split(';')[0];           
stringconvert=item.Replace($"data:image/{format};base64,",String.Empty);
mostafa kazemi
  • 514
  • 6
  • 7
  • 7
    Although this code might solve the problem, a good answer should also explain **what** the code does and **how** it helps. – BDL Apr 06 '20 at 09:25
3

please check if there is no == as a postfix, just add == chars at last of string

// "........V/XeAeH/wALVWKtD8lz/AAAAABJRU5ErkJggg"
"........V/XeAeH/wALVWKtD8lz/AAAAABJRU5ErkJggg=="    /* yes */ 
Mucahid Uslu
  • 367
  • 3
  • 11
2

As Alex Filipovici mentioned the issue was a wrong encoding. The file I read in was UTF-8-BOM and threw the above error on Convert.FromBase64String(). Changing to UTF-8 did work without problems.

testing
  • 19,681
  • 50
  • 236
  • 417
1

And some times it started with double quotes, most of the times when you call API from dotNetCore 2 for getting file

string string64 = string64.Replace(@"""", string.Empty);
byte[] bytes = Convert.ToBase64String(string64);
user193679
  • 181
  • 2
  • 6
0

I get this error because a field was varbinary in sqlserver table instead of varchar.

M Komaei
  • 7,006
  • 2
  • 28
  • 34