HttpNotificationChannel Open() throwing InvalidOperationException ("Failed to open channel")

3.6k views Asked by At

I'm writing a Windows Phone 7 application which utilises Push Notifications and have a class which is responsible for managing interactions between the MS Notification Servers and my service in the cloud. However when I'm attempting to open the channel on my device HttpNotificationChannel is throwing an InvalidOperationException with the message "Failed to open channel". According to MSDN I should try opening the channel again.

My snippet of code to open the push notification is following the standard pattern of;

public class HttpNotification {
  private const string kChannelName = "MyApp.PushNotification";

  private HttpNotificationChannel _Channel;

  public void Register() {
    try {
      _Channel = HttpNotificationChannel.Find(kChannelName);
      if (_Channel == null) {
        _Channel = new HttpNotificationChannel(kChannelName);
        InstallEventHandlers();

        // This line throws
        _Channel.Open();
      } else {
        InstallEventHandlers();
      };
    } catch (InvalidOperationException ex) {
      MessageBox.Show(string.Format("Failed to initialise Push Notifications - {0}", ex.Message));
    };
  }
}

I'm not sure exactly what MSDN means by "try opening the channel again". I've wrapped the call to Open() in a try/catch and snoozing 5 seconds between attempts but it doesn't succeed. I've also tried the same approach around the entire method (ie. Do the call to HttpNotificationChannel.Find() each time it throws) to no avail.

I know this is a tad bit vague - but was wondering if anyone has any suggestions on handling this? This same code works flawlessly in the emulator, but fails every time on my actual device, even after an un-install and re-install of my application. Given that this is my actual phone, I'm a little reticent to do a hardware reset in the hope that it solves this issue, and don't feel comfortable releasing the application to the marketplace with this issue haunting me.

Update: An additional point, I'm using an unauthenticated channel, so there's no certificate installed for my cloud-based service.

Update #2: Further, I just tried deploying the Microsoft Phone Push Recipe to my device and it's also throwing the same exception.

2

There are 2 answers

3
Sam Basu On

@slaad .. here are few things that I would check, unless you have already tried these:

  1. Your actual device does have data connectivity, right? doh :)
  2. How are you storing an existing Channel in Isolated Storage? Make sure your Find() is working & that you are not trying to recreate a channel that exists leading to exception.
  3. Check if your Channel creation has issues with domain name or certs. Try this link
  4. Check every step of your process against this

Sorry, not being of much more help than this.

16
Leon Krancher On

So from your comment I understand that it does work on your emulator but not on your phone right? Did you by any chance use the channel name in another/prior application?

The thing is that the emulator reset back to it's default state everyime it closes, your phone does not. A particular channel name can only be used by a single application. So if the channel name was used by another application on the same phone before it is still registered to that app and you can't access it from your app.

Conversely an app can also regsiter no more than one channel so if there is allready one by another name associated with it you cannot register a new one until you unregister the old one and reboot your device. Also there is no way to request which channel is associated with your app.

Ultimately when I got stuck in this loop I changed the name of the channel and my applications ProductID registered in the WMAppManifest.xml and it worked again form me

<App xmlns="" ProductID="{d57ef66e-f46c-4b48-ac47-22b1e924184b}"

Update My computer crashed this weekend, thank god for WHS and backups. Anyway below is my sourcecode. I notice a two differences.

  1. First off I created a method called RepeatAttemptExecuteMethod() to which I pass the entire executing code as a delegate. The 10 floating somewhere at the end is the amount of times it has to retry. If you only retried the .Open method every 5 seconds the difference might be in that I also call the Find and New methods again...

  2. Another difference I see is that my code assumes that the _appChannel.ChannelUri can be null. In which case it waits for the channel to raise an event and then does the work asociated with a actual channel being there. But since your samplecode doesn't do any of that sort of work I doubt it will be what you are looking for

    protected override void Load(PhoneApplicationPage parent)
    {
        Verkeer.Helper.ExternalResources.RepeatAttemptExecuteMethod(() => 
        {
            _appChannel = HttpNotificationChannel.Find(CHANNELNAME);
            if (_appChannel == null)
            {
                _appChannel = new HttpNotificationChannel(CHANNELNAME);
                SetUpDelegates();
            }
            else
            {
                SetUpDelegates();
                //if (_appChannel.ChannelUri != null) this.NotificationChannel = _appChannel.ChannelUri;
            }
            if (_appChannel.ChannelUri != null) this.NotificationChannel = _appChannel.ChannelUri;
            else
            {
                try
                {
                    _appChannel.Open();
                }
                catch { }
            }
    
            BindToShellTile();
    
            App.ViewModel.TrafficInfo.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(TrafficInfo_PropertyChanged);
    
            if (App.ViewModel.TrafficInfo.TrafficImage != null && this.NotificationChannel != null)
            {
                CreateTiles();
            }
        },10);
    }
    
    private void BindToShellTile()
    {
        if (!_appChannel.IsShellTileBound && App.ViewModel.PanItemSettings.AutomaticallyUpdateTile)
        {
            Collection<Uri> ListOfAllowedDomains = new Collection<Uri> { new Uri("http://m.anwb.nl/") };
            _appChannel.BindToShellTile(ListOfAllowedDomains);
        }
    }
    
    
    void TrafficInfo_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "TrafficImage")
        {
            if (App.ViewModel.PanItemSettings.AutomaticallyUpdateTile && this.NotificationChannel != null)
            {
                CreateTiles();
            }
        }
    }