Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Facebook crossdomain.xml silverlight error

I have a problem with crossdomain.xml that is located on Facebook photo servers. The first problem arises when Silverlight asks for clientaccesspolicy.xml – Facebook servers return 403 – Access Denied which is fine, since they also have crossdomain.xml deployed on their servers. Silverlight then asks for that crossdomain.xml and the response it gets is exactly this:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain- policy.dtd">
<cross-domain-policy>
    <allow-access-from domain="*" secure="false" to-ports="*" />
    <site-control permitted-cross-domain-policies="master-only" />
</cross-domain-policy>

Then I played for a while with this, deployed that crossdomain.xml to my own servers and a got the same results – a security exception. Then I started moving things out and came to a conclusion that everything will work as desired if I only remove the to-ports="*" attribute? Does anyone has an idea how to overcome this, has anyone had the same problem before or is it something that I’m doing wrong?

like image 499
Petar Slavov Avatar asked Jul 25 '11 14:07

Petar Slavov


1 Answers

I have run into the same issue while trying to programmatically retrieve images from Facebook. The strange part is that if you point a Silverlight image control to the Facebook image url, the image is retrieved and displayed without error. This got me thinking and I have come up with a viable workaround that seems to work consistently for my situation. I hope you find it useful too.

var uri = new Uri("http://graph.facebook.com/mglace/picture/", UriKind.Absolute);
var bmp = new BitmapImage();

bmp.ImageOpened += (sender, e) => { /* Do something here with the sender (which is the BitmapImage) */ };
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.UriSource = uri;

Create a BitmapImage object, set an event handler for the ImageOpened event and set the CreateOptions property to BitmapCreateOptions.None. Finally, set the UriSource to the Facebook image you want to retrieve. The image is downloaded immediately because we set the CreateOptions to None (the default value is DelayedCreation). You can then perform any actions you would like in the ImageOpened event handler.

I wanted to encapsulate this logic in my service layer and beef up the error handling and such so I wrapped it in a Reactive Extensions observable to make it easier to use. Here is my final code snippet:

public IObservable<BitmapImage> GetProfilePhoto(string profileId)
{
    return Observable.Create<BitmapImage>(
        observer =>
            {
                // This handler handles a successful fetch
                EventHandler<RoutedEventArgs> openedHandler =
                    (sender, args) =>
                        {
                            try
                            {
                                observer.OnNext(sender as BitmapImage);
                                observer.OnCompleted();
                            }
                            catch (Exception ex)
                            {
                                observer.OnError(ex);
                            }
                        };

                // This handler handle a failure
                EventHandler<ExceptionRoutedEventArgs> failedHandler =
                    (sender, args) => observer.OnError(args.ErrorException);

                var url = string.Format("http://graph.facebook.com/{0}/picture/", profileId);
                var uri = new Uri(url, UriKind.Absolute);

                BitmapImage bmp = null;

                try
                {

                    Deployment.Current.Dispatcher.BeginInvoke(
                        () =>
                            {
                                bmp = new BitmapImage();

                                bmp.ImageOpened += openedHandler;
                                bmp.ImageFailed += failedHandler;

                                bmp.CreateOptions = BitmapCreateOptions.None;
                                bmp.UriSource = uri;
                            });
                }
                catch (Exception ex)
                {
                    observer.OnError(ex);
                }

                return () =>
                            {
                                // Cleanup the event handlers
                                if (bmp != null)
                                {
                                    bmp.ImageOpened -= openedHandler;
                                    bmp.ImageFailed -= failedHandler;
                                }
                            };
            });
}

And usage:

GetProfilePhoto("mglace")
    .Subscribe(image => { /* Do something with the image in here*/  },
               error => { /* Handle any errors in here */ },
               () => { /* Finalization code goes here */ });

I hope someone out there finds this useful.

like image 53
Matthew Scott Avatar answered Sep 23 '22 00:09

Matthew Scott