2

I am using the Background Transfer to upload Photographs to my Web Service. As the Photograph uploads can consume significant time and memory, I thought it might be a nice idea to use the background transfer request to accomplish this. After the photo is uploaded, I want to obtain the Id of the uploaded photo and then use it for post-processing. However, it turns out I can't do that in a background transfer request.

Per my understanding, Background Transfer works using the following logic ONLY:

  1. You have to obtain the file you want to upload and then save/copy it to your app's Isolated Storage under the folder: shared/transfers. This is extremely important. Apparently, using file in a different location didn't work for me. Maybe it isn't the shared/transfers as much as it is a 'relative' path. But I would stick to the same conventions.

  2. After you have saved the file in that location, your background request can be created based on that. It doesn't look like you can pass POST CONTENT other than the file contents, so any other parameters like file name, mime type etc. will need to be passed as QUERY String parameters only. I can understand this, but it would've been nice if I could pass both as POST Content. I don't think HTTP has a limitation on how this works.

Here is some code for creating a request using Hammock:

string url = App.ZineServiceAuthority + "articles/save-blob?ContainerName={0}&MimeType={1}&ZineId={2}&Notes={3}&IsPrivate={4}&FileName={5}";
url = String.Format(url, userId, "image/jpg", ZineId, txtStatus.Text, true, UploadFileName);

var btr = new BackgroundTransferRequest(new Uri(url, UriKind.Absolute));
btr.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
btr.Method = "POST";
btr.Headers.Add("token", IsolatedStorageHelper.GetTravzineToken());
btr.UploadLocation = new Uri(@"/shared\transfers/" + UploadFileName, UriKind.Relative);
btr.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferStatusChanged);
btr.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferProgressChanged);

BackgroundTransferService.Add(btr);

In my case, I am literally passing all the necessary parameters using the query string. On a successful save, my Web Service returns back the Id of the Photo I just uploaded. However: There is NO way (or at least I know of) to obtain and evaluate the RESPONSE. The Background Transfer Request Event handlers do not expose a RESPONSE. Here are my event handlers:

void btr_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
    bool isUploading = e.Request.TotalBytesToSend > 0 ? true : false;
    lblStatus.Text = isUploading ? "Uploading" + e.Request.BytesSent.ToString() + " sent" : "Done";
}

void btr_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
{
    if (e.Request.TransferStatus == TransferStatus.Completed)
    {

        using (IsolatedStorageFile iso =
               IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (iso.FileExists(e.Request.UploadLocation.OriginalString))
                iso.DeleteFile(e.Request.UploadLocation.OriginalString);
        }

        BackgroundTransferService.Remove(e.Request);

        if (null != e.Request.TransferError)
        {
            MessageBox.Show(e.Request.TransferError.Message);
        }
        else
        {
            lblStatus.Text = "Done baby done";
        }

    }
}

So now my question is, how does anyone do any sort of POST Processing in such scenarios? Can anyone please tell me the line of thought behind designing such an inflexible class? Any thoughts on how I could get around this issue would be appreciated.

Also, does anyone have any working examples of a homegrown BackgroundTransfer?

Claus Jørgensen
  • 25,882
  • 9
  • 87
  • 150
Anup Marwadi
  • 2,517
  • 4
  • 25
  • 42

1 Answers1

1

Haven't tried it but why not set a download location like this:

btr.DownloadLocation = "myDownloadFile.html";
btr.UploadLocation = "myUploadFile.jpg";
...

If the request is completed read the file "myDownloadFile.html" where your response has been stored and delete it afterwards.

Rico Suter
  • 11,548
  • 6
  • 67
  • 93
  • Interesting approach, if I understand correctly, you are saying that after saving the file, I should maybe create a txt file with the response? Hmm. Wondering how well this will sit in when I have 100s of photo uploads going on. – Anup Marwadi Oct 30 '11 at 20:41
  • I think this is the only way to get the response => write to a file. Of course, if you have multiple uploads the file must have an unique filename (eg use request start time `DateTime.Now.Ticks` as filename). This response output file is very small, therefore it should not cause performance problems. Is it working for you? – Rico Suter Oct 31 '11 at 10:09
  • I think I'm going to scrap using the Background Transfer service. This doesn't seem like a good idea. I think I'll write my own handler such that it writes bytes to a Web Service from an Isolated Storage and then if the process stops midway, it will have to re-start all over again. Sad that no one at Microsoft thought about this well enough. – Anup Marwadi Nov 02 '11 at 05:14
  • Right, I agree with your idea, but the idea of having response files and additional overhead of managing them doesn't seem very appealing to me. I don't know however, if the same task allows Upload/Download. I may need to create another task that runs a download. I'll keep you posted. – Anup Marwadi Nov 03 '11 at 07:40
  • Hello, wanted to update you on this. I don't think you can perform an UPLOAD and DOWNLOAD simultaneously like this in the same call, so what you've mentioned above will not work. Thanks for your response though. – Anup Marwadi Jan 02 '12 at 03:33
  • Just to re-update it: using this "overheaded" approach is the only way to proceed with BTS on WP7/WP8. – Léon Pelletier Jul 02 '13 at 21:35