Saturday, October 16, 2010
Mo Words in the Marketplace
I've started a Mo Words blog where people can leave feedback about the game and request new features. I'm already read with an update that let's you cancel new challenges, force players to resign who haven't played in over 24 hours and reset your password if you've forgotten it.
Now Playing - Community - Anthropology Rap (Toto - Africa)
Monday, October 11, 2010
Mo Words Marketplace submission details
Splash Screen |
Word a day |
Open Games |
Past Games |
Definitions for played words |
More definitions |
Pro Tips |
Pro tips |
Touch and hold for definitions of played words |
Hopefully that will whet the appetite of some app buyers.
Now Playing - Bubba Sparxxx - Deliverance
Saturday, October 2, 2010
Halo Reach API C# Wrappers
There are Win Phone 7 versions and regular Windows class libraries. I even wrote a simple little proof of concept app that will get a player's details by Gamertag.
Everything is pretty untested at this point. But I'd like to add a video viewer to the Win Phone app sometime tomorrow.
See the project on Codeplex for more code samples and source code downloads.
Now Playing - Otis Taylor - Nasty Letter
Sunday, August 29, 2010
Show Custom In-House Ads in Win Phone 7 with MoAds
Just want the code? Get it here
There is also the sort of unsettling issue of Microsoft's Developer agreement being sort of fuzzy on advertising services (as pointed out by this MobileTechWorld article about MoAds).
At any rate, here's a brief run down of creating your own custom ad service using a new MVC 2 Website and some JSON services.
The Web Services Site - .Net MVC 2
In the example provided, I've created a new .Net MVC 2 website and added an AdController. The AdController is responsible for handling our AdRequests. In this case, we add two methods; Fetch and Click. The Fetch will be responsible for returning the Ad information (ImageUrl, AdText and ClickUrl) and the Click will redirect to the actual Ad Url after recording the client click.public ActionResult Fetch(string pubId, string clientId = "") { // TODO: You'd probably want to keep track of fetches by PubId for analytics, but this is just a demo. var ad = AdRepository.GetRandomAd(); Impression impression; var clickUrl = GenerateClickUrl(ad, out impression); ImpressionRepository.Impressions.Add(impression); return new JsonResult() { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new FetchResponse() { ClickUrl = clickUrl, AdText = ad.AdText, ImageUrl = ad.ImageUrl } }; } public ActionResult Click(string id) { // TODO: Track the click for analytics and what-not. var impression = ImpressionRepository.Impressions.FirstOrDefault(x => x.Token == id); if (impression == null) return View(); // TODO: return not found result. var ad = AdRepository.GetAdById(impression.AdId); return new RedirectResult(ad.AdUrl); }
Creating a Custom Ad Adapter
The Custom Ad Adapter generally has an underlying service component (in our example it's called CustomAdService) that calls out to some service and gets some ad information, massages the response and fires our GotAdResponse event. Here's a brief run down of what our CustomAdAdapter class looks like.
public class CustomAdAdapter : IAdAdapter { private CustomAdService adService = new CustomAdService(); /// <summary> /// Gets or sets the publisher id. /// </summary> /// <value>The publisher id.</value> public string PublisherId { get; set; } /// <summary> /// Gets or sets the client id. /// </summary> /// <value>The client id.</value> public string ClientId { get; set; } public CustomAdAdapter() { adService.GotResult += new EventHandler<Service4u2.Common.EventArgs<CustomAdFetchResponse>>(adService_GotResult); adService.GotError += new EventHandler<Service4u2.Common.EventArgs<Exception>>(adService_GotError); } void adService_GotError(object sender, Service4u2.Common.EventArgs<Exception> e) { if (GotError != null) GotError(this, e); } void adService_GotResult(object sender, Service4u2.Common.EventArgs<CustomAdFetchResponse> e) { var adResponse = new AdResponse() { AdText = e.Argument.AdText, ImageUrl = e.Argument.ImageUrl, ClickUrl = e.Argument.ClickUrl }; if (GotAdResponse != null) GotAdResponse(this, new Service4u2.Common.EventArgs<AdResponse>() { Argument = adResponse }); } #region IAdAdapter Members public event EventHandler<Service4u2.Common.EventArgs<AdResponse>> GotAdResponse; public event EventHandler<Service4u2.Common.EventArgs<Exception>> GotError; public void GetAdResponseAsync() { adService.FetchAdAsync(this.PublisherId, this.ClientId); } #endregion }
Hooking up our Custom Ad Adapter in XAML
Once we have our Custom Ad Adapter in place we can plug it in to our AdDisplay control and start serving ads.
<!-- Custom Ad Service example --> <moad:AdDisplay Style="{StaticResource AnimationAdMobStyle}" VerticalAlignment="Bottom" Foreground="White" RefreshSeconds="30"> <moad:AdDisplay.AdAdapter> <local:CustomAdAdapter PublisherId="SomePubId" ClientId="SomeClientId"/> </moad:AdDisplay.AdAdapter> </moad:AdDisplay>
And that's about it. Hopefully I'll find some other ad service providers to implement soon. If anyone has any recommendations I'd be happy to hear them.
Grab the updated example source from here or the Project Page at BitBucket (Codeplex is still Garbage).
Now Playing - Notorious B.I.G - Mo Money Mo Problems
Saturday, August 28, 2010
MoAds - Custom Win Phone 7 Ad Control with AdMob support
Update 2: Microsoft has released a much better ad serving solution than AdMob, this was just a stop gap in case nothing official was released. This control is old and busted, check out the Microsoft Ad SDK for the new hotness.
After seeing a project on CodePlex that allowed you to display AdMob ads in a Win Phone 7 application, I decided it would be a good project for another custom control.
Custom Styling, Animation and Templates
The main problem I saw with the existing control was that it didn't take advantage of the styling and "Blendability" of the Win Phone 7 platform. Basically, the control used a web browser control to display an HTML template that was updated with ad information.
Here is an example of three different styles for the same template, the top is the default template, the middle is a text only style, and the bottom shows a fading animation when the ads are refreshing. The animations are helped by utilizing the three states for the AdDisplay control; Loading, Normal and Error.
Custom Ad Providers
Another issue I saw was that it relied solely on AdMob, with very little flexibility for hooking up another Ad service (like a rumored Bing Mobile Ad Service), so I added an adapter pattern to the control.
Here is an example of using the provided AdMob Adapter with the control (notice this can all be done in XAML, no code behind).
<!-- Default template example --> <moad:AdDisplay Height="70" VerticalAlignment="Top" Foreground="White" RefreshSeconds="30"> <moad:AdDisplay.AdAdapter> <moad:AdMobAdapter PublisherId="YourPublisherID" CookieString="YourCookieString" AdKeywords="Boston" UseTestMode="True"/> </moad:AdDisplay.AdAdapter> </moad:AdDisplay>
I'm hoping to put up another post to talk about creating a custom "In-House" ad provider.
You can download the source from my DropBox account, or at the created project on Codeplex called MoAds.
Now Playing - Goodie Mob - Get Rich to This
Thursday, July 29, 2010
Clearable TextBox Custom Control
It looks like I've got most of the functionality replicated, including adding two states to help with animations. The states are "Normal" and "Cleared". By default, the Cleared state will cause the clear button text to flash red briefly. You can also now set the ClearButtonTemplate and the ClearButtonContent if you want. In the picture you can see I've set the ClearButtonContent to Clear and used the default template.
<clr:ClearableTextBox Text="{Binding SomeText, Mode=TwoWay}" ClearButtonContent="Clear" VerticalAlignment="Top"/>
I haven't tested any custom state animations, only the default ones that are included. Feel free to let me know if you find any problems. The source and binaries are available below.
Clearable TextBox Custom Control Source
Now Playing: The Roots - Don't Say Nuthin
Wednesday, July 28, 2010
A Clearable TextBox for Win Phone 7
After seeing a tweet about the lack of a clearable text box similar to the IPhone by Eric Malamisura, I was inspired to whip together a simple control that fills this need.
Here is some code for the control, in case you don't want to download the full example. Just create a new UserControl called ClearableEditBox and paste these parts in the relevant places.
<!-- Put inside your new UserControl --> <Grid x:Name="LayoutRoot"> <TextBox MinWidth="50" Text="{Binding ElementName=uiThis, Path=Text, Mode=TwoWay}" x:Name="editBox"/> <Button MinWidth="30" HorizontalAlignment="Right" VerticalAlignment="Center" Click="clrBtn_Click" x:Name="clrBtn"> <Button.Template> <ControlTemplate> <TextBlock FontSize="25" Margin="0 0 20 0" Foreground="Gray" FontWeight="Bold" Text="X"/> </ControlTemplate> </Button.Template> </Button> </Grid> // Put inside your code behind for your new UserControl. public partial class ClearableTextBox : UserControl, INotifyPropertyChanged { public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } // Using a DependencyProperty as the backing store for EditText. This enables animation, styling, binding, etc... public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ClearableTextBox), new PropertyMetadata(string.Empty, HandleTextChanged)); public ClearableTextBox() { InitializeComponent(); } private static void HandleTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { var box = obj as ClearableTextBox; if (null != box) box.OnPropertyChanged("Text"); } private void clrBtn_Click(object sender, RoutedEventArgs e) { Text = string.Empty; } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string name) { if (null != PropertyChanged) PropertyChanged(null, new PropertyChangedEventArgs(name)); } #endregion }
You can also download a sample project containing the control here.
Clearable TextBox UserControl
Now Playing: Eminem - Airplanes
Monday, July 26, 2010
Updated Win Phone 7 Busy Service That Does Not Change RootVisual
As a result, I've updated my sample to not require wrapping the root level PhoneApplicationFrame with a Grid. It turns out, most pages already have a Grid as their LayoutRoot element and you can just pass this in to a new RootPaneBusyService and use it in the same manner. So instead of passing the App.Current.RootVisual as Grid, we pass the LayoutRoot.
protected override void OnNavigatedTo( System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); var busyServ = new RootPanelBusyService(this.LayoutRoot); this.DataContext = new MainPageVM(busyServ); }
I've also updated the CreateBusyElement method to detect how many rows and columns are in the passed in root visual and set the ColumnSpan and RowSpan accordingly.
// Set the row and column span's if the root is a grid. if (rootVisual is Grid) { var gridRoot = rootVisual as Grid; int rowSpan = 1; if (gridRoot.RowDefinitions != null) rowSpan = gridRoot.RowDefinitions.Count + 1; int columnSpan = 1; if (gridRoot.ColumnDefinitions != null) columnSpan = gridRoot.ColumnDefinitions.Count + 1; Grid.SetRowSpan(root, rowSpan); Grid.SetColumnSpan(root, columnSpan); }
Download the updated sample
Create a Win Phone 7 Busy Service with Loady animation
Update 2: I've updated my example to not require changing the RootVisual. But you will still need to have a Grid as the Root of your Page. Check out the Updated Busy Service.
I've been spending a lot of time working on data driven Win Phone 7 apps in the past couple weeks and one of the most useful things I've created is a simple Busy Service for Win Phone 7 apps.
/// <summary> /// An interface for busy services. /// </summary> public interface IBusyService { bool IsBusyShown { get; } void ShowBusy(string message); void ShowBusy(TimeSpan timeToShow, string message); void ShowBusy(double milliSecondsToShow, string message); void HideBusy(double millisecondsToWait); void HideBusy(TimeSpan delay); void HideBusy(); }
I decided to implement a RootPanelBusyService, which basically means that it expects a "Panel" type of element, a Grid for example, at the RootVisual. The problem with the Win Phone 7 Beta update is that the RootVisual is no longer defined in the App.Xaml, so it would seem like you can't just wrap the Root level Phone Application Frame in a Grid. It turns out, it just takes a little more work, if you open up the App.xaml.cs and take a look at the CompleteInitializePhoneApplication method you will see where the RootVisual is assigned. So with a little code we can add a Grid wrapper around the PhoneApplicationFrame and have a nice place to add our Busy Loady icon.
// Do not add any additional code to this method private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) { // Set the root visual to allow the application to render if (RootVisual != RootFrame) { // Add a Grid wrapper around the Root application frame. var root = new Grid(); root.Children.Add(RootFrame); RootVisual = root; } // Remove this handler since it is no longer needed RootFrame.Navigated -= CompleteInitializePhoneApplication; }
Now that we have our Grid at the Root, we can instantiate a RootPanelBusyService and pass it to our ViewModel to start "Getting Busy...".
// From MainPage.xaml.cs protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); if (App.Current.RootVisual is Grid) { var busyServ = new RootPanelBusyService(App.Current.RootVisual as Grid); this.DataContext = new MainPageVM(busyServ); } } // In our MainPage View Model (MainPageVM.cs) /// <summary> /// A view model for the Main Page. /// </summary> public class MainPageVM : ViewModelBase { /// <summary> /// The busy service to use... /// </summary> private IBusyService busyService; /// <summary> /// Gets or sets the do busy command. /// </summary> /// <value>The do busy command.</value> public ICommand DoBusy { get; private set; } public MainPageVM(IBusyService busyServ) { busyService = busyServ; DoBusy = new DelegateCommand<object>(HandleDoBusy); } /// <summary> /// Handles the do busy command. /// </summary> /// <param name="arg">Unused. private void HandleDoBusy(object arg) { busyService.ShowBusy(2000, "Getting Busy..."); } }
And there you have it, you've got a simple and easy to use busy service for your long running operations. One other trick that I occasionally use it to set a Busy Service static property on my App class, so all ViewModels have easy access to it. To do this, just add a static property to your App class, and assign it after setting the RootVisual, like so:
// Easy access to the busy service. public static IBusyService BusyService { get; private set; } // Rest of this class omitted for brevity.... // Do not add any additional code to this method private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) { // Set the root visual to allow the application to render if (RootVisual != RootFrame) { // Add a Grid wrapper around the Root application frame. var root = new Grid(); root.Children.Add(RootFrame); RootVisual = root; // Set our easy access busy service property. BusyService = new RootPanelBusyService(root); } // Remove this handler since it is no longer needed RootFrame.Navigated -= CompleteInitializePhoneApplication; }
If you don't want to download the full example project to get the RootPanelBusyService implementation, here is the source, but you'll need to create your own Loady graphic / control.
/// <summary> /// An interface for busy services. /// </summary> public interface IBusyService { bool IsBusyShown { get; } void ShowBusy(string message); void ShowBusy(TimeSpan timeToShow, string message); void ShowBusy(double milliSecondsToShow, string message); void HideBusy(double millisecondsToWait); void HideBusy(TimeSpan delay); void HideBusy(); } /// <summary> /// A busy service that expects a Panel / Grid as the root visual. /// </summary> public class RootPanelBusyService : IBusyService { private UIElement currentBusyElement; private Panel rootVisual; /// <summary> /// Initializes a new instance of the <see cref="RootPanelBusyService"> class. /// </see></summary> /// The root visual element. public RootPanelBusyService(Panel rootVisualElement) { rootVisual = rootVisualElement; } #region IBusyService Members private bool _busyShown = false; public bool IsBusyShown { get { return _busyShown; } } public void ShowBusy(double milliSecondsToShow, string message = "Loading...") { ShowBusy(TimeSpan.FromMilliseconds(milliSecondsToShow), message); } public void ShowBusy(TimeSpan timeToShow, string message = "Loading...") { ShowBusy(message); ThreadPool.QueueUserWorkItem(new WaitCallback(time => { Thread.Sleep((TimeSpan)time); // Hide the busy after a sleep. rootVisual.Dispatcher.BeginInvoke(() => HideBusy()); }), timeToShow); } public void ShowBusy(string message = "Loading...") { _busyShown = true; var busyEl = CreateBusyElement(message); busyEl.Opacity = 0; try { if (rootVisual is Panel) { var root = rootVisual; root.Children.Add(busyEl); var anim = CreateAnimation(busyEl, Grid.OpacityProperty, 0.8, 0.00, 900, EasingMode.EaseOut); var story = new Storyboard(); story.Children.Add(anim); story.Begin(); } } catch { Debug.WriteLine("Problem showing busy."); } currentBusyElement = busyEl; } public void HideBusy(double milliseconds) { HideBusy(TimeSpan.FromMilliseconds(milliseconds)); } public void HideBusy(TimeSpan delay) { var root = rootVisual; ThreadPool.QueueUserWorkItem(new WaitCallback((arg) => { Thread.Sleep(delay); ((Panel)arg).Dispatcher.BeginInvoke(() => { HideBusy(); }); }), root); } public void HideBusy() { try { if (rootVisual is Panel) { var root = rootVisual; var anim = CreateAnimation(currentBusyElement, Grid.OpacityProperty, 0.00, .80, 1000, EasingMode.EaseOut); var story = new Storyboard(); story.Children.Add(anim); story.Begin(); // Remove the element a second later; I do it this way because StoryCompleted is flaky. ThreadPool.QueueUserWorkItem(new WaitCallback(obj => { Thread.Sleep(900); root.Dispatcher.BeginInvoke(() => { root.Children.Remove(currentBusyElement); currentBusyElement = null; }); }), null); } } catch { Debug.WriteLine("Problem hiding busy."); } _busyShown = false; } #endregion /// <summary> /// Creates the busy element; A Loady with a text block underneath. /// </summary> /// The message to show below the loady. private UIElement CreateBusyElement(string message = "Loading...") { // create a grid to hold the loady and swallow the entire screen. var root = new Grid() { Background = new SolidColorBrush(Colors.Black) }; // The spinny loady thingy... root.Children.Add(new Loady() { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }); // The text below the loady... root.Children.Add(new TextBlock() { Text = message, Margin = new Thickness(0, 150, 0, 0), FontSize = 30, HorizontalAlignment = System.Windows.HorizontalAlignment.Center, VerticalAlignment = System.Windows.VerticalAlignment.Center, Foreground = new SolidColorBrush(Colors.White) }); return root; } /// <summary> /// A helper method for creating double animations. /// </summary> public DoubleAnimation CreateAnimation(DependencyObject obj, DependencyProperty prop, double value, double milliseconds, EasingMode easing = EasingMode.EaseOut) { var from = Convert.ToDouble(obj.GetValue(prop)); return CreateAnimation(obj, prop, value, from, milliseconds, easing); } /// <summary> /// A helper method for creating double animations. /// </summary> public DoubleAnimation CreateAnimation(DependencyObject obj, DependencyProperty prop, double value, double from, double milliseconds, EasingMode easing = EasingMode.EaseOut) { CubicEase ease = new CubicEase() { EasingMode = easing }; DoubleAnimation animation = new DoubleAnimation { Duration = new Duration(TimeSpan.FromMilliseconds(milliseconds)), From = from, To = value, FillBehavior = FillBehavior.HoldEnd, EasingFunction = ease }; Storyboard.SetTarget(animation, obj); Storyboard.SetTargetProperty(animation, new PropertyPath(prop)); return animation; } }
Now Playing: The Roots - Get Busy
Monday, July 19, 2010
Authenticating MVC 2 JSON Services from Win Phone 7 with OAuth Lite
One of the challenges I've been facing with using an ASP.Net MVC 2 site to return JSON data to my Win Phone 7 app is authenticating my requests. I don't want other people to be able to sniff on the data between my app and the server and start making malicious requests.
I started looking into a custom AuthorizeAttribute after spending most of last week looking into OAuth authentication methods for the FatSecret.com API service wrappers. If you're not familiar with OAuth, take a minute to read up on it.
I decided that I wasn't going to use the full OAuth authentication strategy, specifically, I boiled it down to three parameters and an HMACSH1 Hashed Signature. Basically, my signature format is this {HTTPMethod}&{ServiceURL}&{LimitedParmString}. Where my LimitedParmString consists of a standard OAuth "Nonce", a Timestamp (seconds from Jan 1, 1970 UTC), and your consumer key. My client (a Win Phone 7 app in this case) includes this signature as a request header called "oauthlite" when they make their service requests to the MVC Website.
On the server side, my custom AuthorizeAttribute named OAuthLiteAuthenticate takes the HTTPContextBase and constructs a signature based on a request header called "oauthlite". The custom request header is just a url encoded parameter string with the 4 parameters; the "Nonce", Timestamp, Consumer Key and Signature Hash computed by the requestor.
Here is an example "oauthlite" header:
You can get the gist of the authentication process by taking a look at this in-memory implementation of an OAuthLiteAuthenticator:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace OAuthLite.Server
{
/// <summary>
/// An in memory OAuthLite Authenticator example.
/// </summary>
public class OAuthLiteDictionaryAuthenticator : IOAuthLiteAuthenticator
{
// An "in-memory" key repository.
private Dictionary<string, string> _keyRepository = new Dictionary<string, string>()
{
// We only have one client, but you could add more.
{ "8b84444fbc09448da68ca14f000695cb", "83fbf4ea05df427bb3390d6d9a0fc626" }
};
private static string UrlFormat = "{0}://{1}";
#region IOAuthLiteAuthenticator Members
public bool Authenticate(HttpContextBase context)
{
if (context == null
|| context.Request == null)
return false;
var requestUrl = context.Request.Url;
var apiUrl = String.Format(UrlFormat, requestUrl.Scheme, requestUrl.Host);
var method = (HttpMethod)Enum.Parse(typeof(HttpMethod), context.Request.HttpMethod.ToUpper());
var header = context.Request.Headers["oauthlite"];
// We expect a parmstring including the signature.
if (String.IsNullOrEmpty(header)
|| !header.Contains("&"))
return false;
Dictionary<string, string> parms = new Dictionary<string, string>();
foreach (var parm in header.Split('&'))
{
string[] s = parm.Split('=');
if (s.Length < 2)
continue;
parms.Add(s[0], s[1]);
}
if (!parms.ContainsKey("signature") || !parms.ContainsKey("key"))
return false;
var signature = HttpUtility.UrlDecode(parms["signature"]);
parms.Remove("signature");
var key = parms["key"];
var secret = GetSecretByKey(key);
if ( string.IsNullOrEmpty(secret) )
return false;
return OAuthLiteHelper.ValidateSignature(signature, method, apiUrl, secret, parms);
}
private string GetSecretByKey(string key)
{
if (!_keyRepository.ContainsKey(key))
return null;
return _keyRepository[key];
}
#endregion
}
}
I've updated the Win Phone 7 JSON Services code example to use the new OAuthLiteAuthenticate attribute on an action called "Secrets" on the Product Controller. You can download the example below.
Download the code
Now Playing: Foals - Spanish Sahara
Tuesday, July 13, 2010
Data Driven Win Phone 7 Apps With MVC 2 JSON Services
I've been making a lot of little apps for Win Phone 7 in the past couple of weeks and I want to share a little bit of my code for other people who might be starting out and looking for some examples of creating a data driven Windows Phone 7 app.
We are going to be making a simple little product search for a fake company. We are going to show POSTing information to an MVC Controller action from our Win Phone 7 app, and we are going to show parsing a JSON response received from our MVC site and displaying it on the screen.
MVC 2 Website
The first thing I do when I'm creating a strictly service oriented site is to modify the Site.Master page to not display the login control, or the About page. I also, exclude the Account LogOn, Register and ChangePassword views so no one is tempted to register for the site. This step is optional, you can leave all of those things in, and you probably will have to if you have an existing MVC site you are altering.
Next, I create a new controller to serve my data. For our example we will call it ProductController and it will look something like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace WinPhone7.MVCExample.Website.Controllers
{
public class ProductInfo
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public interface IProductService
{
IQueryable<ProductInfo> GetProducts(Predicate<ProductInfo> filter);
void AddProduct(ProductInfo newProduct);
}
// This is dirty... but it's a demo
public static class ProductRepository
{
// An In-Memory persistable list of products.
public static List<ProductInfo> Products = new List<ProductInfo>()
{
new ProductInfo()
{
Id = 1,
Name = "Product 1",
Description = "Some sample product that is related to toys"
},
new ProductInfo()
{
Id = 2,
Name = "Product 2",
Description = "Some sample product that is related to sports"
},
new ProductInfo()
{
Id = 3,
Name = "Product 3",
Description = "Some sample product that is related to cars"
},
new ProductInfo()
{
Id = 4,
Name = "Product 4",
Description = "Some sample product that is related to boats"
},
new ProductInfo()
{
Id = 5,
Name = "Product 5",
Description = "Some sample product that is related to tools"
},
new ProductInfo()
{
Id = 6,
Name = "Product 6",
Description = "Some sample product that is related to technology"
},
};
}
public class MockProductService : IProductService
{
public IQueryable<ProductInfo> GetProducts(Predicate<ProductInfo> filter)
{
return ProductRepository.Products
.Where(prod => filter(prod))
.AsQueryable();
}
public void AddProduct(ProductInfo newProduct)
{
newProduct.Id = ProductRepository.Products.Count + 1;
ProductRepository.Products.Add(newProduct);
}
}
public class ProductSearchRequest
{
public string SearchTerm { get; set; }
}
public class ProductListResponse
{
public List<ProductInfo> Matches { get; set; }
}
public class ProductSearchResponse : ProductListResponse
{ }
public class ProductAddResponse
{
public bool Success { get; set; }
public int Id { get; set; }
}
public class ProductController : Controller
{
IProductService _products;
public ProductController()
: this(new MockProductService()) // Lazy man's dependency injection.
{
}
public ProductController(IProductService productServ)
{
_products = productServ;
}
public ActionResult All()
{
// Get all products by passing true predicate.
var allProducts = _products.GetProducts(prod => true);
var response = new ProductListResponse()
{
Matches = allProducts.ToList()
};
return new JsonResult()
{
// Make sure we allow get's
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
// Set the data to our response.
Data = response
};
}
public ActionResult Search(ProductSearchRequest request)
{
var termLowered = request.SearchTerm.ToLower();
var matches = _products
.GetProducts(prod =>
prod.Name.ToLower().Contains(termLowered)
|| prod.Description.ToLower().Contains(termLowered));
var response = new ProductSearchResponse()
{
Matches = matches.ToList()
};
return new JsonResult()
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = response
};
}
[HttpPost]
public ActionResult Add(ProductInfo product)
{
ProductAddResponse response;
if (!String.IsNullOrEmpty(product.Name)
&& !String.IsNullOrEmpty(product.Description))
{
_products.AddProduct(product);
response = new ProductAddResponse()
{
Success = true,
Id = product.Id
};
}
else
response = new ProductAddResponse()
{
Success = false,
Id = -1
};
return new JsonResult()
{
Data = response
};
}
}
I've included the response and request classes in the code example for brevity, but I usually separate these out into files in the models folder. Once we have our products controller in place, we can go ahead and run the website and see some results. Hit F5 to run the MVC Website, then navigate to /Product/All to see your example JSON response (I highly recommend Google Chrome and this JSON Content Viewer, makes the JSON all color coded and nice).
Win Phone 7 Services
Next, I go ahead and create my Services project as a Win Phone 7 class library. Now, I've written some helper classes to deal with requesting web content and parsing JSON results. I've included it in the Sample Code as a library called Service4u2. The meat and potatoes of this library is the BaseJsonService
using System.Collections.Generic;
using Service4u2.Json;
namespace WinPhone7.MVCExample.Client.Services
{
// Extra stuff included for brevity.
public class ProductInfo
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class ProductSearchRequest
{
public string SearchTerm { get; set; }
}
public class ProductListResponse
{
public List<ProductInfo> Matches { get; set; }
}
public class ProductSearchResponse : ProductListResponse
{ }
public class ProductAddResponse
{
public bool Success { get; set; }
public int Id { get; set; }
}
public static class ExampleUrlHelper
{
// Singleton pattern url helper.
private static ServiceUrlHelper _helper =
new ServiceUrlHelper("http://localhost.:49709");
public static ServiceUrlHelper Instance { get { return _helper; } }
}
// Product List Service.
public class ProductListService : BaseJsonService<ProductListResponse>
{
public void GetProductListAsync()
{
var url = ExampleUrlHelper
.Instance
.GetControllerActionParameterUrl("Product", "All", string.Empty);
StartServiceCall(url);
}
}
// Product Search Service.
public class ProductSearchService : BaseJsonService<ProductSearchResponse>
{
// We have to wrap our request so it is URL encoded properly for MVC.
// Our Product/Search action expects a parameter named request.
public class SearchRequestWrapper
{
public ProductSearchRequest request { get; set; }
}
public void SearchProductsAsync(ProductSearchRequest searchRequest)
{
var url = ExampleUrlHelper
.Instance
.GetControllerActionParameterUrl("Product", "Search", string.Empty);
var postData = new SearchRequestWrapper()
{
request = searchRequest
}.Postify(); // Postify our data, e.g. request.SearchTerm=blah&foo=1
StartServiceCall(url, HttpMethod.GET, postData);
}
}
// Product Add Service.
public class ProductAddService : BaseJsonService<ProductAddResponse>
{
// We have to wrap our request so it is URL encoded properly for MVC.
public class ProductAddWrapper
{
public ProductInfo product { get; set; }
}
public void AddProductAsync(ProductInfo productToAdd)
{
var url = ExampleUrlHelper
.Instance
.GetControllerActionParameterUrl("Product", "Add", string.Empty);
var postData = new ProductAddWrapper()
{
product = productToAdd
}.Postify();
StartServiceCall(url, HttpMethod.POST, postData);
}
}
}
Notice I've copied and pasted the request and response classes from the MVC project. This is a possible down-side to doing services this way. You won't get the autogenerated code that you get from a WCF service, but on the other hand, you will be better prepared in the long run to consume services from other websites that don't expose WCF implementations.
What we are doing is just preparing a URL and then making a request. The actual parsing of the JSON and converting it to our Result class is done by a DataContractJSONSerializer in the BaseJsonService class. To handle the result, or an error, just subscribe to the relevant events in your service consumer.
The Win Phone 7 App
The problem with the win phone 7 app example code is that everyone has different ways of doing things with WPF. I've put together a little MVVM framework tailored to the Win Phone 7 stuff and have included it with the example source code. I'll skip all the XAML and ViewModel code, because it's pretty standard MVVM stuff. Take a look at this demo video to get a look at how our app looks so far.
Hopefully, you've gotten pretty comfortable using MVC and JSON services with your Win Phone 7 apps. Feel free to use any of the code in this example. The Service4u2 and MVVM4u2 libraries are open source under the Microsoft Public License (Ms-PL).
Now Playing: Counting Crows - Friend of the Devil
Win Phone 7 "Words" Game - Mo Words
My wife and I have been playing a lot of word games lately on our IPhones. I've also been playing around with the Win Phone 7 SDK and I've been looking for a good project to work with. So, as a result, I made a little "Words" game called Mo Words.
I've just recently got it to a point where I could play a whole game. But there is still some work to be done for the play notifications (I'm hoping to get Push notifications working this weekend).
The game uses an MVC 2 website returning JSON responses as it's service layer. I hope to put together a couple posts on how I make data driven win phone apps with MVC 2 websites, including how to authenticate to an MVC 2 site and all that.
So, without further ado, here is a demo video (sorry it's choppy, the loading animations and dragging don't match the smoothness of the actual game, it's much better in person) and some screen shots.
Now Playing: Animal Collective - My Girls
Monday, July 12, 2010
FatSecret Sharp - C# Nutrition and Exercise Tracking Services
I started looking into FatSecret.com's REST API this weekend after wondering how hard it would be to make a Food Tracking App for Win Phone 7.
My first step was to take a look at their REST API Documentation, which shows a list of their available methods and how to authenticate using OAuth. It turns out, the hardest part of being able to get data from their services is the OAuth stuff.
OAuth Primer
Basically, OAuth works like this; You get a Consumer Key and a Consumer Secret from their API. You use these to "Sign" your requests. The "Signature" is built up using 3 components joined by an "&"; The method you are using to request (POST or GET), the uri of the service (Url Encoded), and the query parameters (ordered alphabetically by key, then value, then Url Encoded).
{HTTPMethod}&{ServiceUrl}&{OrderedParameters}
GET&http://platform.fatsecret.com/rest/server.api&a=foo&oauth_consumer_key=demo&oauth_nonce=abc&oauth_signature_method=HMAC-SHA1&oauth_timestamp=12345678&oauth_version=1.0&z=bar
Final Version:
GET&http%3A%2F%2Fplatform.fatsecret.com%2Frest%2Fserver.api&a%3Dbar%26%26oauth_consumer_key%3Ddemo%26oauth_nonce%3Dabc%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_version%3D1.0%26z%3Dbar
Then you make your request and hope everything matches up on their side.
FatSecret C# Service Wrappers
The end result of digging into the API was a library to wrap the nutrition and exercise services. Now there is an easy way to search for nutrition information in C#. Visit the FatSecretSharp project on codeplex for examples and code. I'm hoping to start making a Win Phone 7 Application for Food Tracking in the next couple weeks.
Now Playing: Weird Al - Fat
Wednesday, June 23, 2010
My Sail City - Win Phone 7
I've been working on a website in my spare time that tracks sailing trips and lets you share them with your friends. The site uses the new HTML5 GeoLocation API's for tracking a user's movements on the water and then giving a grade to the trip once they are done. Trip scores are based on time, distance and the weather conditions during their trip. Eventually, you get enough points to grow through the ranks.
I've also been looking into the new Win Phone 7 resources and wanted to make a proof of concept out of the website. Here is the result, a quick demo of a Win Phone 7 app that uses MVC 2 as it's service layer. I created a new "Area" (a new feature in .Net MVC 2) called API that exposed most of my necessary data as JSON based REST-like services. I'll try to post something with more technical detail later.
Now Playing: Styx - Sail Away (come on, that's like... mandatory song attribution...)
Friday, April 23, 2010
Exceptional Visualizer
This is a shameless cross post of the project introduction for a new project I just started on CodePlex to help with debugging complex PRISM dependency resolution errors called Exceptional Visualizer.
Project Description
A Debugger Visualizer for Visual Studio 2008 that allows for effective visual tracing of deep Exception stacks. Useful for Unity Resolution Exceptions as seen in PRISM (Composite Application Guidance); such as Microsoft.Practices.Unity.ResolutionFailedException and Microsoft.Practices.ObjectBuilder2.BuildFailedException.
Screen Shots
Other Info
This project displays the Exception information in a WPF window. This is an example of a Debugging Visualizer that uses WPF for visualization.
Now Playing: Otis Taylor - Nasty Letter
Saturday, January 9, 2010
Fluent State Observer for Reactive Extensions / Rx Framework
I've been messing around with the new Reactive Extensions for a couple weeks and wanted to build something that would allow you to match patterns in an Observable stream.
For more detailed information about the Reactive Extensions, check out the Reactive Extensions API In-Depth Intro Video and other In-Depth Reactive Extension videos.
I came up with the following library and put it up on Codeplex as a project called Fluent State Observer in case I ever need to get to it again. I'm going to paste the project home page content here strictly for SEO purposes.
Description
The Fluent State Observer helps perform actions based on a pattern in an IObservable "stream".
This library is developed in C# and uses the Reactive (Rx) Extensions library for it's implementation of the IObservable pattern and helper extensions for creating anonymous observers.
For more detailed information about the Reactive Extensions, check out the Reactive Extensions API In-Depth Intro Video and other In-Depth Reactive Extension videos.
This project is developed by Jacob Gable.
Example Uses
The following examples are from the test project. The test project includes a mocked IObservable that pumps out TestElements in succession. The call to obs.ProcessBlocks() begins the stream of Observable items.
See the Observable Series these tests use
Match Complex Patterns
[TestMethod()]
{
// New up with a Mock IObservable that just pumps out items in this pattern ( 1, 2, 2, 3, 1, 2, 3, 4 )
var obs = TestObservables.BasicObservable();
var target = new FluentStateObserver
bool didMatch = false;
target
.StartsWith(x => x.TypeOfElement == ElementType.TestType1)
.FollowedBy(x => x.TypeOfElement == ElementType.TestType3)
.EndsWith(x => x.TypeOfElement == ElementType.TestType4)
.OnMatch(x => didMatch = true);
obs.ProcessBlocks();
Assert.IsTrue(didMatch);
}
Non-Greedy Matching
Matches only when immediately followed by something.
public void Should_Match_FollowedImmediately_Patterns()
{
var obs = TestObservables.BasicObservable();
var target = new FluentStateObserver
bool didMatch = false;
target
.StartsWith(x => x.TypeOfElement == ElementType.TestType1)
.FollowedImmediatelyBy(x => x.TypeOfElement == ElementType.TestType2)
.EndsWith(x => x.TypeOfElement == ElementType.TestType4)
.OnMatch(x => didMatch = true);
obs.ProcessBlocks();
Assert.IsTrue(didMatch);
}
Specify Reset / Disqualifying Conditions At Each Transition
Match 1, 5, 4, 3, 4, but not 1, 2, 4, 3, 4
public void Should_Reset_When_A_Reset_Condition_Is_Satisfied()
{
var obs = TestObservables.BasicObservable();
var target = new FluentStateObserver
int matches = 0;
target
.StartsWith(x => x.TypeOfElement == ElementType.TestType1)
.FollowedBy(x => x.TypeOfElement == ElementType.TestType3)
.ResetOn(x => x.TypeOfElement == ElementType.TestType2)
.EndsWith(x => x.TypeOfElement == ElementType.TestType4)
.OnMatch(x => matches++);
obs.ProcessBlocks();
Assert.AreEqual(0, matches);
}
The Mock Observable in these tests publishes the following series
new TestElement()
{
Message = "Message 1",
TypeOfElement = ElementType.TestType1
});
new TestElement()
{
Message = "Message 2",
TypeOfElement = ElementType.TestType2
});
new TestElement()
{
Message = "Message 2",
TypeOfElement = ElementType.TestType2
});
new TestElement()
{
Message = "Message 3",
TypeOfElement = ElementType.TestType3
});
new TestElement()
{
Message = "Message 1",
TypeOfElement = ElementType.TestType1
});
new TestElement()
{
Message = "Message 2",
TypeOfElement = ElementType.TestType2
});
new TestElement()
{
Message = "Message 3",
TypeOfElement = ElementType.TestType3
});
new TestElement()
{
Message = "Message 4",
TypeOfElement = ElementType.TestType4
});
That's it. Hope someone finds it useful.
Now Playing: Drake - I'm Going In (Explicit)