Showing posts with label silverlight. Show all posts
Showing posts with label silverlight. Show all posts

Monday, January 26, 2009

The Poor Man’s Stock Quote Web Service

Ever wanted to programmatically fetch stock quotes? Ever look into it? I did. StrikeIron charges top dollar for their stock quote service, and, frankly, I don’t have that kind of money. But I can always go to finance.yahoo.com, and get the same information for free. Let’s exploit that, let’s create The Poor Man’s Stock Quote Web Service.

See it in action!

Using Windows Communication Foundation (Wcf), we will build a web service that takes a ticker symbol for a stock, grabs the text from the yahoo finance webpage, parses out the relevant stock quote information, and then returns a sweet StockQuote struct full of information. The legality of all this in a commercial application could probably be put to question, but we’ll leave that as an exercise for the reader.

Building a Wcf Service is very straightforward, and the source linked at the bottom is a Wcf sample perfect to introduce you to Wcf. This article isn’t an intro to Wcf, but if you’re quick, which I’m sure you are, you could pick it all up from the sample. See my other blog post to see how to host a Wcf service on a shared hosting plan.

First, we must define the ServiceContract for our Wcf Service:

[ServiceContract]    
public interface IStockQuoteService    
{    
    [OperationContract]    
    StockQuote GetQuote(string ticker);    
    [OperationContract]    
    List<StockQuote> GetQuotes(string[] tickers);    
}

As mentioned earlier, I’m going to use the Yahoo Finance to provide information for my Stock Quotes. Thus, the YahooStockService was born:

/// <summary>    
/// The Stock Quote Web Service that scrapes values from Yahoo's finance stock page.    
/// </summary>

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]    
public class YahooStockService : IStockQuoteService

In our Wcf service, we programmatically grab the text from a website using the HtmlScraper.GetPageContent function:

public static string GetPageContent(string url)    
{    
    WebRequest wreq = HttpWebRequest.Create(url);    
    WebResponse wres = wreq.GetResponse();    
    StreamReader sr = new StreamReader(wres.GetResponseStream());    
    string content = sr.ReadToEnd();    
    sr.Close();

    return content;    
}

Now that we have the page’s text, we can clumsily parse the text for the value that prefixes the content we are looking for. I usually break in my debugger, grab the Html page’s string value from the Watch window, and paste it in notepad. Then I look for the company name, and copy whatever’s in front of it.

Here is a simple example of the YahooStockService parsing for the Company Name:

private string ParseCompanyName(string page)    
{    
    // Regex pattern pasted from Html page.    
    Regex parseFor = new Regex("<div class=\"yfi_quote_summary\"><div class=\"hd\"><h1>");    
    return HtmlScraper.ParseContent(page, parseFor, "</h1>");    
}       


And now here’s the source. Many other parse functions exist in the sample, and we eventually end up with all the stock information we could need. Now go forth, poor one, and gather stock information to your heart’s content. At the time of this writing, it’s probably all going down anyways. GGgggooooo Bailout!

One note about the sample: it uses a Silverlight web app to consume the Wcf Service, you might need to install the Silverlight SDK.

References: Building a Web Service to Provide Real-Time Stock Quotes

Sunday, January 4, 2009

Using the PollingDuplexHttpBinding for a Silverlight Group Chat

1) A Quick Intro to the PollingDuplexHttpBinding

Comet technologies, such as AJAX push and HTTP server push, allow web pages to have data pushed to them from the server, rather than always having the client pull information. It mimics this feature by having the browser poll the server at regular but short intervals (~1 second) to check for updates. Now web pages can be updated dynamically without any user input. Lucky for us, Silverlight supports this using the PollingDuplexHttpBinding Wcf Binding, which does most of the heavy lifting.

In this article, we hope to build a basic Silverlight group chat application by connecting a PollingDuplexHttpBinding to a Wcf Service hosted on a shared hosting plan.

There are excellent introductory articles to this technology that are pretty much required reading if unfamiliar with the PollingDuplexHttpBinding (Skim the first link if pressed for time):

  1. Basketball score server by Dan Wahlin
  2. Stock quote server by Peter McGrattan

The bulk of the PollingDuplexHttpBinding functionality is covered in the blogs listed above. From here on out, I will talk about some of the higher level details involved in making the simple chat program on top of the PushDataReceiver.

2) The static list of clients.

Every time a client connects to our webservice, we instantiate a new instance of the GameStreamClient class and keep it in a static List<ChatClient>. This does restrict us to only being able to run our chat server on one appdomain.

private static List<IGameStreamClient> clients = new List<IGameStreamClient>();

Our service gets instantiated on a Per Session basis as shown by the mark up below. In retrospect, I actually think it should have been a singleton, but that's for another time.

[ServiceBehavior(InstanceContextMode =
    InstanceContextMode.PerSession,ConcurrencyMode = ConcurrencyMode.Single,AutomaticSessionShutdown = true)]


3) The inactivity timeout and the stay alive ping.

Each Wcf connection has an inactivity timeout that defaults to around 10 minutes. We want our clients to be able to idle in the chat room, and not get booted for inactivity. Here we introduce a stay alive packet to reset this inactivity timeout. The end user will know nothing of it, and this way they can idle all they want.

Message gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive","stayalive");

gameDataMsg.Properties.Add("Type", "StayAlive");

this.localClient.BeginReceive(gameDataMsg, EndSend, this.localClient);

4) I remove when I catch an exception when sending to a client.

With the PollingDuplexHttpBinding, the only way we will know if a client disconnects, is when the server fails to deliver a message. We cannot rely on the client to tell us when they are disconnecting, especially when considering that they are connecting from a browser; there's no real way to elegantly close out the client. Plus, they could just crash. As a result, there is no real disconnect, there is more of a send failure mechanism, that removes clients from the static list of ChatClients. In the proceeding ChatMessage broadcast, any clients that throw a CommunicationException/TimeoutException are removed from the server's client list. These timeouts could block the server however, so we must handle this asynchronously so as not to penalize connected clients.

foreach (IGameStreamClient client in clients)
{
    try
    {
        //Send data to the client
        if (client != null)
        {
            Message gameDataMsg =
                Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive",data,this.serializer);

            gameDataMsg.Headers.Add(MessageHeader.CreateHeader("Type", "", "DataWrapper"));
            client.BeginReceive(gameDataMsg, EndSend, client);
        }
    }
    catch (Exception ex)
    {
        // Exception caught when trying to send message to client so remove them from client list.
        // Should probably catch a more specific exception but I'll leave that as an exercise for the reader.
        clientsToRemove.Add(client);
    }
}
foreach (IGameStreamClient client in clientsToRemove)
{
    clients.Remove(client);
}


5) Using DataContracts and DataContractSerializers to send complex types.

Sending strings back and forth is not really fun. Complex types such as structs would allow for much richer data transfer. So it's a good thing Wcf supports DataContracts and has a DataContractSerializer that makes this process seemless.

private readonly DataContractSerializer serializer = new DataContractSerializer(typeof(ChatData));
// Serialize
Message
gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive",chatData,this.serializer);

// Deserialize
ChatData
chatData = receivedMessage.GetBody<ChatData>(this.serializer);


6) Adding Header information to the Message object so the Processor can serialize to the appropriate type.

When your application gorws in complexity, you will probably have multiple DataContracts, but your Wcf Callback contract will only have one message handler, and you will need to programmatically handle the Message Body. To know what that body is so you can deserialize it, the sample tags the outgoing message with type strings in the Headers. This acts as a form of metadata for the message and allows the caller to deserialize the DataContract to the message of the passed type, allowing proper complexity to the callback contract. This is a lot better than clumsily having a class with a body and a type, and dealing with deserialization logic yourself.

//Server creates the message and tags it with a type.
Message gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive","stayalive");

gameDataMsg.Properties.Add("Type", "StayAlive");

// Receiver parses the message type and deserializes using the correct deserializer.
// Check message type
string type = string.Empty;
for (int i = 0; i < receivedMessage.Headers.Count; i++)
{
    if (receivedMessage.Headers[i].Name == "Type")
    {
        type = receivedMessage.Headers.GetHeader<string>(i);
        break;
    }
}
// Dispatch message based on type.
switch (type)
{
    case "StayAlive":
    break;
    case "DataWrapper":


7) Source code.

Source code

Tuesday, November 18, 2008

Oct 31st == Nov 30th && Shared plans == win!

So much for that beta by Oct 31st. I've had a lot of petty life things distract me from what's important: Red, White, And Blue! It is coming together though and I have high hopes. There are some interesting obstacles involved with keeping many clients in sync (quasi sync at least), and all the bugs that can occur when you have a client that loses sync with the db.

I have a really annoying issue where a browser's cache will prevent users from downloading a new client, so should I rename my client on every update just to trigger a download? Sounds clumsy. I don't think I would like old silverlight clients pinging my services either, so will I have to check a version string on every login? Seems so.

I am relying on the fact that all of my WCF sessions will exist in the same AppDomain, so I can use a single static to keep track of users. Risky and clumsy, I know, but I'm already stretching the capabilities of a shared hosting plan about as far as possible. I don't know many websites on shared hosting plans using WCF services, Ajax style PollingDuplex binding, Linq2Sql , hosting silverlight. This stuff came out last night (pretty much), so I've been happy with how much I can get away with on a shared hosting plan.

It really is a tribute to the computer industry when you can get so much power for a measly $100 / year hosting plan. This is our one up on any other industry: the low barrier of entry. Can you even imagine something similar in the auto industry? Investment banking? The factories, connections, and brown-nosing needed to do the most trivial things in other industries makes me love my field that much more.

See you next Sunday and have a happy thanksgiving!

Sunday, October 12, 2008

Red, White, and Blue

The final title for my web game, slated for an oct 31st beta. Three parties, three colors: red, white, and blue. I decided to pull back on the plot in an effort to stay out of politics, we don't need half-assed political dialogue in a budget web game prototype (v2?).

The next piece of tech I would like the exploit is Silverlight's Polling Duplex support. Similar to the "AJAX Push" or "HTTP server push", this technique, coined Comet by the web community, allows one to emulate packet "Pushing" in the browser, without having to face the hurdles of socket programming, policy files, and blocked ports. I'm pretty excited about it's capabilities and it's ease of implementation with WCF and Silverlight. Although it won't be enough for any serious real-time multiplayer communication, it'll be "good enough" for most scenarios, especially those found in a turn-based world.

As a side note, does anyone have a problem with dandruff dirtying up their keyboard?

Monday, September 15, 2008

Secession

Today's bankruptcy filing of Lehman Brothers and Bank of America's purchase of Merrill Lynch defined a new Black Monday in what could be a new Great Depression. This event is sure to make future iterations of Globalization when the Economy portion of the game is released, but let's not get ahead of ourselves. For now, let's keep our eyes on the November 30th Alpha which will have the turn-based combat. This first chapter of Globalization will be titled Secession:

Set in 2020, the Republicans have just won their 6th straight presidential election, only to be rewarded with a country torn asunder. The previous decade saw numerous clashes between the two political parties, and spawned thoughts of secession in the halls of democratic strongholds. Throughout the years, media slammed small town conservatives, bible beaters denounced godless liberals, and now, politics wasn't just a stance, it was a way of life.

During the chaos, another ideology bubbled into significance in the northwest. The Green Party Libertarians rose to take the mantle of the west, rejecting the status quo of America's two party System, and jumped into the increasingly hostile fray.

The Republican's November victory was the last election to be held across the Union. Seeking independence from the larger Republican electoral block, the other parties seceded immediately and drafted their own policies. This did not calm the tension, and the new borders became the new frontier.

Thus was born the War of the Primaries, a sempiternal struggle that broke the union, shook the balance of power, and emboldened America's enemies.


Welcome. Choose your party ...


That's all I've got. I chose to have a 3 party campaign to add complexity to diplomacy, and to prevent any one party from becoming too powerful. All party systems seem to evolve into a virtual two-party system, where alliances are formed between the weaker factions to secure victory. Hopefully, the three party campaign will emulate that idea; when there's an imbalance in power, the weaker parties will pair up against the superpower.


With regards to the actual game. I've focused on tool development, with the world editor about 40% complete, and a lot of database work finished. I am looking forward to the ability to manipulate the story and the world in real time. It allows for some interesting dynamics that simply cannot be matched by a fixed plot stamped onto a disc.

In another note, I've read Vargo's posts and can't help but notice his writing superiority. I hope to improve my writing, but I have a ways to go before I can match his eloquence. I DO wonder how many rewrites he goes through for one post ...

Sunday, August 24, 2008

Render Target!


Progress is creeping forward in my Silverlight game. I've heard from 2 other people interested in helping out with the project and have start to refactor heavily as a result.

There are many complications involved when your dev team grows bigger than 1, especially with members new to the technology. As a result, I've gone so far as to throw up a render target (quality is questionable) which you can see to the left, and a bunch of probably unseen UML diagrams which help me lay out my thoughts as much as it helps the other devs figure out what I'm trying to do.

So far, this project has incorporated a lot of the latest and greatest .NET 3.5 has to offer, such as: WCF Services, LINQ, LINQ2SQL, and XAML with Silverlight/WPF (for tools).

It's been great learning all this tech, and I hope it'll result in a great game. It might be a sip of the Kool-Aid , but hearing about Mike's forays into the IPhone SDK, and having a few stints into the LAMP stack, the Microsoft dev environment seems to be unmatched. With some experience and a decent code library, one could create a ridiculously powerful application in a ridiculously short amount of time.

Saturday, August 2, 2008

So long DotNetNuke

My stint with DotNetNuke looks like it's coming to a close. I think DNN is fantastic, but I want to create a complete silverlight experience. Having remnants of Web 1.0 HTML floating around, contaminating my Rich Internet Application like dust on a diamond, just detracted from the user experience I seek.

What does this mean work load wise? I know have to write a login WCF service. Apparently ASP.NET has a rich set a libraries for this, complete with Membership roles. So perhaps it won't be too painful, and I will be able to dictate exactly what I want from my user., instead of lazily requesting your First and Last Name just to keep DNN happy.

Silverlight 100% here we come.

Sunday, July 27, 2008

DotNetNuke and Silverlight Chatter done!

I finally have a framework up for logins and other mundane albeit necessary web things. Using DotNetNuke, I will be having an optional login for my silverlight games. You can check out how to plug silverlight modules in DotNetNuke right here:
http://dnnsilverlight.adefwebserver.com/Silverlight20/tabid/65/Default.aspx

I wanted to take a very minimalist approach, deferring most of the page space to the hosted silverlight module, rather than slamming my viewers with clumsy div boxes that seems to be standard for enterprise web pages. You can check it out below (ignore the placeholder silverlight button):



I custom skinned the Dnn portal which was extremely easy. Don't fall for the lazy trap and buy off-the-shelf skins, they tend to be garbage anyways. Here's a great site to learn how to skin Dnn sites:
http://www.dotnetnukerocks.com/tabid/3167/Default.aspx

If you are just starting off, remember, only edit the .htm files. The "parse skin package" will generate the .ascx file for you to manipulate later. You'll know what I talk about after reading / watching the tutorial linked above.

To get my silverlight app to benefit from the user login received by DotNetNuke, I pass the information as InitParams to the Silverlight module. I leaned away from marshalling data back and forth between JavaScript and Silverlight because of the added difficulty of doing this inside a DotNetNuke module. I might exploit that capability in the future, but for now, I'm just happy with a unique username that I can plug into my own database to create a personal gaming experience perhaps even across multiple games.

As for my associate Vargo, he's been silent lately, probably waiting to have something substantial to show in his next post. Don't wait up.

Saturday, July 19, 2008

Indecision in Game Design

Every week my game changes. This week, we're looking at Civilization meets Supreme Commander with a dash of Wall Street (in game stock ticker reflecting the game economy, stock purchasing incorporated in full force!). A game will be played simultaneously by at least ~40 players in their browser and last around a month. They log in every day or so and spend 30 minutes managing their country/state/corporations. The first chapter will be titled "Secession" and only contain the United States. I'm trying to limit the scope for the initial release while keeping the environment interesting. I don't know about you, but I've always wanted to invade Jersey.

Keep posted for progress reports! My alpha will most likely by a single player game with no ai but a real time version of the game described above, to test out physics and game mechanics.


I would like to take a moment to apologize for the ramblings of Vargo. He's spamming his own blog with gibberish and making the whole site look pretty amateur. Maybe after he reads this, he'll clean it all up. I wish there was an option to view posts by author, if there is let me know. For now, to save you time, just look for posts by d-roc. Vargo's posts combined might produce one with substance. I hope this doesn't continue and again, sorry.

Saturday, July 12, 2008

Initiative and Beyond

There's a lot of talk out there with the promise of rich internet applications. Let me add to the pile of e-promises and tell you all right now what my purpose is: To put the BLING in rich internet applications. That's right, Bling. This blog will serve to document my adventures with Silverlight, something I'm equally excited and frustrated about. Excited, because it's a subset of WPF, and frustrated, because it's a ridiculously SMALL subset of WPF (No triggers! Seriously). There is already a very clean application that can be used with the Silverlight 2 beta 2 that you can find here:

http://www.farseergames.com/

My cohert, Vargo, spoke endlessly of the ultimate blog, with promises of tutorials, vlogs, discussion boards, and the community that would come with it. What was the result, months after the vision? Nothing. The first step is the hardest, is this why he never takes it? As is the norm, I took the liberty of relieving him of that step and created the page you are looking at now. Wow, action! Imagine that. I remember the last idea we had, another great one. Behold the glory of an internet multiplayer 3D platformer featuring shader instancing, shadow mapping, etc, which was code named Project Earnie:



Who's idea was it? His. What did he do? Nothing. His sermons only yield inaction. But there is a hidden fruit to all this malice: He inspires me to be different. And so my disposition towards development has been cemented as: Don't talk, Do. I'll be sure to deliver something tangible within the next few months, mark my words.

d-roc

Wednesday, June 25, 2008

WPF a must for Silverlight

If you're interested in Silverlight, be sure to learn WPF first. Or you could do everything backwards like me: traverse the logical tree and set Dependency Properties by hand in C# code (don't do it).