###Source As an example of how leveraging [Soapi.CS][1] and the reusable controls in Soapi.Contrib.Silverlight can increase productivity when writing code against the API, I include the source code for the Soapi.Explore Silverlight application. // // Project: SOAPI // http://soapics.codeplex.com // http://stackapps.com/questions/386 // // Copyright 2010, Sky Sanders // Licensed under the GPL Version 2 license. // http://soapics.codeplex.com/license // // Date: Aug 12 2010 // API ver 1.0 rev 2010.0709.04 // #region using System; using System.Text.RegularExpressions; using System.Threading; using System.Windows; using System.Windows.Controls; using Amp.Controls.MouseWheel; using Soapi; using Soapi.Contrib.Controls; using Soapi.Domain; using Soapi.Net; using Soapi.Parameters; using Soapi.Routes; #endregion namespace Explore { public partial class MainPage { #region Constants private const string ApiKey = "qgAq_KfDu0KYzlNG-qaTuw"; #endregion #region Fields private TextBlock _busyMessage; private bool _cancel; private Button _cancelButton; private ApiContext _context; #endregion #region Constructors public MainPage() { InitializeComponent(); InitializeContext(); } private void InitializeContext() { BusyIndicator.IsBusy = true; BusyIndicator.DisplayAfter = new TimeSpan(0, 0, 0, 0, 500); ScrollViewerMouseWheelSupport.Initialize(this); AccordionScroller.AddMouseWheelSupport(); JsonOutputScroller.AddMouseWheelSupport(); RequestCache.Instance.DefaultDuration = new TimeSpan(0, 0, 0, 1); _context = new ApiContext(ApiKey); _context.Initialized += ContextInitialized; _context.Initialize(true); } void ContextInitialized(object sender, EventArgs e) { Dispatcher.BeginInvoke(() => { SitesComboBox.ItemsSource = _context.Sites; SitesComboBox.SelectedIndex = 0; // this is a total hack. need to use mvvm light and a command pattern. WireUpRouteControl(AnswersById); WireUpRouteControl(AnswersByIdComments); WireUpRouteControl(Badges); WireUpRouteControl(BadgesById); WireUpRouteControl(BadgesName); WireUpRouteControl(BadgesTags); WireUpRouteControl(CommentsById); WireUpRouteControl(PostsByIdComments); WireUpRouteControl(Questions); WireUpRouteControl(QuestionsById); WireUpRouteControl(QuestionsByIdAnswers); WireUpRouteControl(QuestionsByIdComments); WireUpRouteControl(QuestionsByIdTimeline); WireUpRouteControl(QuestionsUnanswered); WireUpRouteControl(RevisionsById); WireUpRouteControl(RevisionsByIdByRevisionGuid); WireUpRouteControl(Search); WireUpRouteControl(Stats); WireUpRouteControl(Tags); WireUpRouteControl(Users); WireUpRouteControl(UsersById); WireUpRouteControl(UsersByIdAnswers); WireUpRouteControl(UsersByIdBadges); WireUpRouteControl(UsersByIdComments); WireUpRouteControl(UsersByIdCommentsTo); WireUpRouteControl(UsersByIdFavorites); WireUpRouteControl(UsersByIdMentioned); WireUpRouteControl(UsersByIdQuestions); WireUpRouteControl(UsersByIdReputation); WireUpRouteControl(UsersByIdTags); WireUpRouteControl(UsersByIdTimeline); WireUpRouteControl(UsersModerators); WireUpRouteControl(Sites); WireUpRouteControl(UsersByIdAssociated); BusyIndicator.IsBusy = false; }); } #endregion #region Private Methods private void BusyMessageLoaded(object sender, RoutedEventArgs e) { _busyMessage = (TextBlock)sender; } private void CancelButtonClick(object sender, RoutedEventArgs e) { _cancel = true; _cancelButton.IsEnabled = false; } private void CancelButtonLoaded(object sender, RoutedEventArgs e) { _cancelButton = (Button)sender; } private void SetJsonText(string value, bool scroll) { JsonOutput.Text += value; if (scroll) { try { JsonOutput.SelectionStart = JsonOutput.Text.LastIndexOf(Environment.NewLine); JsonOutput.SelectionStart = JsonOutput.Text.LastIndexOf(Environment.NewLine, JsonOutput.SelectionStart); JsonOutput.SelectionLength = 0; } catch { } } } private void SetUrl(IRoute route) { var url = Regex.Replace(route.RequestUri.AbsoluteUri, @"(\?|&)key=" + ApiKey, ""); QueryUrl.Content = url; QueryUrl.NavigateUri = new Uri(url); } private void WireUpRouteControl(ParametersControl ctrl) { ctrl.ExecuteQuery += (s, e) => { IParameter parameters = ctrl.Parameters; try { parameters.Validate(); } catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); return; } var site = ((Site)SitesComboBox.SelectedItem); var route = site.RouteFactory.GetRouteByPath(ctrl.Route); route.Parameters = parameters; var pagedRoute = route as IPagedRoute; if (pagedRoute != null) { var pageParameters = (IPageParameter)parameters; if (pageParameters.PageCount < 1 || pageParameters.PageCount > 9) { var result = MessageBox.Show( "Large result sets may be hard for your browser to handle.\r\nAre you sure you want to continue?" +"\r\n\r\nNote: I am working on a virtualized textbox\r\nthat will relieve this issue." , "Large Result Warning", MessageBoxButton.OKCancel); if (result == MessageBoxResult.Cancel) { return; } } } Dispatcher.BeginInvoke(() => { _cancelButton.IsEnabled = true; BusyIndicator.IsBusy = true; _busyMessage.Text = String.Format("Initializing request"); JsonOutput.Text = string.Empty; }); ThreadPool.QueueUserWorkItem(ignored => { if (pagedRoute != null) { pagedRoute.PageRecieved += (ss, ee) => { Dispatcher.BeginInvoke(() => { _busyMessage.Text = String.Format("Fetched Page {0} of {1}", ee.CurrentPage, ee.TotalPages); string value = "\r\n" + ee.Result.ResponseText; SetJsonText(value, false); SetUrl(route); }); ee.Cancel = _cancel; }; } try { #pragma warning disable 168 // need this to build structured response var response = route.GetResponse(); #pragma warning restore 168 // todo - structured output of response if (pagedRoute == null) { Dispatcher.BeginInvoke(() => { SetJsonText(route.ResponseText, false); SetUrl(route); }); } } catch (Exception ex) { Dispatcher.BeginInvoke(() => { SetJsonText("\r\n--------------------------------------------------" + "\r\nERROR:" + "\r\n--------------------------------------------------\r\n" + ex.Message + "\r\n--------------------------------------------------\r\n" + ex + "\r\n--------------------------------------------------", true); SetUrl(route); }); } finally { Dispatcher.BeginInvoke(() => { _cancel = false; BusyIndicator.IsBusy = false; }); } }); }; } #endregion } } [1]: http://stackapps.com/questions/386/