DarksideCookie

Come to the dark side...we have cookies!

SilverTweet – Building a Silverlight Twitter client part 3

Once again I am back to my Twitter client. The next step in my application is to create some view models to bind the view to. This includes adapting the models I get from the Twitter service to the interface that I am going to create, as well as creating some models of my own. The modification of the auto generated ones, is pretty easy to do using the “new” partial class definition, that the objects defined in by the service proxy use.

Anyhow, let’s get started with some coding. But before I get started with the viewmodels, I am going to create a very simple little layer of abstraction. What? Why? Well, I want to de-couple the Twitter service as much as possible. The reasons for this are a couple, but mainly because of the way Twitter works. Since it is on the web, it means that I need to have internet connection to access it. It also has a limit to the amount of requests one can do per hour. This means that if I work without an internet connection or do a lot of testing with loads of requests to the service, it might cause some problems. By de-coupling it, I can switch the implementation to a mocked version, removing the need for internet access as well as the request limits. It also makes it possible for me to create unit tests for my viewmodels if I wanted that. So this layer of abstraction gives me some options. Not that I will use any of them in this example, but I have the option if I ever needed.

So how do I create this abstraction. Well, in my case that is going to be a simple case of identifying an interface and creating a service locator. Generally, naming your service interface should be something generic and so on and so on…now this is simple and should be so. So I have created an interface called ITwitterService. It basically declares 4 functions. They define the 4 things that we can do using the service. Each one of these functions have 2 methods and an event. More or less like the proxy that VS generated for us when creating the service reference. But the interface makes a few modifications to the methods. The proxy methods all pass tokens back and forth to Twitter. My interface ignores this, and rewrites the method signatures as follows

public interface ITwitterService
{
void GetAccessTokenAsync(string pin, AuthToken authToken);
void GetAccessTokenAsync(string pin, AuthToken authToken, object userState);
event EventHandler<GetAccessTokenCompletedEventArgs> GetAccessTokenCompleted;

void GetAuthorizationUrlAsync(object userState);
void GetAuthorizationUrlAsync();
event EventHandler<GetAuthorizationUrlCompletedEventArgs> GetAuthorizationUrlCompleted;

void TweetAsync(string text, object userState);
void TweetAsync(string text);
event EventHandler<TweetCompletedEventArgs> TweetCompleted;

void VerifyCredentialsAsync(object userState);
void VerifyCredentialsAsync();
event EventHandler<VerifyCredentialsCompletedEventArgs> VerifyCredentialsCompleted;

void GetTimelineAsync(long? sinceId, int? count, object userState);
void GetTimelineAsync(long? sinceId, int? count);
event EventHandler<GetTimelineCompletedEventArgs> GetTimelineCompleted;
}

 

So this gives me a cleaner interface and makes sure that the classes that interact with it doesn’t need to be aware of the whole token thing. The actual implementation to get around it has some caveats and could probably be made a bit nicer, but it works.

So how do I change the interface of my generated proxy class? Well, what you DON’T do is go in and modify the auto generated code that VS gives you. You could do this, but that would make it impossible to update the service reference if we ever extended the functionality. Luckily, Microsoft came up with partial classes a while ago. And all the classes in the proxy are implemented as such. So we can actually extend them to our hearts content. The only problem is that we can’t add our own constructors as freely as might want to. So to change the interface of the TwitterServiceClient created in the previous post, I have created a new class in my project. I name the class exactly the same, but add a partial to it. I then tell it that it should implement the ITwitterServiceClient interface and create the implementation for these. Some of these interface methods are actually already implemented by the auto generated part of the class. The other methods don’t really do anything except delegate the functionality to the auto generated methods. However, they “attach” the AccessToken, which is stored in a private member. The value of the AccessToken is set in a non interface defined method called SetAccessToken. Finally, the delegating methods also verifies that this has been set before being called, making sure that the methods aren’t being called before the AccessToken has been set. The entire implementation looks like this

public partial class TwitterServiceClient : ITwitterService
{
AccessToken _accessToken;

public void TweetAsync(string text, object userState)
{
if (_accessToken == null)
throw new Exception("AccessToken must be set before calling this method");
TweetAsync(text, _accessToken, userState);

}
public void TweetAsync(string text)
{
TweetAsync(text, _accessToken);
}
public void VerifyCredentialsAsync(object userState)
{
if (_accessToken == null)
throw new Exception("AccessToken must be set before calling this method");
if (userState != null)
VerifyCredentialsAsync(_accessToken, userState);
else
VerifyCredentialsAsync(_accessToken);
}
public void VerifyCredentialsAsync()
{
VerifyCredentialsAsync(_accessToken,null);
}
public void GetTimelineAsync(long? sinceId, int? count, object userState)
{
if (_accessToken == null)
throw new Exception("AccessToken must be set before calling this method");
if (userState != null)
GetTimelineAsync(_accessToken, sinceId, count, userState);
else
GetTimelineAsync(_accessToken, sinceId, count);
}
public void GetTimelineAsync(long? sinceId, int? count)
{
GetTimelineAsync(_accessToken, sinceId, count, null);
}
public void SetAccessToken(AccessToken token)
{
_accessToken = token;
}
}

As you can see, even if the code snippet is long, it is still just simple boilerplate code to delegate the calls and adding the AccessToken. By doing this, I don’t have to pass around the AccessToken all over the place.

So the service locator I was talking about is up next. This is really a sidestep from the whole thing. It also became more complicated than I wanted to. There are probably better ways of doing this, but this is what I came up with. I’m pretty sure it would have been better to use some existing IoC container, but I didn’t want to pull that into this simple example. So my service locator basically has 2 methods. One to register a type and one for getting an instance of it. However, I needed to add a delegate in there as well to do the initialization, since the AccessToken needed to be set as well. So since this is a sidestep, I will just post the code, let you flame me for it, and get on with the important part of this blog post

public class ServiceLocator
{
static Dictionary<Type, Delegate> _services = new Dictionary<Type, Delegate>();

public static void AddService<T>(TypeInitializer<T> initializer) where T : class
{
_services.Add(typeof(T), initializer);
}

public static T GetService<T>() where T : class
{
if (_services.ContainsKey(typeof(T)))
{
TypeInitializer<T> initializer = (TypeInitializer<T>)_services[typeof(T)];
return initializer.Invoke();
}
return null;
}
}

public delegate T TypeInitializer<T>();

 

The final step before getting into the viewmodels and so on, is to register the ITwitterService service with the service locator in the App class. The registration is not that complicated, but gets more complicated than I wanted based on the TypeInitializer<T> interface

private void Application_Startup(object sender, StartupEventArgs e)
{
TypeInitializer<ITwitterService> twitterInitializer = delegate {
TwitterServiceClient svc = new TwitterServiceClient("CustomBinding_TwitterService",GetServiceUrl("TwitterService.svc"));
svc.SetAccessToken(_token);
return svc;
};
ServiceLocator.AddService<ITwitterService>(twitterInitializer);
...
}

As you can see, I register the interface together with an anonymous method that will instantiate a new TwitterServiceClient and set its AccessToken. There are a few things to note here. First off is the GetServiceUrl method. This basically just helps me to build a URL to the local server. If you don’t pass in this second parameter, Silverlight will use the value in the ServiceReferences.ClientConfig file. This is however bound to my built in Cassini server, and changes ports constantly if I don’t tell it specifically not to. And as soon as I deploy to a server, I need to remember to reconfigure this. So instead I have this little helper to figure out the address to the server

private string GetServiceUrl(string serviceName)
{
string port = App.Current.Host.Source.Port != 80 ? ":" + App.Current.Host.Source.Port : "";
string ret = string.Format("{0}://{1}{2}/{3}",
App.Current.Host.Source.Scheme,
App.Current.Host.Source.Host,
port,
serviceName);
return ret;
}

 

And the next part to note is that i use a private member called _token. You will see more about this later…

So…this now means that any class in my project can just call the service locator and get hold of my service. And the service, could as I mentioned before be mocked if needed.

Unfortunately, there is even more preparation to be made. Just remember that it is all in the preparation. If you prepare well, the actual adventure will be less adventurous, simpler and less likely to make you scream things like !”£$%. So, what else is there. Well, I have actually made some more modifications to the objects in the proxy. Actually they are small changes to two classes. First of all, I needed a simple serialization method for the AccessToken class. I went for a simple and somewhat ugly solution. I decided to override the ToString method and implement a static Parse method. This works fine for my simple needs. What needs you say…well, you will see. I needs to store the AccessToken in IsolatedStorage between application uses, and doing it like this is simple. Once again, a partial class implementation with some modifications

public partial class AccessToken
{
public static AccessToken Parse(string str)
{
string[] parts = str.Split(';');
AccessToken token = new AccessToken()
{
UserID = long.Parse(parts[0]),
ScreenName = parts[1],
PIN = parts[2],
Token = parts[3],
TokenSecret = parts[4]
};
return token;
}

public override string ToString()
{
return string.Format("{0};{1};{2};{3};{4}", this.UserID, this.ScreenName, this.PIN, this.Token, this.TokenSecret);
}
}

And the final class that needed modifying is the Tweet class. This needs a really tiny change that will make a part of the implementation really simple. It needed a DateTime property that would convert the Twitter timestamp to local time. And also a way to have the PropertyChanged event raised from an external object. That sounds really odd I know, but it will make more sense later

public partial class Tweet : INotifyPropertyChanged
{
public void UpdateCreatedBinding()
{
RaisePropertyChanged("CreatedLocal");
}

public DateTime CreatedLocal
{
get
{
return Created.ToLocalTime();
}
}
}

OK, so now I need to spill some of my uncertainty to my blog. I don’t actually know if what I have just done is a good idea, but I’ve done it anyway. And no, I don’t mean the previous little workaround with the UpdateCreatedBinding method, I’m talking about using the auto generated proxy classes straight up like this. Modifying them, rather than wrapping them in a viewmodel. Basically tweaking the model to work with the view, instead of wrapping them in a viewmodel. Well, if you have any thoughts, go ahead and voice them…please! But I just think that wrapping the objects seem overworked in this case. They already implement INotifyPropertyChanged, and I can get the functionality I need into them by creating partial classes. Well, you will just have to make up your own mind about this. I don’t believe that there are absolute rights of wrongs in this. There might be upsides and downsides, but as long as it is simple and works, I like it…

So, now that we are done with modifying the auto generated classes, it is time to create the viewmodels I need to create. First out is a base class for my models. As you know if you have read my blog before, I almost always start with a common base class for my viewmodels and have it implement the INotifyPropertyChanged interface. This is no exception, however, in this case it will be abstract and include and abstract property of type string called Name. This will be used later for a little crude navigation thingy.

public abstract class ModelBase : INotifyPropertyChanged
{
public abstract string Name { get; }
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}

My first viewmodel to be created is one called MainModel. This will be the “driving” thing behind my application. In future blog posts, I will venture into Composite Application Guidance and things like that, which doesn’t work in that way, but this is not a big, composite application…

The MainModel has a few functions to fill. First of all, it handles all of the different views to show. It also handles the IsolatedStorage things. This should definitely be moved into a service and be placed in the service locator, but for now, it is in the MainModel. So lets unravel the class step by step. The declaration and constructor looks like this

public class MainModel : ModelBase
{
const string CREDENTIALS_FILENAME = "SilverTweet.credentials";

ModelBase _currentView;


public MainModel()
{
if (HtmlPage.Document.QueryString.ContainsKey("resetstorage"))
{
ClearStoredAccessToken();
}

AccessToken token = GetStoredAccessToken();
if (token == null)
{
SetLoginModel();
}
else
{
AccessToken = token;
CredentialVerificationModel verificationModel = new CredentialVerificationModel();
verificationModel.VerificationComplete += VerificationComplete;
verificationModel.VerificationFailed += VerificationFailed;
CurrentView = verificationModel;
}
}

public override string Name
{
get { return "Main"; }
}
}

So…there is a lot of things going on here. Let’s take it one step at the time. The first step in the constructor is actually there due to the lack of functionality in my application. Instead of having a button to clean the AccessToken from the application, adding a querystring parameter named “resetstorage” will do it for you. It is mainly for debugging. But I recommend that you, at the end of this series, test your knowledge by adding a command for doing this to one of the viewmodels and a button in the interface. But for now, it works as a way to clean out the IsolatedStorage.

The actual cleaning up is done in a method called ClearStoredAccessToken. It has a sibling method called GetStoredAccessToken. This is used next to see if the user has an AccessToken in IsolatedStorage. If this isn’t the case it sets the application up to show the login form. If a token is available, a property called AccessToken is set. The AccessToken property implements property changed notification as follows

AccessToken _accessToken;

public AccessToken AccessToken
{
get { return _accessToken; }
set
{
if (_accessToken == value)
return;

_accessToken = value;
OnPropertyChanged("AccessToken");
}
}

After that, the application is set up to verify the token to make sure it hasn’t been revoked.

As you can see from the code row that says “CurrentView = verificationModel;”, the MainView has a property called CurrentView. This is used to control what to show in the interface, as what to bind the UI to. This will become more obvious in the next post, so just bear with me for now.

public ModelBase CurrentView
{
get { return _currentView; }
private set
{
_currentView = value;
OnPropertyChanged("CurrentView");
}
}

So, what do I do in the IsolatedStorage methods? Well, nothing complicated. In the GetStoredAccessToken I check if there is a file with a specific name in storage, and if there is, I read it and parse the string in it to an AccessToken. The name of the file is actually stored as a constant in the class, since it is used in several places. The ClearStoredAccessToken starts out in the same way, with a check if the file exists. But if it does, it instead deletes it. These two methods are then also accompanied by a SaveAccessToken method. This obviously does the reverse of both of them. It creates a file and writes the AccessToken to it by calling its ToString method

 

const string CREDENTIALS_FILENAME = "SilverTweet.credentials";

private AccessToken GetStoredAccessToken()
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
if (storage.FileExists(CREDENTIALS_FILENAME))
{
IsolatedStorageFileStream fileStream = storage.OpenFile(CREDENTIALS_FILENAME, System.IO.FileMode.Open);
StreamReader sr = new StreamReader(fileStream);
string credentials = sr.ReadLine();
sr.Close();
return AccessToken.Parse(credentials);
}
return null;
}
private void SaveAccessToken(AccessToken token)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream fileStream = storage.OpenFile(CREDENTIALS_FILENAME, System.IO.FileMode.Create);
StreamWriter sw = new StreamWriter(fileStream);
sw.Write(token.ToString());
sw.Close();
}
private void ClearStoredAccessToken()
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
if (storage.FileExists(CREDENTIALS_FILENAME))
{
storage.DeleteFile(CREDENTIALS_FILENAME);
}
}

It is “a lot” of code, but it is pretty simple.

 

So, if we now start at the end where we have no token. In this case a method called SetLoginModel is obviously called. This method creates a new LoginModel, hooks up handlers for its LogInCompleted event and then sets it as the CurrentView. This means that the user will be displayed a login form. And when the login has been successfully completed, the LogInCompleted event will be raised

private void SetLoginModel()
{
LoginModel loginModel = new LoginModel();
loginModel.LogInCompleted += LogInCompleted;
CurrentView = loginModel;
}

 

So, what is happening in that LogInCompleted eventhandler? Well, not much actually. First off, I detach the handler. After that I raise the AccessTokenReceived event, save the AccessToken and switched the CurrentView by calling SetTimelineModel.

void LogInCompleted(object sender, PayloadEventArgs<AccessToken> e)
{
((LoginModel)sender).LogInCompleted -= LogInCompleted;
AccessToken = e.Payload;
SaveAccessToken(e.Payload);
SetTimelineModel();
}

The EventArgs being used for the event is a custom one that I have called PayloadEventArgs. It is basically just a simple EventArgs class with one generic property making it possible to use to pass a value to the handler…

public class PayloadEventArgs<T> : EventArgs
{
public readonly T Payload;
public PayloadEventArgs(T payload)
{
Payload = payload;
}
}

But what happens if I already have a token in IsolatedStorage. Well, in that case, it needs to be verified. This is done using the CredentialVerificationModel. This model has 2 events. One called VerificationComplete and one called VerificationFailed. I guess they are pretty self explanatory. Their handlers are quite simple. The xxxComplete handler detaches the handler and sets the CurrentView by calling SetTimelineModel, just as we would after having completed the login procedure. The xxxFailed also detaches the handler, but then it clears the IsolatedStorage and calls SetLoginModel, forcing a new login.

void VerificationComplete(object sender, EventArgs e)
{
((CredentialVerificationModel)sender).VerificationComplete -= VerificationComplete;
SetTimelineModel();
}
void VerificationFailed(object sender, EventArgs e)
{
((CredentialVerificationModel)sender).VerificationFailed -= VerificationFailed;
ClearStoredAccessToken();
SetLoginModel();
}

 

And the only thing left is to have a look at the SetTimelineModel method, which is so simple it is barely meaningful to show it

private void SetTimelineModel()
{
TimelineModel timelineModel = new TimelineModel();
CurrentView = timelineModel;
}

That is the implementation of the main driving model behind the application. My plan was to cover all of the viewmodels in this post, but it is just getting too big to handle. So I will move the other three models into the next post, extending the series by one post. Hopefully making it less heavy to read.

But since I guess some of you are curios about my “navigation thingy” using the CurrentView property, I will just explain it briefly. Basically, the main view in the application will bind to this property’s Name property (that sounds really bad, but I hope you get it). This way, it gets notified every time it changes. It then uses a little switch statement on the name to decide what usercontrol to show in the UI. It then loads up that control and sets its DataContext. As simple as that. This makes it simple to switch everything from one main viewmodel and have it control what is to be done by the user, without coupling it too bad and without telling the view how to show it. But we need to make sure that the view shows the different controls at the correct times to get it to work… And yes, there are other ways of doing this, but this way is once again simple and functional. And I have also added some animations to the usercontrols that makes their trantisions smooth and easy on the eyes…

I hope you have enjoyed this part as well, and that you came back for the last 2 posts. I really hope I manage to get it in to two posts, we’ll just have to see. But I think so… The comments box below is there to be used… :)

Cheers!

[UPDATE!]

A little code change was made on October 17th…
The MainModel used to have an event when an AccessToken was received. It has been changed into a property instead…

Part 4 is now available as well as Part 5

Posted: Sep 23 2009, 12:14 by ZeroKoll | Comments (0) |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: Silverlight
Manage post: :)
Comments are closed