Upload file from WinRT to WCF - c#

Help again please. I managed to upload a file from ASP.NET to my WCF service and it works like a charm. Now I want to do the same thing from WinRT without success. My file upload service is based on this post http://www.seesharpdot.net/?p=214. From ASP.NET I upload the file using this code
string filePath = Server.MapPath("~/Files/Happy.jpg");
string fileName = "Happy.jpg";
ServiceReference1.FileMetaData metadata = new ServiceReference1.FileMetaData();
metadata.LocalFilename = fileName;
metadata.FileType = ".jpg";
fileStream = new FileInfo(filePath).OpenRead();
oService.UploadFile(metadata, fileStream);
byte[] buffer = new byte[2048];
int bytesRead = fileStream.Read(buffer, 0, 2048);
while (bytesRead > 0)
{
fileStream.Write(buffer, 0, 2048);
bytesRead = fileStream.Read(buffer, 0, 2048);
}
From WinRT I thought this will work but it does not. No exception is thrown.
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
byte[] bytes = await GetByteFromFile(file);
await App.ServiceInstance.UploadFileAsync(bytes);
}
// This is the method to convert the StorageFile to a Byte[]
private async Task<byte[]> GetByteFromFile(StorageFile storageFile)
{
var stream = await storageFile.OpenReadAsync();
using (var dataReader = new DataReader(stream))
{
var bytes = new byte[stream.Size];
await dataReader.LoadAsync((uint)stream.Size);
dataReader.ReadBytes(bytes);
return bytes;
}
}
What is interesting is that my WCF Service method only accepts a byte array (byte[]) as parameter and ignores the messageContract. Do I need to change my WCF service? How would you recommend I go about to fix this? Any help appreciated.
My WCF Service:
public void UploadFile(FileUploadMessage request)
{
Stream fileStream = null;
Stream outputStream = null;
try
{
fileStream = request.FileByteStream;
string rootPath = HttpContext.Current.Server.MapPath("~\\Files"); ; // ConfigurationManager.AppSettings["RootPath"].ToString();
string newFileName = Path.Combine(rootPath, request.MetaData.LocalFileName);
outputStream = new FileInfo(newFileName).OpenWrite();
const int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead = fileStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesRead = fileStream.Read(buffer, 0, bufferSize);
}
}
catch (IOException ex)
{
throw new FaultException<IOException>(ex, new FaultReason(ex.Message));
}
finally
{
if (fileStream != null)
{
fileStream.Close();
}
if (outputStream != null)
{
outputStream.Close();
}
}
}

I had to implement the same, but the WinRT generation of the library is different as to the one for desktop (Console application).
I had to take out Mtom in the binding, and leave the WCF service parameter as a Stream type.
This still allowed me to upload the document as required. However, on the service, i named the file to the md5 checksum value. The windows 8 app then sent another message to the service, with the parameter being the md5 checksum (calculated on the WinRt device) along with the file metadata. The WCF service then looked for the file with the md5 checksum and renamed the file.
So its a 2 step process from what I see as an immediate workaround, which I think i am happy with.
Happy to share the code for the md5 checksum on the service and WinRt side if required.

Related

WCF: ZIP file generation

I am uploading a file using a WCF service.
The client side code looks like this:
System.ServiceModel.EndpointAddress endPointAddress = new System.ServiceModel.EndpointAddress(address);
IFileStreamService proxy = new FileStreamServiceClient("FileTransfer", endPointAddress);
proxy.UploadFile(uploadReq); //upload the file
Server side includes
public void UploadFile(FileUploadRequest uploadRequest)
{
try
{
string targetFile = uploadRequest.getTargetFile();
Stream sourceStream = uploadRequest.FileByStream;
Log("Going to read stream from client");
using (FileStream outfile = new FileStream(targetFile, FileMode.Create))
{
const int bufferSize = 65536; // 64K chunk
Byte[] buffer = new Byte[bufferSize];
int bytesRead = sourceStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outfile.Write(buffer, 0, bytesRead);
bytesRead = sourceStream.Read(buffer, 0, bufferSize);
}
}
}
}
I am not doing any zipping at client side. But at the server side zip file is getting created like this
temp_c7dfbfd7-3495-43b6-a0ec-e46153cef72a.zip
zip file is also corrupted. Can anybody point me to where things are going wrong?

Download a torrent file result is corrupt WP8

in an app I am making some of the files required are torrent files but i'm having an odd issue, whenever I download a torrent file through the app the files ends up corrupt and wont open in any torrent app, I used wptools to extract them to a pc and test it and still corrupt here is my code I can't see what 'im doing wrong, I am fairly new to using webclient. I assume it has something to do with the way im saving the file any help would be great thanks.
private void tbLink_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
string[] linkInfo = (sender as TextBlock).Tag as string[];
fileurl = linkInfo[0];
System.Diagnostics.Debug.WriteLine(fileurl);
WebClient client = new WebClient();
client.OpenReadCompleted += client_OpenReadCompleted;
client.OpenReadAsync(new Uri(fileurl), linkInfo);
client.AllowReadStreamBuffering = true;
}
async void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
string[] linkInfo = e.UserState as string[];
filetitle = linkInfo[1];
filesave = (filetitle);
var isolatedfile = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = isolatedfile.OpenFile(filesave, System.IO.FileMode.Create))
{
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
}
try
{
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile torrentfile = await local.GetFileAsync(filesave);
Windows.System.Launcher.LaunchFileAsync(torrentfile);
}
catch (Exception)
{
MessageBox.Show("File Not Found");
}
This is incorrect:
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
The Read method will return the number of bytes read, it can be less than buffer.Length. So the code should read:
int byteCount;
// Select an appropriate buffer size.
// This is a buffer, not space for the entire file.
byte[] buffer = new byte[4096];
while ((byteCount = e.Result.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
UPDATE: If the data is compressed, as in the question that you posted in your comment, then you can decompress the stream:
int byteCount;
byte[] buffer = new byte[4096];
using (GZipStream zs = new GZipStream(e.Result, CompressionMode.Decompress))
{
while ((byteCount = zs.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
}
Note that I have not tested this code, I'm assuming that e.Result is a stream.

c# upload in real time from client to server to amazon s3

Good morning, I have an desktop app that uploads files to a WCF service and then WCF Service uploads to Amazon S3.
This is my WCF method that receives the file and uploads to S3.
public void UploadFile(RemoteFileInfo request)
{
config = new AmazonS3Config();
config.CommunicationProtocol = Protocol.HTTP;
accessKeyID = "XXXXXXX";
secretAccessKeyID = "YYYYYYYY";
client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKeyID, secretAccessKeyID, config);
int chunkSize = 2048;
byte[] buffer = new byte[chunkSize];
using (System.IO.MemoryStream writeStream = new System.IO.MemoryStream())
{
do
{
// read bytes from input stream
int bytesRead = request.FileByteStream.Read(buffer, 0, chunkSize);
if (bytesRead == 0) break;
// simulates slow connection
System.Threading.Thread.Sleep(3);
// write bytes to output stream
writeStream.Write(buffer, 0, bytesRead);
} while (true);
// report end
Console.WriteLine("Done!");
// start the uploading to S3
PutObjectRequest fileRequest = new PutObjectRequest();
fileRequest.WithInputStream(writeStream);
fileRequest.Key = "testfile.pdf";
fileRequest.WithBucketName("tempbucket");
fileRequest.CannedACL = S3CannedACL.Private;
fileRequest.StorageClass = S3StorageClass.Standard;
client.PutObject(fileRequest);
writeStream.Close();
}
}
On my client I get the progress in real time when upload the file to the WCF Service but when I get the 100% complete it doesnt mean that the file has already uploaded to S3, so I would like to know if its possible to being uploading the file to S3 while Im writing the stream (inside of the using
(System.IO.MemoryStream writeStream = new System.IO.MemoryStream())
{
Is this possible? Any guideline on how to do it?
Appreciate in advance.
You can use InputStream property of PutObjectRequest
public void UploadFile(RemoteFileInfo request)
{
config = new AmazonS3Config();
config.CommunicationProtocol = Protocol.HTTP;
accessKeyID = "XXXXXXX";
secretAccessKeyID = "YYYYYYYY";
client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKeyID,secretAccessKeyID,config);
int chunkSize = 2048;
byte[] buffer = new byte[chunkSize];
PutObjectRequest fileRequest = new PutObjectRequest();
fileRequest.Key = "testfile.pdf";
fileRequest.WithBucketName("tempbucket");
fileRequest.CannedACL = S3CannedACL.Private;
fileRequest.StorageClass = S3StorageClass.Standard;
using (fileRequest.InputStream = new System.IO.MemoryStream())
{
do
{
// read bytes from input stream
int bytesRead = request.FileByteStream.Read(buffer, 0, chunkSize);
if (bytesRead == 0) break;
// simulates slow connection
System.Threading.Thread.Sleep(3);
// write bytes to output stream
fileRequest.InputStream.Write(buffer, 0, bytesRead);
} while (true);
// report end
Console.WriteLine("Done!");
client.PutObject(fileRequest);
}
}
I would recommend uploading the file to the WCF as chunks instead of a stream. I did so and it works just fine. also you need to return a message of the actual bytes written to the amazon later on you can increase the progress bar based on that. I know it will cause you to write a while loop in the client application but it will help you to show the progress with 100% accuracy for large files. Your WCF function should take the parameter like these
[DataContract]
class RemoteFileInfo
{
[DataMember]
Byte[] myChunk;
[DataMember]
long myOffset;
// other stuff you think you need to be sent each time.
}

Uploading image as attachment in RESTful WCF Service

I am trying to upload an image as an attachment in REST WCF Service and I am getting the following error.
"Access to path "C:\ImageUpload" is denied"
I have enabled Full Contorl permissions to this folder. I dont understand why I am getting this error.
I am new to WCF, and the most of the code I gathered from online resources.
Appreciate if you could let me know If there is any mistake in my code.
Here is my code.
REST WCF Service Code:
[OperationContract]
[WebInvoke(UriTemplate = "uploadImage/{parameter1}")]
void uploadImage(Stream fileStream);
public void uploadImage(Stream fileStream)
{
string filePath = #"C:\ImageUpload";
FileStream filetoUpload = new FileStream(filePath, FileMode.Create);
byte[] byteArray = new byte[10000];
int bytesRead, totalBytesRead = 0;
do
{
bytesRead = fileStream.Read(byteArray, 0, byteArray.Length);
totalBytesRead += bytesRead;
}
while (bytesRead > 0);
filetoUpload.Write(byteArray, 0, byteArray.Length);
filetoUpload.Close();
filetoUpload.Dispose();
}
This is my Test Client Code(Simple .aspx web page)
protected void btnUpload_Click(object sender, EventArgs e)
{
string file = FileUpload1.FileName;
RESTService1Client client = new RESTService1Client();
byte[] bytearray = null;
string name = "";
if (FileUpload1.HasFile)
{
name = FileUpload1.FileName;
Stream stream = FileUpload1.FileContent;
stream.Seek(0, SeekOrigin.Begin);
bytearray = new byte[stream.Length];
int count = 0;
while (count < stream.Length)
{
bytearray[count++] = Convert.ToByte(stream.ReadByte());
}
}
WebClient wclient = new WebClient();
wclient.Headers.Add("Content-Type", "image/jpeg");
client.uploadImage(FileUpload1.FileContent);
}
It's likely nothing to do with WCF or your code. It really is highly probable that permissions on that folder are insufficient for the IIS process user. By default the ASP.NET user is Network Service.
Try creating a new Windows user just for your ASP.NET application. Grant that user explicit read/write access to the upload folder. Then use Impersonation to make ASP.NET use that user.
http://www.codeproject.com/Articles/107940/Back-to-Basic-ASP-NET-Runtime-Impersonation
Rewrite server side as such:
REST WCF Service Code:
[OperationContract]
[WebInvoke(UriTemplate = "uploadImage/{parameter1}/{parameter2}")]
void uploadImage(Stream fileStream, string fileName);
.
public void uploadImage(Stream fileStream, string fileName)
{
string filePath = #"C:\ImageUpload\";
using (FileStream filetoUpload = new FileStream(filePath + fileName, FileMode.Create))
{
byte[] byteArray = new byte[10000];
int bytesRead = 0;
do
{
bytesRead = fileStream.Read(byteArray, 0, byteArray.Length);
if (bytesRead > 0)
{
filetoUpload.Write(byteArray, 0, bytesRead);
}
}
while (bytesRead > 0);
}
}
and your client side as such:
protected void btnUpload_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
RESTService1Client client = new RESTService1Client();
client.uploadImage(FileUpload1.FileContent, Path.GetFileName(FileUpload1.FileName));
}
}

How to properly serve a PDF file

I am using .NET 3.5 ASP.NET. Currently my web site serves a PDF file in the following manner:
context.Response.WriteFile(#"c:\blah\blah.pdf");
This works great. However, I'd like to serve it via the context.Response.Write(char [], int, int) method.
So I tried sending out the file via
byte [] byteContent = File.ReadAllBytes(ReportPath);
ASCIIEncoding encoding = new ASCIIEncoding();
char[] charContent = encoding.GetChars(byteContent);
context.Response.Write(charContent, 0, charContent.Length);
That did not work (e.g. browser's PDF plugin complains that the file is corrupted).
So I tried the Unicode approach:
byte [] byteContent = File.ReadAllBytes(ReportPath);
UnicodeEncoding encoding = new UnicodeEncoding();
char[] charContent = encoding.GetChars(byteContent);
context.Response.Write(charContent, 0, charContent.Length);
which also did not work.
What am I missing?
You should not convert the bytes into characters, that is why it becomes "corrupted". Even though ASCII characters are stored in bytes the actual ASCII character set is limited to 7 bits. Thus, converting a byte stream with the ASCIIEncoding will effectively remove the 8th bit from each byte.
The bytes should be written to the OutputStream stream of the Response instance.
Instead of loading all bytes from the file upfront, which could possibly consume a lot of memory, reading the file in chunks from a stream is a better approach. Here's a sample of how to read from one stream and then write to another:
void LoadStreamToStream(Stream inputStream, Stream outputStream)
{
const int bufferSize = 64 * 1024;
var buffer = new byte[bufferSize];
while (true)
{
var bytesRead = inputStream.Read(buffer, 0, bufferSize);
if (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
}
if ((bytesRead == 0) || (bytesRead < bufferSize))
break;
}
}
You can then use this method to load the contents of your file directly to the Response.OutputStream
LoadStreamToStream(fileStream, Response.OutputStream);
Better still, here's a method opening a file and loading its contents to a stream:
void LoadFileToStream(string inputFile, Stream outputStream)
{
using (var streamInput = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
{
LoadStreamToStream(streamInput, outputStream);
streamInput.Close();
}
}
You may also need to set the ContentType by doing something like this:
Response.ContentType = "application/octet-stream";
Building upon Peter Lillevold's answer, I went and just made some extension methods for his above functions.
public static void WriteTo(this Stream inputStream, Stream outputStream)
{
const int bufferSize = 64 * 1024;
var buffer = new byte[bufferSize];
while (true)
{
var bytesRead = inputStream.Read(buffer, 0, bufferSize);
if (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
}
if ((bytesRead == 0) || (bytesRead < bufferSize)) break;
}
}
public static void WriteToFromFile(this Stream outputStream, string inputFile)
{
using (var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
{
inputStream.WriteTo(outputStream);
inputStream.Close();
}
}

Categories