Quantcast
Channel: Http Client Protocol Issues (and other fun stuff I support)
Viewing all 140 articles
Browse latest View live

How to troubleshoot Windows Azure Mobile Services

$
0
0

Undoubtedly when developing application using Windows Azure Mobile Services you will get unexpected results.  This guide will help you isolate and troubleshoot the most common errors that you will encounter.  This post is not intended to solve you issues but help you isolate and simplify the problem so you can dig in deeper or engage Microsoft Support for additional help.

Basic Architecture

To effectively troubleshoot a problem you need to understand how Mobile Services work.  A simple breakdown of the architecture is that there is a server component (your Mobile Service URL) and a client component (your application code). 

When you create your Mobile Service, we host your Service on Azure and expose an HTTPS endpoint that allows your client code to access your data stored in your Azure SQL database.

Your Mobile Service (the server component) is hosted on Azure and depends on our Azure infrastructure to bring up your Service when it is needed (if free mode… the default) and provides logging and other services like the Scheduler.

The client will issue one of five types of requests to the server.  There is a login request and four data requests.  The client communicates with the server through the REST API over HTTPS (or HTTP).  If you are using Windows, Android, iOS or any other client, those libraries simply translate the client library code into an HTTPS call to the REST API.  Understanding this API is your key to troubleshooting difficult issues!  Here is a link to the REST API documentation.  Watch Josh’s video on this API to learn how to login, create, read, update and delete data without writing any client code!

The server has a script interface for the four data operations.  You can use logging in these scripts to determine if a request gets to your server and what parameters are being passed How to: write output to the mobile service logs.  In addition you can run a Scheduler script on demand or on a schedule and there too, you can use logging to troubleshoot.  Ultimately the scripts will communicate with your Azure SQL database.  You can see your data in the DATA tab of your Mobile Service or connect to the Database through the portal and view it there.

Troubleshooting the Problem is Isolating the Problem!

You need to determine where you think the problem is; the Mobile Service infrastructure, your Mobile Service, Azure SQL or client code, and then compare what the expected result is verses what you are experiencing.  Here are some steps you can take to isolate the problem:

Can you get to your Mobile Services dashboard (https://manage.windowsazure.com/) and click on your Mobile Service?  If not, perhaps there is a connectivity or network error where you are.

Are the Mobile Services healthy?  You can go to Windows Azure Service Dashboard and see if the Mobile Services are see the status.  Click on the RSS feed icon on the right of the Mobile Services to see any news about Mobile Services.  There is a link at the top of the page to get help if the service is not healthy.

image

Look in the LOGS tab of your Mobile Service in the Windows Azure Management dashboard (https://manage.windowsazure.com/) and see if there are any useful errors logged that give you a clue where to start looking.  These logs are generated when there are errors or messages generated from the scripts you have defined for your mobile service or if there are problems executing the default script actions (Scheduler, insert, read, update or delete).

Can you get to your Mobile Service URL?  You can find this if you don’t know it if you click on your Mobile Service and look on the Dashboard tab for ‘MOBILE SERVICE URL’?  If you cannot reach this URL there may be a problem with your network or Mobile Service.  Your Mobile Service URL will be of the form https://MOBILESERVICENAME.azure-mobile.net.  If you cannot get to your Mobile Service URL, turn off ‘Friendly Error Messages’ in Internet Explorer and see if you are getting a 500 (note: 500 error means anything in the 500 range) error back.  If you get a message that you cannot connect that means there is an issue with your network.  If you get a 500 error back that means something is wrong in your Mobile Service!  The problem may be due to one of your scripts.  This could be the Scheduler, insert, read, update or delete scripts for one of your tables.  A quick test is to go to the configure tab and toggle the ‘ENABLE DYNAMIC SCHEMA’ property  from its current value, save and then toggle it back and save.  This will reset you Mobile Service instance.  Immediately try the Mobile Service URL again and if you can get to it without the 500 error, one of your scripts is at fault (see debugging scripts).  If that does not fix the 500 error look in your LOGS tab to see if there are errors logged that may help you troubleshoot further or contact Microsoft Support.  

Cannot reach Mobile Service URL (network issue):

image

Successful test for Mobile Service URL:

image

Turn off Friendly Error Messages by unchecking this box:

image

 

If you can get to your Mobile Service URL and it reports that your service is up and running the problem may be your code, data or scripts is causing your issue.  You can use Fiddler or your favorite ‘Man in the Middle’ https or http network inspection tool to troubleshoot this further.  Your Mobile Service is accessible over HTTP or HTTPS so if you cannot find a tool to decode the HTTPS you can change your Mobile Service URL to point to the HTTP version of your site and use a tool like Netmon (Microsoft Network Monitor) or WireShark.  For example: https://jeffcooldemo.azure-mobile.net/ is also reachable at the HTTP URL http://jeffcooldemo.azure-mobile.net/.  Change your code to point to the http version and log the traffic!  Here is an example of a response that was due to a script that was stuck in a loop.  By removing the script temporarily we were able to confirm that indeed the script was the cause and we could put parts of the script back in to find the problem:

HTTP/1.1 503 Service Unavailable
Cache-Control: no-cache
Content-Length: 56
Content-Type: application/json
Server: Microsoft-IIS/8.0
Set-Cookie: ARRAffinity=a1609f7e18423e2e751820185650cd3294e23cc9124779bc6fa5cbbf3c204a6c;Path=/;Domain=jeffcooldemo.azure-mobile.net
x-zumo-version: Zumo.Main.0.1.6.2648.Runtime
X-Powered-By: ASP.NET
X-Powered-By: ARR/2.5
X-Powered-By: ASP.NET
Set-Cookie: WAWebSiteSID=aff2b3fa800f40f0ae32c899ca03029b; Path=/; HttpOnly
Date: Thu, 30 May 2013 13:00:43 GMT

{"code":503,"error":"Error: The request has timed out."}

If you see a 401 error from Fiddler the problem is in your authentication.  Find out from your DATA tab what the permissions are on the table you are trying to access.  Adjust your code or permissions appropriately.

If Fiddler or similar tools do not reveal a specific error or problem (inspect both what you are sending and what you are receiving) you need to simplify the problem to determine if basic functionality is working for you.  Use Composer in Fiddler or Postman in Chrome to manually retrieve your table information.  Start simple and add complexity as you succeed with the simple operations.  For example, can you fetch the entire table (see this post)?  If not what does the dashboard show, can you see the data from your Mobile Services DATA tab?  If you can see the data in the dashboard but fetching results in nothing or an error, then inspect the LOGS on the Mobile Service and/or temporarily put back the default ‘read’ script if you have modified it.  Optionally you can bypass your scripts by using the X-ZUMO-MASTER header with your Master key and use the noscript uri parameter (see the Query documentation).

If the read operation works but the Insert, Update or Delete operations fail then follow a similar pattern: Check the LOGS, try restoring the default scripts (create a new Mobile Service to see what they were originally) and finally you can try some simple operations using the REST APIs and Fiddler or Postman.  If restoring the scripts to the original scripts works, then you need to debug the problem script.  You can do this using console.log(“message”) throughout the script or better yet see this post: Debugging your Mobile Service scripts.

Assuming you have proven to yourself the Mobile Service itself is performing correctly, you can move on to troubleshooting the Client application code.

Again, Fiddler is your hero here.  Capture the traffic from your application and compare it to the successful cases when troubleshooting the server side.  Are there query parameters or odd data?  What is the client sending when you inspect the traffic in Fiddler and does it get a response back?  Perhaps the Mobile Service is giving you back exactly what you are asking for but your client logic is filtering the data with the request.  You can see detailed error messages in the response that may not be visible in your application.  For example here is some output from a custom query that resulted in a 400 error.  The 400 code is not useful but the JSON in the response (viewable in Fiddler) pinpointed the problem:

{"code":400,"error":"Error: Invalid query specified. Error: Unknown identifier 'substringOf' (at index 11)"}

If Fiddler does not show you what the problem is you can debug your code and see what is being returned and sent.  Perhaps the problem has nothing to do with the Mobile Service client but with your logic after you get the response!  Confirm you are getting the data back you expect using Fiddler and then start breaking down what you are doing with that data.  You can create a new project that uses your Mobile Service and start with the simplest operations to isolate the potential issue.

Search the Forums.  Chances are, someone else has faced the same problem you are!  You can get to the Forums from the Azure portal.  Mobile Services is currently in the Preview Forums here:  http://social.msdn.microsoft.com/Forums/en-US/azuremobile/threads

Try the sample code and quickstarts to see what is different between your code and these documented working scenarios (again Fiddler can help you compare traffic between the success and failed cases).

Parting thoughts

Isolating the problem is critical for troubleshooting.  If you ask for help on the forums or through support, you will be asked to narrow the problem to the simplest repro so you should do this on your own as you try to find where the problem is.

I will augment this post with new information and ideas for troubleshooting.  Feel free to let me know if you have success with these steps or have suggestions for other troubleshooting steps!  Do not expect support via this blog however.  Make sure you post questions to the Mobile Services forum instead (I filter responses on my blog and won’t post support requests).

Jeff


Move Your Client Logic to the Server - Windows Azure Mobile Services

$
0
0

The Client Libraries for Windows Azure Mobile Services are powerful and allow you to embed logic within your client application.  The quickstart and sample applications give you a great overview on how to implement logic on the client to get the view of data you would like in the client application.  A different architecture for you would be to move this view logic to the server using the Server Scripting capability of Windows Azure Mobile Services so that you do not have to duplicate the client side logic for each platform that you target as a client! 

NOTE: There is nothing wrong with having your query logic client side but sometimes it makes sense to have it all on the server.  For example if it is a complicated query and every platform needs to implement it, consider moving it server side.

For this example I will to take the C# Windows Store app Todo sample project that is generated for you from the Azure Management Dashboard and move the client side logic into the server.  In this case we never want any view besides the one that excludes the complete items so I will modify the client code to remove the filtering logic and add it to the server read script.  Then I will show you how to modify the C# Windows Phone sample to take advantage of these views.

Follow along with me to get started!

Create a new Mobile Service and follow the steps to create your TodoItem table and download and run a new Windows Store app (C#).

Ensure you can add items and mark several of them complete.

Create a new Windows Phone app and ensure you can see the data you see in the store app and it is the same (completed items should be hidden).

 

Modify your code in the Windows Store app to remove the client logic

Open Mainpage.xaml.cs and remove the filtering logic when you read the table in RefreshTodoItems:

private async void RefreshTodoItems()
        {
            MobileServiceInvalidOperationException exception = null;
            try
            {
                // This code refreshes the entries in the list view by querying the TodoItems table.
                // The query excludes completed TodoItems
                items = await todoTable.ToCollectionAsync();
            }
         

Run your app to verify that even the items in your list appear briefly but then go away!  Put a breakpoint on CheckBoxComplete_checked to see why they appear briefly.   Leave this breakpoint in place to verify after you modify the server read script, you are not retrieving completed items (you will not hit this breakpoint after the server side change).

Now, go to your DATA tab in your mobile service, click on your TodoItem table and choose the SCRIPT tab.  Choose the Read script from the dropdown and we will move the login to only return completed items (since that is the only thing we need to read in our app anyhow).

function read(query, user, request) {
    query.where({ complete: false });
    request.execute();

}

Test you Windows Store app with the breakpoint still set on CheckBoxComplete_checked to verify you are not longer retrieving complete items.

Now go to your Phone application and remove the filter from RefreshTodoItems() like you did in your Windows Store app and test this code!

private async void RefreshTodoItems()
        {
            // This code refreshes the entries in the list view be querying the TodoItems table.
            // The query excludes completed TodoItems
            try
            {
                items = await todoTable.ToCollectionAsync();
            }

 

You have now successfully moved your client logic server side!

Obviously this is a super simple example of moving Client Logic server side.  You would want to do this whenever you have a complex query as well so that you do not burden each of the client platforms (I only showed you two) with implementing the same logic.  In my next post I will show you how to implement the same Server side logic to access complete items only in the read form TodoItem but in a dummy table so that you do not modify the TodoItem table.

 

Let me know if this was useful to you!

 

-Jeff

Using Virtual Tables for Different Views – Windows Azure Mobile Services

$
0
0

Building on my last post (Move Your Client Logic to the Server - Windows Azure Mobile Services) I will show you how to create a Virtual (or dummy) table to give you a different view of your TodoItem table.  This Virtual table will not contain any records however.

In this case, let’s assume you did not want to change your TodoItem table read script because you do need the full table with complete items elsewhere in your application.

Start by returning the read script back to it’s original form.

Navigate to the TodoItem read script and hit the ‘Clear’ icon at the bottom of the page to restore the script:

image

 

Your Read script should only contain the request.execute(); method as it originally did.

Next define a new table called ‘todoitemcomplete’ by choosing the CREATE icon in the DATA tab:

image

Be sure to set the appropriate permission levels as well

 

image

Next we will modify the four server scripts to use the TodoItem table and not the newly created table for their operations.

Here is the read script (actually the only one used in my example):

 

function read(query, user, request) {

    var todoItemsTable = tables.getTable('TodoItem');
    todoItemsTable.where({ complete: false }).read({ success: respondOK });
    function respondOK(results) {
        request.respond(statusCodes.OK, results);
    }

    // no! request.execute();
}

The next step is to setup for reading from this dummy table an mainpage.xaml.cs:

 

//Strongly typed class for dummy table is same structure as old table
    public class TodoItemComplete: TodoItem
    {
        
    }

    public sealed partial class MainPage : Page
    {
        //Changed the items collection to the new class
        private MobileServiceCollection<TodoItemComplete, TodoItemComplete> items;
        //Added a reference to the dummy table 
        private IMobileServiceTable<TodoItemComplete> todoTableComplete = App.MobileService.GetTable<TodoItemComplete>();
        //For now... keep a reference to the old table for Update and Insert operations
        private IMobileServiceTable<TodoItem> todoTable = App.MobileService.GetTable<TodoItem>();

 

Fix up any references that used a TodoItem in this collection by casting to a TodoItemComplete such as this:

  items.Add(todoItem as TodoItemComplete);
items.Remove(item as TodoItemComplete);
 

And change the RefreshTodoItems() to use the new todoTableComplete:

private async void RefreshTodoItems()
        {
            MobileServiceInvalidOperationException exception = null;
            try
            {
                // This code refreshes the entries in the list view by querying the TodoItems table.
                // The query excludes completed TodoItems
                items =  await todoTableComplete.ToCollectionAsync();
                //items = await todoTable.ToCollectionAsync();
            }

 

Now you have a Virtual table that will give you a view of complete items only with the logic on the server.

Further Discussion

I only discussed the Read script but you can extend this to the other scripts.

This has the downfall that the query parameters passed to the Read (if any) are difficult to extract and pass on to the table read.

A better option may be to use parameters in the query for the special cases (see my next post).

Let me know if this was useful to you!

 

-Jeff

 

 

Ref: http://www.windowsazure.com/en-us/develop/mobile/how-to-guides/work-with-server-scripts/#access-tables

How to take a System.Net trace from Windows Store applications (Developer Preview)

$
0
0

In desktop applications and services we frequently take System.Net traces to diagnose issues using the HttpWebRequest class, HttpListener, sockets, smpt etc… (and now the HttpClient classes).  We traditionally use the application configuration file (appname.exe.config) to enable the tracing.  The config file is read and the tracing parameters are used to trace the information we find useful.   Windows Store applications do not have configuration files however so you cannot use the application configuration file to take the trace.

The good news is that you can go further up and put your tracing settings in the machine.config file!  The one minor issue is that any process using system.net will be included in the trace file if it starts after you make the change.  If you use my trace file it logs the process and time so you can use that to filter the trace information see: My Favorite System.Net trace configuration file dumps Process ID and Date Time Information .

Here are the steps:

You will be making changes to the machine.config file.  If you mess this up, you could keep .NET framework applications from running so be SURE you make a copy of the file that you can restore after you have gotten your trace!  If you are using a 64 bit build you make the config changes in the Framework64 tree.

    • Save a copy of C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config because you will be modifying this file (or C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config if your image is a 64 bit build)
    • Open Notepad as an Administrator (right mouse click or press and hold with touch and choose ‘Run as Administrator’
    • From your Administrator Notepad open: C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config (or C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config if your image is a 64 bit build)
    • Add the normal System.Net tracing setup at the bottom of the file before the </configuration> tag (see above link)
    • Find this section in the text you just added to machine.config:
      <add
      name="System.Net"
      type="System.Diagnostics.TextWriterTraceListener"
      initializeData="System.Net.trace.log”
      traceOutputOptions = "ProcessId, DateTime"
      />
      • Change the path and file name of initializeData to “c:\temp\network.log” (or a path of your choosing)
        <add
        name="System.Net"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="c:\temp\network.log”
        traceOutputOptions = "ProcessId, DateTime"
        />
      • Save the file
      • Create the directory c:\temp\ (or if you chose a different directory go to that), and give the local user named “ALL APPLICATION PACKAGES” full control of the directory.  To do this:

        a. Right click on the c:\temp folder and select properties
        b. Click on the security tab
        c. Hit the Edit button
        d. Hit the Add button
        e. Hit the Locations... button and change the location to the very top item (the name of your computer)
        f. In the space below Enter the object names to select add ALL APPLICATION PACKAGES and hit Check Names
        g. Hit OK and check Allow, Full control for the ALL APPLICATION PACKAGES and then hit OK again to apply your changes

          1. Start your application and recreate the issue you wish to trace, and close your application
          2. Restore the machine.config file from the copy you created in step 1

          You can then analyze the trace as you would in the past!

          Please let me know if you have found this useful or have any questions.

          Where is the Windows 8 Product key?

          Client and Server certificates in Windows Store applications

          $
          0
          0

          I answered a couple of certificate questions in the C# Windows Store applications forum that you all may find useful:

          Provide Client side certificate:

          http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/0d005703-0ec3-4466-b389-663608fff053

          Include Server certificate in manifest so application can
          trust an non-trusted or self-issued server certificate:

          http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/5ec17748-8980-4714-b25a-c3c9192bbefc

           

          Great video describing SelfSigned certs and embedding it in an app:

          http://channel9.msdn.com/Events/Build/2012/3-127  See at 0:36 - 0:42 for the SSL part.

           

           

          How do I figure out what the hex error codes from WinJS.xhr are?

          $
          0
          0

          These codes are hex representations of the underlying WinINet error codes.  You can use calc to translate the code from hex to decimal and then look up that error here:

          http://support.microsoft.com/kb/193625

          To use calc bring up the calculator by hitting the Windows key and typing calc.  Then Alt+3 (or use the view menu) to change to programmer mode.  Ensure the 'Hex' radio button is selected and input the hex code.  Then choose the 'Dec' radio button to get the decimal version.

          -Jeff

           

          Windows 8 Video Driver for Inspiron 1521 - Radeon Xpress 1270

          $
          0
          0

          I have an old (circa 2007) Dell Inspirion 1521 laptop and wanted to get a better Video driver installed for Windows 8.  I found a Vista 64 bit driver on the Dell site that seems to work very well (compared to the generic drivers): http://www.dell.com/support/drivers/us/en/19/DriverDetails/DriverFileFormats/Product/latitude-d531?DriverId=X2T0W&FileId=2731098358&urlProductCode=False

          When you get to the installer, ONLY install the drivers.  Do not install the catalyst stuff (it will make your CPU max out with an ati service).  I had some errors installing but the display now supports full resolution and the graphics speed is much faster!  I also upgraded to the latest bios available and gave the system the max memory I could for graphics (I had plenty to give because I have 4G Ram installed).

           

          Let me know if this helps you!


          Building Package for the Windows Store–The package contains a Debug framework reference

          $
          0
          0

          I was helping a customer with a problem they were encountering when trying to build a package for submission to the Windows App Store.  The error was:

          “The package contains a Debug framework reference”.  To make a long story short the solution is simple.

          The problem was that even though the project was set to Release for the solution configuration (in the Configuration Manager), the Project (here ‘CanvasSize’) configuration was set to Debug.

           

           

          image

           

          The fix is simple!  Just change the Configuration for the Project and any other project in the solution to Release!

          image

           

          Let me know if this help you by adding a comment!

          -Jeff

          Portable Class Library error when building a Windows Phone 8, Windows Store app library

          $
          0
          0

          I had a customer issue that I thought I would share in the event you run into this issue (it may save you some heartburn).

          Here is the error:

          The "Vbc" task failed unexpectedly.
          System.Runtime.InteropServices.COMException (0x80004005): Unable to find required file 'Microsoft.VisualBasic.dll'.

           

          The repro of this is as follows:

          With WP8 SDK and VS2012 Pro or above installed:

          1. Create a new Visual Basic Portable Class Library

          2. Choose .NET 4.5, Windows Phone 8, and Windows Store apps as the targets (or if you leave Windows Store apps unchecked)

          3. Build project

           

          The solution is quite simple and should be in the next release of Visual Studio 2012

          1. Close Visual Studio

          2. Open the vbproj file with a text editor like notepad

          3. Find the first entry <ProjectTypeGuids> and after the closing tag add: <VBRuntime>Embed</VBRuntime>

          Example: 

              <ProjectTypeGuids>{14182A97-F7F0-4C62-8B27-98AA8AE2109A};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids>
              <VBRuntime>Embed</VBRuntime>

          4.  Rebuild the project

           

          Let me know if this helped you!

          Peace,

          Jeff

          ATL Library and Windows Store apps

          $
          0
          0

          Just a quick post in case you run up against this issue.

          You can use a subset of ATL Library code in your Windows Store app.  You may run into errors with validation when compiling or when running the Windows App Certification Kit (WACK) tool.

          If you include CComCriticalSection in your Windows Store app code and then run the WACK tool you will get these errors:

          Error Found: The supported APIs test detected the following errors:

          • API GetModuleHandleW in kernel32.dll is not supported for this application type. XXXXX.XXX calls this API.
          • API InitializeCriticalSectionAndSpinCount in kernel32.dll is not supported for this application type. XXXXX.XXX calls this API.

          This is caused by a bug in the current ATL Library.  The workaround is to add this code to your project which will implement the correct code (add it to any of your CPP files):

          #if (_ATL_NTDDI_MIN >= NTDDI_VISTA)

          namespace ATL {

          BOOL _AtlInitializeCriticalSectionEx(__out LPCRITICAL_SECTION lpCriticalSection, __in DWORD dwSpinCount, __in DWORD Flags)
          {
               return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags); 
          }

          }
          #endif

          Let me know if this helped you out!

          -Jeff

          Windows Store Developer Solutions blog!

          How To: Send and Expire a Tile Notification from Mobile Services Server Scripts

          $
          0
          0

          We document how to send push notifications using Mobile Services fairly well.  You can use the wns object and push the notification.  This is documented here:

          Get started with push notifications in Mobile Services 

          Push notifications to users by using Mobile Services

          What is not documented until now is how to expire the notification after a certain time period.  This is actually very easy (especially now that I have documented it)!

          What you want to do is to pass this header: X-WNS-TTL and the number of Seconds you wish this notification to live.  Here is an example of how to do this:

           

          push.wns.sendTileSquareBlock(
             item.channel,
             { text1: item.id, text2: item.text },
             {
                 headers: { 'X-WNS-TTL': 30 },
                 success: function (error, result) {
                     console.log(error);
                     console.log(result);
                 }
             });

          This example will expire the tile 30 seconds from now.  The key here is that the second object passed now has the headers option specified (https://github.com/tjanczuk/wns).

          Here is some further documentation on that header:

          Push notification service request and response headers - X-WNS-TTL

           

          Let me know if this helps!

          How To: Decode Event Viewer logs to see What Tile Notification data is

          $
          0
          0

          Using Push Notifications for my Windows Store app I needed to debug what message was being received for my Tile Notifications.  The payload however was just a hex blob and THAT wasn’t too useful.  Here is what I did to find the payload and see what was in it.

          Using the Event Viewer you can enable (if it isn’t already) the Push Notifications logging.

          To enable and view open the event viewer

          • Hit the Windows key and then type: event viewer (click on Event Viewer).
          • Then expand this tree: Application and Services Logs/Microsoft/Windows/PushNotifications-Platform/Operational
          • Right click on this node to enable or disable logging at this level. 
          • Once it is enabled, send the push notification (however you are doing it).

          To filter on the tile notification messages

          • Click on the Operational Node and choose ‘Filter Current Log…’ from the Actions pane on the right side.
          • Click on the ‘XML’ tab and check the box ‘Edit query manually’
          • Paste the below query in (cut from here paste into notepad and copy and paste from notepad):

          <QueryList>
            <Query Id="0" Path="Microsoft-Windows-PushNotification-Platform/Operational">
              <Select Path="Microsoft-Windows-PushNotification-Platform/Operational"> *[System[Provider[@Name='Microsoft-Windows-PushNotifications-Platform'] and (EventID=1225)]] and *[EventData[Data[@Name='Verb'] and (Data='NFY')]]</Select>
            </Query>
          < /QueryList>

           

          • Hit the ‘OK’ button

          You now will have a list of the notifications sent and the payloads.

          You can browse the notifications that have been received, but the ‘Payload’ is where the encoded tile data is.

          To view the payload click on an event and select the ‘Details’ tab and hit the ‘XML View’ radio button.  Then scroll down to the <EventData> section and find the <Data Name="Payload"> section.  That string is the message sent to windows!

          To decode the message you can use a public hex to string decoder or this handy Power Shell script.  Replace the string in ‘’ with the payload:

          # paste Hex string you want to convert here
          $hexstring='5469…’

          # size of char array
          $hexcharcount = $hexstring.Length

          # position in hexstring
          $i = 0

          $output=$null
          # get every two chars and convert to ascii
          while ($i -le $hexcharcount -1) {
              $output = $output + [Char][Convert]::ToInt32($hexstring[$i] + $hexstring[$i + 1] ,16) 
              $i = $i + 2
          }

          $output 

          Sample output:

          Time: 2013-03-13T14:12:20Z
          Channel: 1;17014027897125354927
          Type: wns/tile
          Msg-Id: 107904C1BDA0828

          <tile><visual><binding template="TileWideSmallImageAndText02"><image id="1" src="images/widget2_thin_25.png"/><text id="1">≈17 mi</text><text id="2"></text><text id="3">30% Intensity</text
          >< text id="4">2% Area</text><text id="5"></text></binding><binding template="TileSquarePeekImageAndText01"><image id="1" src="images/widget2_thin_25_small.png"/><text id="1">≈17 mi</text><
          text id="2"></text><text id="3">30% Intensity</text><text id="4">2% Area</text></binding></visual></tile>

          So how do you find tile notifications just for your app?

          Get your App identity from and search for it.  I use this tool from Fiddler.  Look for the Display name and you want to copy the ‘AC Name’ by clicking on the ‘AC Name’ and choose ‘Copy selected column…’

           

          Go back to the filter and replace the AppUserModelId with your app id and append ‘!App’ (cut from here paste into notepad and copy and paste from notepad):

          <QueryList>
            <Query Id="0" Path="Microsoft-Windows-PushNotification-Platform/Operational">
              <Select Path="Microsoft-Windows-PushNotification-Platform/Operational"> *[System[Provider[@Name='Microsoft-Windows-PushNotifications-Platform'] and (EventID=1010)]] and *[EventData[Data[@Name='AppUserModelId'] and (Data='44083JeffAndDeeSoftware.jsandersPushDemo_x5q5wcd24ndqc!App')]]
              </Select>
            </Query>
          < /QueryList>

          Now you will see the ‘1010’ events associated with the tile update for your app!

          You can note the time of the ‘1010’ event, clear the filter and look for the next event that is a 1225 event and that will most likely be the tile notification with the Payload that you can decode using the first method I specified.

          Closing notes

          The ‘General’ tab will give you a good idea of what the various log entries are.  You can use the ‘XML’ tab to drill into the message.  Enable and look through this event log.  You will see all sorts of notifications related to establishing a channel and receiving push notifications.  If you see any errors you can drill into them here.  Happy Push Notifying!

          Let me know if this was helpful!

          Server Script to Insert Table Items in Windows Azure Mobile Services

          $
          0
          0

          I needed a script to load a database with dummy items.  I created a Scheduler script with a simple loop to insert 1000 items into my table.  I found that when I ran this script it would kick off and seemingly never complete.  What was worse, my service was returning a 500 internal server error when I tried to hit it!

          The underlying problem is that a Mobile Service running in free mode (the default configuration) throttles the number of connections that can be made and in a tight loop, you can quickly exceed that and put the service in a bad state.  The solution is to wait for previous inserts to complete before inserting new items.  You can safely insert a batch of items (say 10) and once that is complete submit another batch of insert operations to avoid this connection limit.

          Let’s create a script, step by step and discuss it so you can apply the same logic to your situation.

          In my example I am using Scheduler but you may have similar logic in an Insert or Update script.

          The problem script

          First the problem script (THIS WILL NOT WORK – DO NOT RUN THIS SCRIPT):

           

          image

          The issue is that line 11 executes asynchronously and we quickly run out of connections!

          Let’s discuss a scheme to work around this async behavior and connection limit.

          Building a script to solve the issue

          In this script we will insert the same 1000 records but do this in batches of 10.  When we are done inserting the batch of 10, we will kick off another batch of 10 until we have completed the task.

          I changed the script and started out by defining some variables and calling a yet to be defined function ‘insertItems’

          image

           

          Note the comments and what we are using them for!

          Next we will define the ‘insertItems’ function.  Note that this function only inserts 10 records (the value I chose for batchSize)!  We will need to do some more work to kick off the next batch of inserts!  The insert method call on the table takes an Object as the second parameter.  This object defines two members:  success: and error:.  I set each of these members to point to functions that will be called on success or error from the insert operation on the table.

          image

           

          Now we need to actually add the success and error callback functions.  The first (insertComplete) is called if there were no errors during the insert.  It will have the logic to see if we have completed the current batch.  If we have completed inserting the records in the batch and have more records to process, we will call insertItems again to process the next batch.  To track the number of items we have completed in the batch we also define a variable to track that!  The second (errorHandler) will keep track of the error count then call insertComplete to use it’s logic for determining if we need to kick off a new batch or not.

           

          image

           

          Note:  You have to define the success and error functions before you use them in the insert function.  If you do not you will get an error similar to this:

          Error in script '/scheduler/testLoad.js'. Error: Invalid callback options passed to 'insert'. Callback options must be an object with at least one 'success' or 'error' property of type 'function'.

          Putting it all together

          Assembling all of these pieces you can now test the script.  If it is a Scheduler script you can configure it as an ‘On demand’ script and run once.  Then check the log to ensure your records were processed.  Any script errors will show up in the Mobile Services log as well.

          Once you develop your script, you need to TEST, TEST and then of course TEST AGAIN.  Check the boundary conditions (0 records, 1 record, 999 records) for whatever is inside and outside your expected conditions.  Along with what I have discussed, you need to adapt this logic to your situation.  For example, if you are not generating dummy data this won’t work for you!  You will be able to study the logic however and apply it to your situation.  The key parts are the success and error functions that allow you to detect when you have processed the current batch and how to kick off the next batch.  You will also need to determine when you have reached the end of your processing to stop batching and log the results!

          Complete Code Listing

          You should type all of this in yourself so you don’t become a cut and paste programmer.  However… I do it too Winking smile

          Special thanks to Paul Batum who helped me with this problem!

          Code listing for sample (Copy Code):

           
          function testLoad(){ 
              //Write to my service log 
              console.info("Running 'PrePopulateTable' job."); 
              
              
              // The table we will be inserting into var todoTable = tables.getTable('TodoItem'); 
              // The number of records to insert at a time (to avoid blowing our connection limit) var batchSize = 10; 
              // The number of records I want to generate dummy data for var recordsToInsert = 1000; 
              // The number of records processed var totalCount = 0; 
              // The number of insert failure var errorCount = 0; 
            
          // Start inserting items! 
              insertItems(); 
            
          // define the insertItems function function insertItems() { 
                  
                  // local var shared with the insertComplete callback function. // This is scoped to this function so if the function is called again // it will be reset to 0 var batchCompletedCount = 0; 
            
           
                  // insertComplete is called for each record inserted into the table // called when the insert completes async. Also called by the errorHandler callback var insertComplete = function() { 
                      // increment the number of records we have completed the insert call for 
                      batchCompletedCount++; 
                      // increment the total number of records processed 
                      totalCount++; 
                      // if we have completed all of the records in this current batch // or don't have any more records to process we either... if(batchCompletedCount === batchSize || totalCount === recordsToInsert) {                        
                          if(totalCount < recordsToInsert) { 
                              insertItems(); // kick off the next batch 
                          } else { 
                              // or we are done // report the status of the job to the log and don't do any more processing 
                              console.log("Job 'PrePopulateTable' complete. %d Records processed. There were %d errors.", totalCount, errorCount); 
                          } 
                      } 
                  }; 
                  
                  // called if there was an error doing the insert var errorHandler = function(err) { 
                      // I want to track the number of errors for reporting, // you may want to do something different here 
                      errorCount++; 
                      console.warn("Ignoring insert failure as part of batch.", err); 
                      // call insertComplete simply to use the logic to track the batch count, // total count and kick off the next batch if necessary. // you may want to do something different! 
                      insertComplete(); 
                  }; 
                       // insert some items! for(var i = 0; i < batchSize; i++) { 
                      // num is used to generate some unique dummy data var num = totalCount + i; 
                      // dummy data item to insert var item = { text: "This is Item number: " + num }; 
                      //This table insert completes async so we have a success and error callback set of functions // defined that will be called when the insert completes 
                      todoTable.insert(item, { 
                          success: insertComplete, 
                          error: errorHandler 
                      }); 
                  } 
             
          
              } 
          }
            

           

          End code listing

           

          Helpful Links

          Schedule recurring jobs in Mobile Services

          Validate and modify data in Mobile Services by using server scripts

          Debugging your Mobile Service scripts

          Forum for Windows Azure Mobile Services' projects, problems, and questions

          Be sure to follow me on Twitter @jsandersrocks and my team @WSDevSol

          Let me know if this was useful to you!


          How to: Add a ‘Copy Code’ Link to Your Blog Post and Colored Code Blocks

          $
          0
          0

          A nice touch to your blog is to have a link to copy the code you have entered.  Another great feature is to have your code colored as it would be in Visual Studio.  There a couple of ways you can do this.  Here is how I prefer to do it!

          LiveWriter Plug-in for code formatting

          I use LiveWriter so I love to use Plug-Ins when appropriate.  There are some plugins to make code pretty but some require <style> definitions.  The MSDN blogs parse out these styles so you end up having to manually adding these styles to your blog’s theme (yuck).

          Install plug-in

          In LiveWriter, go to the ‘Insert’ tab and choose ‘Add plug-in’

          image

           

          Once there filter by ‘Formatting / clipboard’ and choose ‘Paste from Visual Studio’

          image

          Hit the download button, then run the installer.

          Now close and restart LiveWriter (don’t forget to save your work).

          Use the Plug-in

          To use this plugin:

          • Copy the code you want from Visual Studio
          • From the ‘Insert’ tab choose the ‘VSPaste’ plug-in (highlighted for you here:

           

          image

          Result:

           

              app.addEventListener("activated", function (args) {
                  if (args.detail.kind === activation.ActivationKind.launch) {
                      if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                          // TODO: This application has been newly launched. Initialize
                          // your application here.
                      } else {
                          // TODO: This application has been reactivated from suspension.
                          // Restore application state here.
                      }
          
                      if (app.sessionState.history) {
                          nav.history = app.sessionState.history;
                      }
                      
                      args.setPromise(WinJS.UI.processAll().then(function () {
                          if (nav.location) {
                              nav.history.current.initialPlaceholder = true;
                              return nav.navigate(nav.location, nav.state);
                          } else {
                              return nav.navigate(Application.navigator.home);
                          }
                      }));
                  }
              });
          

           

          Note:  If you disable any plug-in, installing it will not make it show up in the plug-in list.  Simply re-enable it.

          Add a Copy Code link

          You can of course sweep out code and copy it from the page.  I like to provide a ‘Copy Code’ link so I can ensure the blog reader gets all of the code correctly from me (and it is cool).

          To do this you simply need to add a little JavaScript and a give a unique name to the block around the code you just pasted into the document.

          How to add the Copy Code JavaScript to your page

          • Click on the ‘Source’ tab at the bottom LiveWriter and then scroll all the way to the top of the page.
          • Insert this script at the top
          Copy Code:
          <SCRIPT language=jscript>
              function CopyCode(elemName) {
                  var obj = document.getElementById(elemName);
                  window.clipboardData.setData("Text", obj.innerText);
              }
          </SCRIPT>
          

            How to use the JavaScript and add Copy Code links

             

            • Still in the Source view, find the code you want to add the Copy Code link to (hint, if you used the VSInsert plug-in it will start with <pre class="code"> and end with </pre>
            • Give this block of text a unique id.  This id has to unique to your entire blog as well as this page because on your blog home page there may be more than just your current blog with a copy code section (and you would get the wrong one potentially). 

             

            <pre id="CopyCodeCodeSection1" 
            • Insert the Copy Code link and use the same id with the link handler like this

             

            <strong><a href="javascript:CopyCode('CopyCodeCodeSection1');">Copy Code:</a></strong> 
            
          • Add more Copy Code buttons to your code and ensure you increment the name each time for the code id and the text for the javascript (CopyCodeCodeSection2, CopyCodeCodeSection3, CopyCodeCodeSection4, etc…)
            • Save your blog as a draft and see how it works!
            • Note: You will see my ‘Copy Code:’ text has a lightgray background.  I did this by styling the <a> tag like this:
            <strong>
            <
            a style="background: lightgray;" href="javascript:CopyCode('CopyCodeCodeSection1');">Copy Code:</a>
            </
            strong>

             

            Summary

            You can feel free to change the formatting or style of you Copy Code: link!  I hope you find this useful so drop me a note if you like it!

            @JsandersRocks, @WSDevSol

            Helpful links

            Windows Live Writer

            Install point for 'Paste from Visual Studio'

            Using Parameters with Tables for Different Views – Windows Azure Mobile Services

            $
            0
            0

            In my two previous posts I discussed how to move your table filter logic server side, and how to use Virtual tables to get different views of data.  In this blog post I will show you how to pass parameters to you read script to get different views of the data.

            In this example, the default view of this table will be to filter the complete items (since my services all require this as a default view) and still expose a way to get the unfiltered data back if I wish.  This will also preserve the query and select parameters passed to the read in the event I wish to use those!

            Server Script

            The server script will use a jump table to execute a code path based on the parameter passed in.  It also has stubbed out another operation to show how this would be done.

            function read(query, user, request) {
                //console.log(request.parameters.operation);
                var dispatch = {
                    op1: operation1,
                    nofilters: operation2,
                }
            
                //doesn't return valid JSON but shows how you might 
                // execute another function based on different parameters passed in
                function operation1(query, user, request) {
                    request.respond(200, "this result is from operation1");
                }
            
                // no server side filter applied 
                function operation2(query, user, request) {
                    request.execute();
                }
            
                // if we have parameters and a matching entry in the jump table we have defined
                // dispatch it!
                if (request.parameters.operation && dispatch.hasOwnProperty(request.parameters.operation)) {
                    dispatch[request.parameters.operation](query, user, request);
                    return;
                }
                else // otherwise execute the default logic I have defined.
                {
            
                    query.where(function () {
                        return this.complete === false && this.createdAt !== null;
                    }
                    );
            
            
                    request.execute({
                        success: function (results) {
                            results.forEach(function (item) {
                                delete item.createdAt;
                            }
            
                            );
                            request.respond();
                        }
                    }
            
                    );
                }
            }

             

            Client Code:

            private async Task<string> RefreshTodoItems()
                    {
                        string aStr = "MyString";
                        MobileServiceInvalidOperationException exception = null;
                        try
                        {
                            // This code refreshes the entries in the list view by querying the TodoItems table.
                            // The query excludes completed TodoItems
            
                            Dictionary<string,string> parameters = new Dictionary<string,string>();
                            parameters.Add("operation","nofilters");
            
                            items = await todoTable.WithParameters(parameters).ToCollectionAsync();
                        }
                        catch (MobileServiceInvalidOperationException e)
                        {
                            exception = e;
                        }
            
                        if (exception != null)
                        {
                            await new MessageDialog(exception.Message, "Error loading items").ShowAsync();
                        }
                        else
                        {
                            ListItems.ItemsSource = items;
                        }
                        return aStr;
                    }
            

             

            You should be able to see how you could extend this to do things like execute a SQL statement passed in as a parameter!

            Let me know if you find this useful,

            Jeff

            Use PasswordVault to Store Your Tokens–Windows Azure Mobile Services

            $
            0
            0

            There was no end to end sample of how you might use the PasswordVault to store your JWT used for user authentication in Mobile Services.  I created this class to be used with your Windows Store app.

            Copy Code:
            using Microsoft.WindowsAzure.MobileServices;
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using Windows.Security.Credentials;
            
            namespace MobileServices.Samples.Authentication
            {
                class AuthProviderVault
                {
                    MobileServiceClient _mobileService = null;
                    private PasswordVault providerVault = null;
            
                    public AuthProviderVault(MobileServiceClient mobileService)
                    {
                        // PasswordVault is specific to this Windows Store app
                        providerVault = new PasswordVault();
                        // Set to the application MobileService
                        _mobileService = mobileService;
                    }
            
                    // Use the MobileService login
                    public async Task<MobileServiceUser> LoginUser(MobileServiceAuthenticationProvider provider)
                    {
                        MobileServiceUser user = null;
                        //There should be a MobileService attached!
                        if (_mobileService != null)
                        {
                            try
                            {
                                // Clear the CurrentUser
                                _mobileService.CurrentUser = null;
                                // Use the OAuth Login for the provider
                                user = await _mobileService.LoginAsync(provider);
                                // Have user will add!
                                addToVault(provider, user);
                                //  Set the current user
                                _mobileService.CurrentUser = user;
                            }
                            catch (InvalidOperationException exLogin)
                            {
                                string error = "An error occurred during login. Login Required. Message: " + exLogin.Message;
                                user = null;
                            }
            
                        }
                        // might be null
                        return user;
                    }
            
                    // Will use the user JWT stored in the vault or go to LoginUser
                    public async Task<MobileServiceUser> GetOrLoginMobileServiceUser(MobileServiceAuthenticationProvider provider)
                    {
                        MobileServiceUser userReturned = getStoredMobileServiceUser(provider);
            
                        // See if there is a user stored in the vault use it otherwise
            // call LoginUser (which will also store the user in the vault)
            if (userReturned == null) { userReturned = await LoginUser(provider); } //userReturned could still be null if the user does not login _mobileService.CurrentUser = userReturned; return userReturned; } // adds a provider based User to the vault or replaces and existing one private void addToVault(MobileServiceAuthenticationProvider provider, MobileServiceUser user) { IReadOnlyList<PasswordCredential> creds = null; try { // Will throw an exception if none found (I hate that design) creds = providerVault.FindAllByResource(vaultKey(provider)); } catch (Exception) { //expect an exception if not found in container } // remove existing creds (there should be only one if this is the only access to the App PasswordVault if (creds != null) { foreach (PasswordCredential cred in creds) { providerVault.Remove(cred); } } // Create a new cred and add it to the vault PasswordCredential newCred =
            new PasswordCredential(vaultKey(provider), user.UserId, user.MobileServiceAuthenticationToken); providerVault.Add(newCred); } private string vaultKey(MobileServiceAuthenticationProvider provider) { return provider + ":" + _mobileService.ApplicationUri.DnsSafeHost; } private MobileServiceUser getStoredMobileServiceUser(MobileServiceAuthenticationProvider provider) { // if found in the vault return the mobile service user with info MobileServiceUser userReturned = null; try { PasswordCredential userCred = null; IReadOnlyList<PasswordCredential> creds = providerVault.FindAllByResource(vaultKey(provider)); if (creds != null) { // In my code there should ONLY be one cred per provider so problably should check that. userCred = creds[0]; // Create a User to use with the Mobile Service (instead of doing the login sequence) userReturned = new MobileServiceUser(userCred.UserName); // Explicitly fetch the PWD into memory userCred.RetrievePassword(); // Set the JWT userReturned.MobileServiceAuthenticationToken = userCred.Password; // remove from memory userCred = null; } } catch (Exception e) { // if there was an exeption, eat the error userReturned = null; } return userReturned; } } }

             

            This is pretty easy to used.  I modified our Auth Sample to use this with each of the providers.  Here is an example from Scenario1.xaml.cx:

            Copy Code:
            private async void Launch_Click(object sender, RoutedEventArgs e)
                    {
                        try
                        {
                            AuthProviderVault vlt = new AuthProviderVault(App.MobileService);
                            MobileServiceUser user = 
            await vlt.GetOrLoginMobileServiceUser(MobileServiceAuthenticationProvider.Facebook); if (user != null) { this.OutputPrint(string.Format("You are now logged in - {0}", user.UserId)); App.MobileService.CurrentUser = user; } else { this.DebugPrint("An error occurred during login. Login Required."); } } catch (InvalidOperationException) { this.DebugPrint("An error occurred during login. Login Required."); } }
            When you attempt to use a table you could fail with an Unauthorized exception.  If this does happen simply clear the old credential for the provider you are using and call LoginUser to get and store new credentials in the vault.

             

            Copy Code:
            try
                        {
                            items = await todoTable.ToCollectionAsync();
                        }
                        catch (MobileServiceInvalidOperationException msEx)
                        {
                            if (msEx.Response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                            {
                                AuthProviderVault vlt = new AuthProviderVault(App.MobileService);
            
                                // LoginUser goes right to the OAuth Login and then stores the user info in the vault
                                MobileServiceUser user = await vlt.LoginUser(MobileServiceAuthenticationProvider.Facebook);
                                if (user != null)
                                {
                                    // user has been set on the MobileService so retry the query up to x times here!
                                }
                                else
                                {
                                    // user could have denied to login and hit the back button
                                }
                            }
                        }
            

            You can see the credentials (and remove them) in the credential manager after you have stored them:

            image

             

            This should get your ideas flowing and if this helps let me know!

            Attaching to a Windows Azure Mobile Services database in ASP.NET

            $
            0
            0

            The preferred way to talk to the database you are using for you Windows Azure Mobile Services is through the REST APIs and by using the Clients we supply for you.  The reason you should go through the REST APIs is to ensure you are hitting the Scripts you defined in your Mobile Service.  I had a case where someone wanted to directly connect to the SQL Azure database in the backend to list data in a grid view.  The call would fail with this error: “invalid object name‘tablename’" where ‘tablename’ was the name of the table in the SQL Azure database.

            The fix was very simple if you understand how database tables are created for Mobile Services.   Have you ever wondered for instance how you can have several Mobile Services with ‘TodoItem’ tables in them and they are all hosted in the same SQL Azure database?  The reason this works is because we use the schema property of the database to scope the table to the Mobile Service.  If I have two mobile services ‘JeffMobileFirst’ and ‘JeffMobileSecond’ both with a ‘TodoItem’ table and look in the SQL Azure database you will see tables ‘JeffMobileFirst.TodoItem’ and ‘JeffMobileSecond.TodoItem’.  To access the database table of either simple ensure you include the schema along with the table name.  For example:

            string sql = "select * from JeffMobileFirst.TodoItem";

            SqlConnection connection = new SqlConnection(@"Server=tcp:x0etablf0pp.database.windows.net,1433;Database=jsanders_db;User ID=dbadmin@x0etablf0pp;Password=mypassword;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;");

             

            Let me know if this helped you!

            How To: Popup a XAML WebView UI async and wait for results

            $
            0
            0

            I needed to popup a WebView and wait on an event before continuing.  There really was no illustration on how to do this so here you all go!

            In my scenario I wanted to Navigate to a Uri to do some forms authentication and get some cookies loaded.  I knew when I was redirected to a certain Uri the cookie was loaded.  To leverage the WebForms based UI I decided to use the WebView control.  I would navigate to the Uri to authenticate, then when the browser navigates to another know Uri I would close the browser and continue code execution.

            WebView.Navigate returns immediately so you cannot await this call.  What you need to do is wait on an event flag then continue execution.

            The code is relatively simple and well commented.  The key to awaiting this async is the line of code with the Task.Run call.  This spins off a thread that allows the UI to refresh.  To see the effect, remove the Task.Run and just await the AutoResetEvent.  You will see the UI freezes!

            Code

            Xaml

            <Page
                x:Class="AsyncWebUI.MainPage"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="using:AsyncWebUI"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                mc:Ignorable="d">
            
                <Grid  Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
                    <TextBlock VerticalAlignment="Top" HorizontalAlignment="Left" Margin="120,28,0,0" 
            Text="Wait for Event" FontSize="60"/> <Grid Margin="120,100,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" Margin="0,10" > <TextBox x:Name="theUri" Width="300" Text=http://blogs.msdn.com/wsdevsol
            Margin="0,5,5,5"></TextBox> <Button Content="Navigate" Click="Button_Click" FontFamily="Global User Interface" Margin="5">
            </
            Button> <TextBlock Text="Navigate to http://bing.com to close browser" HorizontalAlignment="Center"
            VerticalAlignment="Center" Margin="5,0,0,0"/> </StackPanel> <StackPanel x:Name="hidePanel" Grid.Row="1"> <TextBlock Text="Here is some stuff to hide while navigating" Height="100"></TextBlock> <TextBlock Text="Here is some stuff to hide while navigating" Height="100"></TextBlock> </StackPanel> <WebView x:Name="MyWebView" Grid.Row="1" Visibility="Collapsed"
            NavigationCompleted="MyWebView_NavigationCompleted"></WebView> </Grid> </Grid> </Page>

            C#

            using System;
            using System.Collections.Generic;
            using System.IO;
            using System.Linq;
            using System.Runtime.InteropServices.WindowsRuntime;
            using System.Threading;
            using System.Threading.Tasks;
            using Windows.Foundation;
            using Windows.Foundation.Collections;
            using Windows.UI.Xaml;
            using Windows.UI.Xaml.Controls;
            using Windows.UI.Xaml.Controls.Primitives;
            using Windows.UI.Xaml.Data;
            using Windows.UI.Xaml.Input;
            using Windows.UI.Xaml.Media;
            using Windows.UI.Xaml.Navigation;
            
            
            namespace AsyncWebUI
            {
                public sealed partial class MainPage : Page
                {
                    AutoResetEvent waitForNavComplete;
                    public MainPage()
                    {
                        this.InitializeComponent();
                        // Create AutoResetEvent initially not set
                        waitForNavComplete = new AutoResetEvent(false);
                    }
            
                    /// <summary>
                    /// async so we can wait for somethign before proceeding (whatever that may be)
                    /// </summary>
                    async private void Button_Click(object sender, RoutedEventArgs e)
                    {
                        // Hide XAML and bring up the WebView
                        hidePanel.Visibility = Visibility.Collapsed;
                        MyWebView.Visibility = Visibility.Visible;
            
                        // Go to the site specified
                        MyWebView.Navigate(new Uri(theUri.Text));
            
                        // Wait for this AutoResetEvent to be Set
                        // If you just did the Wait the WebView would not come up and the UI would freeze
                        await Task.Run(() => { waitForNavComplete.WaitOne(); });
            
                        // Reset the event (unset it)
                        waitForNavComplete.Reset();
            
                        // Swap back the UI
                        MyWebView.Visibility = Visibility.Collapsed;
                        hidePanel.Visibility = Visibility.Visible;
                    }
            
                    void MyWebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
                    {
                        // I am waiting for a specific Uri.  When I see it...
                        if (args.Uri == new Uri("http://www.bing.com"))
                        {
                            // Reset the event so we close the browser and bring up the old XAML
                            waitForNavComplete.Set();
                        }
                    }
                }
            }
            

            Summary

            So it is fairly easy to do this.  The trick is really in the await Task.Run(() =>   call.  Please drop me a line if you find this useful!

            Viewing all 140 articles
            Browse latest View live


            <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>