I’m on an RSS widget roll. I put together a widget that is much like the Flickr widget only it uses Twitter as the source. Now Twitter had to go and give me a hard time by recently changing their cross domain policy file to only allow specific sites. Because of this I had to add a proxy to this solution to get it to work.
Let’s get to the code. If you need an aspx proxy this should do the trick for you.
1: using System;
2: using System.Configuration;
3: using System.Data;
4: using System.Linq;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.HtmlControls;
9: using System.Web.UI.WebControls;
10: using System.Web.UI.WebControls.WebParts;
11: using System.Xml.Linq;
12: using System.IO;
13: using System.Net;
14:
15: public partial class _Default : System.Web.UI.Page
16: {
17: protected void Page_Load(object sender, EventArgs e)
18: {
19: // Load the URI from the Query String
20: string sourceUriString = Request.QueryString["Uri"];
21:
22: // Clear the output buffer
23: Response.Clear();
24:
25: // Make new WebClient
26: WebClient webClientRequest = new WebClient();
27:
28: // Download data from URI
29: byte[] requestByteArray = webClientRequest.DownloadData(sourceUriString);
30:
31: // Match the Mime Types
32: string contentType = webClientRequest.ResponseHeaders["Content-type"].ToString();
33: Response.ContentType = contentType;
34:
35: // Copy the Streams
36: int requestByteArrayLength = requestByteArray.GetLength(0);
37: Response.OutputStream.Write(requestByteArray, 0, requestByteArrayLength);
38: Response.OutputStream.Close();
39:
40: // Exit the Page
41: Response.End();
42: }
43: }
proxy/Default.aspx.cs
As you’ll see in the next bits of code that I’m just passing the Twitter RSS URL to my proxy to get around the current limits of the cross domain policy.
Because of the way I set up this solution with the proxy running on another port I had to add a crossdomain.xml file and I went ahead and put in the clientaccesspolicy.xml for example too.
Back to the goods. Let’s take a look at the Silverlight object embedded in the html page and how it’s being loaded to pass parameters as need.
1: <div id="silverlightControlHost">
2: <object data="data:application/x-silverlight," type="application/x-silverlight-2-b1" width="100%" height="100%">
3: <param name="source" value="ClientBin/TwitterFeed.xap"/>
4: <param name="onerror" value="onSilverlightError" />
5: <param name="background" value="white" />
6: <param name="initParams" value="twitterID=futileboy,proxy=http://localhost:51591/Default.aspx?uri=,time=4" />
7:
8: <a href="http://go.microsoft.com/fwlink/?LinkID=108182" style="text-decoration: none;">
9: <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
10: </a>
11: </object>
12: <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
13: </div>
TwitterFeedPage.html
I’m using the initParams to pass my customizable variables in to Silverlight app.
- twitterID – takes the user id that you would like to display. Mine is futileboy.
- proxy – is an optional parameter to handle a proxy. localhost:51591 is part of my example solution.
- time – is the duration that you want your tweets to be displayed for. The time parameter is in seconds.
From the HTML side the parameters are passed App.xaml.cs which reads them in and then hands it off to the Page.xaml.cs
1: using System.Windows;
2: using System;
3:
4: namespace TwitterFeed
5: {
6: public partial class App : Application
7: {
8:
9: public App()
10: {
11: this.Startup += this.OnStartup;
12: this.Exit += this.OnExit;
13:
14: InitializeComponent();
15: }
16:
17: private void OnStartup(object sender, StartupEventArgs e)
18: {
19: //grab the params pased from the html page
20: string currentUserID = e.InitParams["twitterID"];
21: string currentProxy = e.InitParams["proxy"];
22: int currentDuration = Convert.ToInt32(e.InitParams["time"]);
23: // Load the main control here
24: this.RootVisual = new Page(currentUserID, currentProxy, currentDuration);
25: }
26:
27: private void OnExit(object sender, EventArgs e)
28: {
29:
30: }
31: }
32: }
App.xaml.cs
Here’s the real meaty part that you’ve all been waiting for. I did my best to get all the comments in there.
1: using System;
2: using System.Windows;
3: using System.Windows.Browser;
4: using System.Windows.Controls;
5: using System.Windows.Documents;
6: using System.Windows.Ink;
7: using System.Windows.Input;
8: using System.Windows.Media;
9: using System.Windows.Media.Animation;
10: using System.Windows.Shapes;
11: using System.Windows.Threading;
12: using System.Xml.Linq;
13: using System.Net;
14: using System.IO;
15: using System.Xml;
16: using System.Collections;
17: using System.Text;
18: using System.ServiceModel;
19: using System.ServiceModel.Syndication;
20:
21:
22: namespace TwitterFeed
23: {
24: public partial class Page : UserControl
25: {
26: //Set up the global variables here
27: DispatcherTimer dt = new DispatcherTimer();
28: string currentTitle;
29: string currentDate;
30: string currentLink;
31: int currentDuration;
32: DateTime lastUpdate;
33: string[,] postArray;
34: Int32 feedIndex = 0;
35: Int32 x = 0;
36: Int32 feedItemAmount;
37:
38: string feedBaseUri = "http://twitter.com";
39: string feedProxyUri;
40: string feedPathUri;
41:
42: public Page(string userID, string proxyUri, int duration)
43: {
44: // Required to initialize variables
45: InitializeComponent();
46:
47: currentDuration = duration;
48: feedProxyUri = proxyUri;
49: feedPathUri = (string.Format("/statuses/user_timeline/{0}.rss", userID));
50:
51: this.Loaded += new RoutedEventHandler(Page_Loaded);
52:
53: // Make new WebClient
54: WebClient webClientRequest = new WebClient();
55:
56: LabelBlock.Text = "Loading...";
57:
58: //put the url together
59: string sourceUrl = feedProxyUri + feedBaseUri + feedPathUri;
60:
61: //Create the URI to send the request to
62: Uri feedURL = new Uri(sourceUrl);
63:
64: HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(feedURL);
65:
66: //Make the asynchronous request and register a callback.
67: request.BeginGetResponse(new AsyncCallback(responseHandler), request);
68:
69: //
70: }
71:
72: void responseHandler(IAsyncResult asyncResult)
73: {
74: //Define the responseHandler function and get the HttpWebResponse.
75: HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
76: HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
77:
78: //Get the Stream that contains the response.
79: Stream responseStream = response.GetResponseStream();
80:
81: //Get a XmlReader over the stream and load it into a SyndicationFeed class.
82: XmlReader responseReader = XmlReader.Create(responseStream);
83: SyndicationFeed feed = SyndicationFeed.Load(responseReader);
84:
85: //get the number of feed items returned
86: feedItemAmount = (((System.Collections.ObjectModel.Collection<SyndicationItem>)(feed.Items))).Count;
87:
88: postArray = new string[feedItemAmount, 3];
89:
90: foreach (SyndicationItem item in feed.Items)
91: {
92: currentTitle = item.Title.Text;
93: currentDate = XmlConvert.ToString(item.PublishDate, "MM-dd-yyyy HH:mm");
94:
95: postArray[feedIndex, 0] = currentTitle;
96: postArray[feedIndex, 1] = currentDate;
97: postArray.SetValue(feedBaseUri + item.Links[0].Uri.AbsolutePath, feedIndex, 2);
98: feedIndex++;
99: }
100:
101: lastUpdate = DateTime.Now;
102:
103: dt.Interval = new TimeSpan(0, 0, 0, currentDuration);
104: dt.Tick += new EventHandler(dt_Tick);
105: dt.Start();
106: }
107:
108: void Page_Loaded(object sender, RoutedEventArgs e)
109: {
110: LabelBlock.MouseEnter += new MouseEventHandler(LabelBlock_MouseEnter);
111: LabelBlock.MouseLeave += new MouseEventHandler(LabelBlock_MouseLeave);
112: LabelBlock.MouseLeftButtonDown += new MouseButtonEventHandler(LabelBlock_MouseButtonDown);
113: }
114:
115: void dt_Tick(object sender, EventArgs e)
116: {
117: //this is our timer control, every time we update this will run
118: Update();
119: }
120:
121: void Update()
122: {
123: //Updating the time
124: DateTime now = DateTime.Now;
125: TimeSpan elapsed = now - lastUpdate;
126: lastUpdate = now;
127: //do your loop processing here
128: if (x <= (feedItemAmount - 1))
129: {
130: LabelBlock.Text = postArray[x, 0];
131: Pub_Date.Text = postArray[x, 1];
132: currentLink = postArray[x, 2];
133: x++;
134: }
135: else
136: {
137: x = 0;
138: }
139: }
140:
141: private void LabelBlock_MouseEnter(object sender, MouseEventArgs e)
142: {
143: //stop the animation
144: dt.Stop();
145: }
146:
147: private void LabelBlock_MouseLeave(object sender, MouseEventArgs e)
148: {
149: //start it back up again
150: dt.Start();
151: }
152:
153: private void LabelBlock_MouseButtonDown(object sender, MouseButtonEventArgs e)
154: {
155: //follow the link of the current tweet
156: HtmlPage.Window.Navigate(new Uri(currentLink));
157: }
158:
159: }
160: }
Page.xaml.cs
Last but not least here’s the XAML that is being used to display our lovely little widget.
1: <UserControl
2: xmlns="http://schemas.microsoft.com/client/2007"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: x:Class="TwitterFeed.Page"
5: Width="150" Height="150" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
6:
7: <Grid x:Name="LayoutRoot" >
8: <Rectangle HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" RadiusX="8" RadiusY="8" x:Name="background">
9: <Rectangle.Fill>
10: <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
11: <GradientStop Color="#FF213343"/>
12: <GradientStop Color="#FF5C7D99" Offset="1"/>
13: </LinearGradientBrush>
14: </Rectangle.Fill>
15: </Rectangle>
16: <Rectangle HorizontalAlignment="Stretch" Margin="4,4,4,71" VerticalAlignment="Stretch" RadiusX="8" RadiusY="8" d:LayoutOverrides="VerticalAlignment">
17: <Rectangle.Fill>
18: <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
19: <GradientStop Color="#80FFFFFF" Offset="0.013"/>
20: <GradientStop Color="#00FFFFFF" Offset="0.906"/>
21: </LinearGradientBrush>
22: </Rectangle.Fill>
23: </Rectangle>
24: <TextBlock Margin="0,0,0,0" Text="test"
25: TextWrapping="Wrap"
26: x:Name="LabelBlock"
27: Foreground="#FFFFFFFF"
28: FontSize="12"
29: FontFamily="Verdana"
30: VerticalAlignment="Top"
31: HorizontalAlignment="Left"
32: LineHeight="10"
33: Padding="11,11,11,10"
34: Cursor="Hand"/>
35: <TextBlock Height="14" Margin="8,0,8,0" VerticalAlignment="Bottom" Text="" TextWrapping="Wrap" FontSize="9" FontFamily="Verdana" Foreground="#FFA0BEE1" x:Name="Pub_Date"/>
36: </Grid>
37: </UserControl>
Page.xaml
I haven’t added this to my blog here yet, but I plan on putting up there in the upper right in place of the current twitter widget in the very near future.
Related posts:
{ 1 trackback }