Reputation: 79
I have a android mobile application that has functionality to set a profile picture.
I send a variable containing the path of the image to a method that does the following:
string imagePath = _ProfilePicture.GetTag (Resource.String.profile_picture_path).ToString ();
byte[] imageBytes = System.IO.File.ReadAllBytes(imagePath);
Stream imageStream = new MemoryStream(imageBytes);
After this block of code I send the imageStream variable to UploadUserProfilePicture(imageStream);
which is located on the WCF Service
Currently it only sends the stream, but because we cannot send another parameter containing the extension. We save all images as png. I have however found a library that requires the stream to be parsed to bytes and then based on the bytes the file type can retrieved.
However when I then try to use the same stream to Write the file to the location on the server, the position is at the end so the file created is always 0 bytes.
I have tried: Doing the conversion to Bytes in another method and only returning the fileType, however the originals position was still at the end. The CopyTo function gave me the same results. I tried using the Seek function and setting it's position back to zero however the I get a NotSupportedException.
I tried this as well:
string content;
var reader = new StreamReader(image);
content = reader.ReadToEnd();
image.Dispose();
image = new MemoryStream(Encoding.UTF8.GetBytes(content));
^ this seems to corrupt the stream as I cannot get the FileType nor write it to the above location.
I have also had a look at: How to read a Stream and reset its position to zero even if stream.CanSeek == false
This is the method on the WCF Service:
public Result UploadUserProfilePicture(Stream image)
{
try
{
FileType fileType = CommonMethods.ReadToEnd(image).GetFileType();
Guid guid = Guid.NewGuid();
string imageName = guid.ToString() + "." + fileType.Extension;
var buf = new byte[1024];
var path = Path.Combine(@"C:\" + imageName);
int len = 0;
using (var fs = File.Create(path))
{
while ((len = image.Read(buf, 0, buf.Length)) > 0)
{
fs.Write(buf, 0, len);
}
}
return new Result
{
Success = true,
Message = imageName
};
}
catch(Exception ex)
{
return new Result
{
Success = false,
Message = ex.ToString()
};
}
Link to Library Used: https://github.com/Muraad/Mime-Detective The CommonMethods.ReadToEnd(image) method can be found here: How to convert an Stream into a byte[] in C#? as the questions answer
I hope this is enough information on my problem.
Upvotes: 2
Views: 496
Reputation: 22456
On the server side, you receive a stream from WCF that does not support seek operations. You can, however, read the stream to memory as the GetFileType
method requires an array of bytes as input parameter. Instead of accessing the original stream again, you can write the bytes of the array to disk in a very easy way using the File.WriteAllBytes method:
public Result UploadUserProfilePicture(Stream image)
{
try
{
// Store bytes in a variable
var bytes = CommonMethods.ReadToEnd(image);
FileType fileType = bytes.GetFileType();
Guid guid = Guid.NewGuid();
string imageName = guid.ToString() + "." + fileType.Extension;
var path = Path.Combine(@"C:\" + imageName);
File.WriteAllBytes(path, bytes);
return new Result
{
Success = true,
Message = imageName
};
}
catch(Exception ex)
{
return new Result
{
Success = false,
Message = ex.ToString()
};
}
}
Please note that this means that you store a possibly large amount of bytes in memory, in the same way you already did before. It would be better if you could use the stream without reading all bytes into memory, so looking for an alternative for the GetFileType
method that can handle a stream is well worth the time. You could then first save the image to a temporary file and then open a new FileStream to discover the correct file type so that you can rename the file.
Upvotes: 1