We are working on a Windows 8 app where we simply need to email the results of a survey. Sounds easy enough, right? Particularly with Windows 8′s shiny new Share framework. Fast forward a month of struggle and frustration and here’s what I’ve learned.
Cliff Notes: if you are a Windows 8 developer, prepare to be frustrated by coding and debugging share content. Also, apparently I only blog when I need to rant about something
First, a couple of caveats that would have been helpful to know a month ago.
- Because the share charm will only wait a very limited time to get a response from the app, if you set breakpoints you probably aren’t going to complete a share operation. Sometimes it will continue and finish the share, but usually not. Also depends where your breakpoints are.
- If your app has an exception while debugging your share operation, say goodbye to share. It seems to break the whole framework until you reboot. Once again, not every time, but usually. More on that in a bit.
- Don’t expect the documentation or samples to be correct. There is a lot of bad information in there and not much else in the way of Google to help you.
You can choose to share one or more types of content during a share operation. I’m just trying to share an html fragment that has 2 images. You can see a simplified example here: http://msdn.microsoft.com/en-us/library/windows/apps/hh758310.aspx
Here is another: http://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.datatransfer.datapackage.resourcemap
The takeaway is if you reference images in your html fragment source, you need to set up a stream reference to the file and then assign that to a resourceMap matching the name in your html img src property. Here is a rough idea of the code to do it.
var emailReport = WinJS.UI.eventHandler(function (e) { try { var appData = Windows.Storage.ApplicationData.current; var localFolder = appData.localFolder; var request = e.request; var localImage = "Survey1\\Image1.png"; var localMap = "Image1.png"; var html = "<div><p>Here is the image I wanted you to see: <img src='" + localMap + "'></p></div>"; request.data.properties.title = “The best image ever”; var def = e.request.getDeferral(); localFolder.getFileAsync(localImage).done(function (i) { var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(i); request.data.setHtmlFormat( Windows.ApplicationModel.DataTransfer.HtmlFormatHelper.createHtmlFormat(html)); request.data.resourceMap[localMap] = streamRef; def.complete(); }); } catch (ex) { logger.error(ex.message, "your share blowed up"); } });
The images we needed to share were in a subfolder in Local Storage. Now first of all, there aren’t any samples that I’ve found that show how to do that. But shouldn’t be much different, right? After spending a week on and off fighting it, here’s what I found.
1. Apparently you can’t have spaces or slashes in the resourceMap key. I guess this makes sense in retrospect, but considering the samples which clearly show using slashes, it’s not very discoverable. Almost every official MSDN sample has this issue.
2. You have to get a proper reference to the image file to set up the stream reference. If the image files aren’t in the root of local storage, things get tricky. Ours are not because they are segregated by a survey identifier.
For instance the docs say to use an absolute path, but it isn’t even clear what that means in this context. You also can’t use this format: "ms-appdata:///local/SomeFolder/MyImage.png". Doesn’t find the file and you get Access Denied. What I found that does work is this format: "SomeFolder\MyImage.png". I think two back slashes at the front of the path works as well. (Update Two back slashes at the front of the path does not work.)
3. It makes a difference whether you use forward or back slashes and how many. This gets extra tricky due to a backslash also being an escape character. Also, what works for your local path to retrieve the file won’t work for the html src path (which makes sense, but isn’t obvious from the docs).
4. I haven’t completely proved this out yet, but apparently you can use whatever name for the file you want to in the html img src. It just has to match the resourceMap key. Still need to confirm this.
About that debugging business
So don’t get me started on the issues with debugging sharing in Visual Studio 2012. You could always go read my Connect bug. And recently some other developers started feeling my pain, as evidenced by this thread. I’m still not sure if this is a Windows 8 issue or a Visual Studio issue or both. It does seem to be cross language since I’m developing in javascript and some of the other folks with the issue are using WPF/XAML.
It seems like if you get an exception and/or stop the debugger in the middle of a share operation, whatever is facilitating share behind the scenes just crashes. After that, your breakpoints won’t get hit and it appears the datarequested handler never gets called. The share operation just sits and spins with “Getting info from {your app name}”. Even if you just get out of the debugger entirely and just run the app, share breaks as well although you do get an error message. Once that happens, often the only thing you can do is reboot. Yesterday I must have rebooted my dev machine 10-15 times just to continue debugging the share issues above. If you completely close the Simulator and start it again, usually this will allow the share to work again, but on the Simulator only. But your local machine won’t work without a reboot. Sometimes if you wait long enough it seems to fix itself. This makes me think there is some pending operation hanging out that never gets terminated, but at some point gets garbage collected.
At any rate, it makes developing any kind of complicated sharing content a real chore, unless you are the type of developer who can write perfect code the first time. If you found this post because you are having this issue, please join the conversation on the forums or Connect or both. Microsoft really needs to fix this.