Building a Playstation Network Widget for Blog Engine

by Albert Mutangiri 6. March 2011 01:16

Well last week I spent a few hours digging into BlogEgine widgets, and I'm planning to add a few more custom widgets for my blog. BlogEngine.NET makes it very easy to create your own widgets. Widgets are ASP.NET Custom Controls. Each widget is in its own folder within the widgets folder found in your blog. All widgets must have a widget.ascx file and a widget.ascx.cs file. There are a few rules that you might need to adhere to for example the widget.ascx must override the WidgetBase Class, will look at that a bit later.

There is an API out there for playstation Network at codeplex.com that is exposed as a service. So all I needed was to consume this service and persist the xml feed with member information and game collection on a local store as well as provide a mechanism to check for latest updates and update this local feed.

So lets have a look at this service -- there is an operation that's exposed - GetProfile(), this requires your PSN ID and location and returns a collection of your games, trophies as well as your profile.



At runtime i lookup for updates on PSN Network and persist changes on a local store, this mechanism uses HttpRuntime.Cache to cache settings as well as the profile xml feed itself.

So there is two important controls you need (1) edit.ascx and (2) widget.ascx. The first one is for widget configurations, must inherit from the WidgetEditBase Class and override Save() function. So what are we interested in here ? We need to know the User PSN ID, Web Service URL, Refresh Interval for checking for updates on the server and total Number of trophies to diplay on the widget. We will use the key setting PLAY_STATION_NETWORK_KEY_SETTINGS to store these settings using the

HttpRuntime.Cache(PLAY_STATION_NETWORK_KEY_SETTINGS);


public partial class widgets_PSNetwork_edit : WidgetEditBase
{
    /* We will use this key setting to cache the current control settings */
    private const string PLAY_STATION_NETWORK_KEY_SETTINGS = "psn-network-settings";

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            StringDictionary settings = GetSettings();
            if (settings.ContainsKey("psn-id"))
            {
                txtPsnID.Text = settings["psn-id"];
                txtServiceURL.Text = settings["psn-service-url"];
                txtRefreshInterval.Text = settings["psn-feed-refresh-rate"];
                txtTotalNumberofTrophies.Text = settings["psn-total-trophies-per-page"];
            }
        }

    }
    /* Override the Save function of the WidgetEditBase Class with values supplied by the user from the UI */
    public override void Save()
    {
        try
        {
            StringDictionary settings = GetSettings();
            settings["psn-id"] = txtPsnID.Text.Trim();
            settings["psn-feed-refresh-rate"] = txtRefreshInterval.Text.Trim();
            settings["psn-total-trophies-per-page"] = txtTotalNumberofTrophies.Text;
            settings["psn-service-url"] = txtServiceURL.Text.Trim();
            SaveSettings(settings);
            HttpRuntime.Cache.Remove(PLAY_STATION_NETWORK_KEY_SETTINGS);
        }
        catch (Exception ex)
        {
            string msg = "Error Saving PSN Network Widget";
            if (ex != null) msg += " " + ex.Message;
            Utils.Log(msg);
        }
    }

}

The widget.ascx control is the actual widget that users will see on your blog and must inherit from the WidgetBase Class and override the following functions.

/* The Name of the Widget */
public override string Name { get; }
/* A boolean value that specifes if this widget is editable or not */
public override bool IsEditable { get; }
/*Renders the widget to the user. */
public override void LoadWidget() { }

To store the user profile i have a few internal classes to catter for this, I have the following Entities

1) PSNSettings - to store user preference settings for this widget.
2) TrophyCount - stores user trophies
3) PSNProfile - PSN user profile for example the progress, location etc.
4) PlayedGame - a collection of games as well as the related trophies.


The first time I load the widget, I check user settings from the cache and based on these settings we load the user profile on Playstation Network.
The constant value PLAY_STATION_NETWORK_REMOTE_OPERATION_NAME is the remote operation name on the web service to invoke.

private const string PLAY_STATION_NETWORK_REMOTE_OPERATION_NAME = "GetProfile";

/* the first time we load the widget, we check for the current settings */
public override void LoadWidget()
{   
        PSNSettings settings = getPSNSettings();
       /* logic to fetch user profile and game collection  here */
}
/* get user current widget settings */
private PSNSettings getPSNSettings()
    {
        Uri _networkserviceUri;
        int _refreshInterval = 10;
        int _totalNumberofTrophies = 4;

        PSNSettings psnsettings = HttpRuntime.Cache[PLAY_STATION_NETWORK_KEY_SETTINGS] as PSNSettings;
        if (psnsettings != null)
            return psnsettings;
        psnsettings = new PSNSettings();
        StringDictionary settings = GetSettings();

        if (settings.ContainsKey("psn-service-url") && !string.IsNullOrEmpty(settings["psn-service-url"]))
        {
            Uri.TryCreate(settings["psn-service-url"] + "/" + PLAY_STATION_NETWORK_REMOTE_OPERATION_NAME + "?psnid=" + settings["psn-id"] + "&location=", UriKind.Absolute, out _networkserviceUri);
            psnsettings.ServiceURL = _networkserviceUri;
        }
        if (settings.ContainsKey("psn-feed-refresh-rate") && !string.IsNullOrEmpty(settings["psn-feed-refresh-rate"]))
        {
            int temp_refreshInterval;
            if (int.TryParse(settings["psn-feed-refresh-rate"], out temp_refreshInterval))
            {
                if (temp_refreshInterval > 0)
                    _refreshInterval = temp_refreshInterval;
            }
        }
        if (settings.ContainsKey("psn-total-trophies-per-page") && !string.IsNullOrEmpty(settings["psn-total-trophies-per-page"]))
        {
            int temp_totalNumberofTrophies;
            if (int.TryParse(settings["psn-total-trophies-per-page"], out temp_totalNumberofTrophies))
            {
                if (temp_totalNumberofTrophies > 0)
                    _totalNumberofTrophies = temp_totalNumberofTrophies;
            }
        }
        psnsettings.RefreshInterval = _refreshInterval;
        psnsettings.TotalNumberofTrophies = _totalNumberofTrophies;
        HttpRuntime.Cache[PLAY_STATION_NETWORK_KEY_SETTINGS] = psnsettings;
        return psnsettings;
    }

The last two important functions take advantage of HttpWebRequest  to invoke the service, the nice part of this is that we dont need a pre-generated proxy stub to invoke the service. BeginGetPSNServiceRequest function accepts a uniform resource identifier, in this case the web service location + the operation name + parameters.


/* To Construct the URI, I call getPSNSettings() function */
 Uri.TryCreate(settings["psn-service-url"] + "/" + PLAY_STATION_NETWORK_REMOTE_OPERATION_NAME + "?psnid=" + settings["psn-id"] + "&location=", UriKind.Absolute, out _networkserviceUri); psnsettings.ServiceURL = _networkserviceUri;

/*Invokes the remote PSN Service and we pass a callback function EndGetPSNServiceResponse() to fetch the xml result */
private void BeginGetPSNServiceRequest(Uri url)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            request.BeginGetResponse(EndGetPSNServiceResponse, request);
        }
        catch (Exception ex)
        {
            string msg = "Error requesting PSN feed.";
            if (ex != null) msg += " " + ex.Message;
            Utils.Log(msg);
        }
    }
   /* loads the response into an xml document and then we persist this to our local store using the XmlDocument.Save() function */
    private void EndGetPSNServiceResponse(IAsyncResult result)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)result.AsyncState;
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(response.GetResponseStream());
                HttpRuntime.Cache[PLAY_STATION_NETWORK_KEY_SETTINGS] = doc.OuterXml;
                SavePSNFeed(doc);
            }
        }
        catch (Exception ex)
        {
            string msg = "Error retrieving PSN feed.";
            if (ex != null) msg += " " + ex.Message;
            Utils.Log(msg);
        }

    }

The widget is a very simple ASP.NET ListView Control bound to the PSNProfile class. The installation is very easy. Just extract the package to widgets folder and login as admin user to add this widget to widget zone, edit settings and that's all. A good example is on the right side of my blog.

Download widget source below.
PSNetwork.zip (16.87 kb)

Tags:

Comments

7/30/2012 1:43:18 PM #

pingback

Pingback from friendslosangeles.march9online.net

Learning Fundamental Web Design Is Vital For Successful Online … | Friends Los Angeles

friendslosangeles.march9online.net | Reply

10/16/2014 4:12:14 AM #

trackback

Winter Jam 2011

Winter Jam 2011

Black's Web Log | Reply

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



About Me

mage.axd?picture=2012%2f4%2fbert.jpg

Hi, My name is Albert Mutangiri, I am a software developer currently interested in software design, integration, .net technologies and Java. I'm currently developing enterprise applications for business process automation using Java & .Net Technologies.

 

I Code Java

PSNetwork


bertoncaffeine

Playing
17 0 1 0 18
13 6 0 0 19
4 0 0 0 4
22 1 0 0 23
0 0 3 0 3

Tag cloud