DateTime + WCF: How I tamed the beast

I have been working a bit with WCF lately and like everyone else use Json with WCF I ran into some issues with DateTime formats. I kept trying to find a valid solution to this where it outputted a readable value.

Eventually I started outputting the DateTime as a formatted string and this worked, but it meant I have to create new string variables in all of my classes instead of the DateTimes that I already had and was using, but then I still needed the variable in its DateTime form.

So I came up with the WCFDate class, at its heart this class outputs a string in a set format, this allows it to be easily read by what ever needs to. I could then replace all of my DateTimes with WCFDate and all was good in the world.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

/// <summary>
/// Class to help get around the craziness of WCF DateTime formats (Use this class instead of DateTime for WebService Models)
/// </summary>
public class WCFDate
{

    public static string DateTimeFormat = "yyyy-MM-dd hh:mm:ss zz";

    /// <summary>
    /// The Date as a formatted string
    /// </summary>
    public string Data { get; set; }

    /// <summary>
    /// Basic constructor (with no value)
    /// </summary>
    public WCFDate() { }
    /// <summary>
    /// String constructor setting a Formatted string for the DateTime
    /// </summary>
    /// <param name="data"></param>
    public WCFDate(string data)
    {
        Data = data;
    }
    /// <summary>
    /// DateTime constructor, sets the Data to the formatted String from the DateTime
    /// </summary>
    /// <param name="date"></param>
    public WCFDate(DateTime date)
    {
        Data = date.ToString(DateTimeFormat);
    }

    /// <summary>
    /// DateTime constructor, sets the Data to the formatted String from the DateTime
    /// </summary>
    /// <param name="date"></param>
    public WCFDate(DateTime? date)
    {
        if (date.HasValue)
        {
            Data = date.Value.ToString(DateTimeFormat);
        }
    }

    /// <summary>
    /// Check if the class is holding a Date or not
    /// </summary>
    public bool HasDate
    {
        get
        {
            return !string.IsNullOrWhiteSpace(Data);
        }
    }

    /// <summary>
    /// Gets the DateTime the class represents
    /// </summary>
    /// <returns></returns>
    public DateTime GetDate()
    {
        try
        {
            return DateTime.ParseExact(Data, DateTimeFormat, CultureInfo.CurrentCulture);
        }
        catch
        {
            return new DateTime();
        }
    }
}

Follow the Gist of this class or feel free to add to it.

AppEvents – Do stuff when things happen (WP7)

Ever wanted an easy way for apps to track certain events then run code based off what events the user has triggered? Well now you can with AppEvents!

So AppEvents is a Windows Phone 7 library to manage events for a user across multiple sessions. In this example I will use it with CodeTrack to prompt the user to rate the app after they have added 3 repos.

Lets get started, App.xaml.cs (this code can be put anywhere in the app but I felt this was better to be done at the start of the app)

public App()
{
    ...
    EventClient.New()
        .Add(RuleSet.When("rate-app",
            el => el.Any(e => e.Name == "addrepo" && e.Occurrrences.Count > 2))
            .Do(r => AskToRate())
        );
}

Now lets break that down, first we have the New() function being called, this creates the instance (and sets the Current singleton in the EventClient class). It also uses the default JsonEventStorageProvider to store the EventStore data, this can be overwritten with a type parameter on the new function:

EventClient.New<MyCustomEventStoreage>()

Now this is where the RuleSets are added to the client using RuleSet.When() The first parameter of this function is a name of the rule. This is mainly to keep track of the rule and make sure we don’t run it twice. The second parameter is a Func<UserEventList, bool> which means we can create lamba expressions to be run agains the UserEventList object, this expression tells the RuleSet when it should fire its Do Action.

    .Add(RuleSet.When("rate-app",
        el => el.Any(e => e.Name == "addrepo" && e.Occurrrences.Count > 2))
        .Do(r => AskToRate())
    );

So where do I get it?

The last part to this is firing off the events this part is very simple.

    EventClient.Current.Fire("addrepo");

And thats pretty much it, the library then does the rest

The library also allows for manual checking of events if for instance you fire an event on a page but want the RuleSet to be executed on a different page. To do this we simply add a false optional parameter to the Fire method to stop it running the RuleSets with the event. We can also manually run rules, either singly by the RuleSet name or all the rules in the list. We can also set the EventClient to not save the EventStore using the provider each time (and just have it saved later for performance).

EventClient.Current.Fire("addrepo", false);
EventClient.Current.Fire("addrepo", false, false);
EventClient.Current.RunRule("rate-app");
EventClient.Current.RunRules();
EventClient.Current.SaveEventStore();

So where do I get it?

The project if on GitHub for your forking, issues and discussions.AppEvents on Github.

Windows Mobile 6: Legacy

I have also made a Windows Mobile 6 version of this library but haven’t actively tested it too much, if you feel like giving it a go be sure to let me know how you go.

Dropbox on Windows Phone 7 with DropNet

So I have been working on an open source Dropbox client library for a while now called DropNet. I have recently put this project into NuGet so its super easy to add Dropbox support to your Windows Phone 7 apps.

Update: The source for this sample project is available here: http://bit.ly/dYjRnW

Update: The DropNet and DropNet-WP NuGet packages have been merged and allow for both Project Types.

I’ll start with a File -> New Project, creating a sample Windows Phone Application.

FileNew2

First thing to do is install the DropNet package, NuGet will automatically detect the type of project you are using and add the DropNet reference for that project type (eg. DropNet.WindowsPhone for Windows Phone 7 projects.)

DropNetNuGet

Ok, now we can start with the App, for starters I created a global variable for my DropNetClient instance.

GlobalClient = new DropNetClient("API KEY", "API SECRET");

Now from that we will need to let the user login so my main page has a basic login form, 2 textboxes for Email and Password and a button to make it work.

private void Login_Click(object sender, RoutedEventArgs e)
{
    //try login
    App.GlobalClient.LoginAsync(_model.Email, _model.Password,
        (response) =>
        {
            if (response.Data != null)
            {
                //DropNet automatically sets the result token inside the client
                NavigationService.Navigate(new Uri("/FilesPage.xaml", UriKind.Relative));
            }
        });
}

DropNets Login function automatically saves the user Token and Secret to its client instance so we dont have to set it. Then I just navigate to a new page where we will attempt to browse our Dropbox Folder.

This page has a basic view model with 1 property for the folders content.

private ObservableCollection<MetaData> _contents;
public ObservableCollection<MetaData> Contents
{
    get { return _contents; }
    set
    {
        _contents = value;
        NotifyPropertyChanged("Contents");
    }
}

Pretty easy, the page itself simply binds this collection to a listbox displaying the Name and an icon if its a folder.

Ok, now to actually get the data from Dropbox… We do this by calling our DropNetClient’s GetMetaDataAsync method. This method takes a path parameter so we can tell it which folder to get the metadata for.

App.GlobalClient.GetMetaDataAsync("/",
    (response) =>
    {
        foreach (var c in response.Data.Contents.OrderBy(f => f.Name).OrderByDescending(f => f.Is_Dir))
        {
            _model.Contents.Add(c);
        }
    });

Browse1

After getting the MetaData I then order it, folders first then alphabetically.

Wait, really? Thats it?

Yep! Thats my Dropbox folder.

Now to make it even better we can handle the listbox’s selection change event and if the selected item was a folder we can show its contents.

private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
    if (e.AddedItems.Count > 0)
    {
        var selected = (e.AddedItems[0] as MetaData);

        //if its a folder browse to it
        if (selected.Is_Dir)
        {
            _model.Contents = new ObservableCollection<MetaData>();
            App.GlobalClient.GetMetaDataAsync(selected.Path,
            (response) =>
            {
                foreach (var c in response.Data.Contents.OrderBy(f => f.Name).OrderByDescending(f => f.Is_Dir))
                {
                    _model.Contents.Add(c);
                }
            });
        }
    }
}

 

There we go, thats the basis for a Dropbox app using DropNet, lets see what we can come up with!

DropNet Implements most of the API’s functions, including :

  • Uploading files
  • Downloading files
  • Creating folders
  • Creating an account
  • Getting account info
  • Deleting files/folders
  • Data usage counter

I’m always updating the project over at GitHub, drop by and let me know what you think or if you have any feature requests/bugs. GitHub Project.

Or check out the NuGet Package here.

Browse3Browse2

BitBucket API from Windows Phone 7 and C#

With my latest update of CodeTrack (1.2) I implemented BitBucket as a provider, so you can watch repositories from there now as well. On the app itself there are a few search functions using the BitBucket API, this post will provide some insight and example code for doing this.

So basically I wanted to go from having nothing at all (no BitBucket user, no username, no repo slug/id) to being able to search for repositories by either their name or their owners username.

Note: The BitBucket API has recently changed to allow you to do this by giving the repository responses the Onwer property.

As always, RestSharp was used in the making of this code sample.

The 2 requests share the same response class BitBucketRepoList, this class is pretty simple because we are calling the API anonymously where using a BitBucket username/password would return a more detailed response.

public class BitBucketRepoList
{
    public List<BitBucketRepo> Repositories { get; set; }
}

public class BitBucketRepo
{
    public string Website { get; set; }
    public string Slug { get; set; }
    public string Name { get; set; }
    public string Owner { get; set; }
    public int FollowersCount { get; set; }
    public string Description { get; set; }
}

Searching by Repo Name

This request is pretty straight forward, RestClient with the base url for the API, RestRequest with the Resource “repositories” then add a get parameter of "name” with the search term. (API Doco)

_client = new RestClient("https://api.bitbucket.org/1.0");
var request = new RestRequest("repositories/");

request.AddParameter("name", searchTerm);

_client.ExecuteAsync<BitBucketRepoList>(request, (response) =>
{
    //Do stuff here with response
});

Searching by Repo Owner

Now for this request, BitBucket API doesnt actually support searching on usernames so these must be exact matches on the username.

_client = new RestClient("https://api.bitbucket.org/1.0");
var request = new RestRequest("users/{username}");

request.AddParameter("username", username, ParameterType.UrlSegment);

_client.ExecuteAsync<BitBucketRepoList>(request, (response) =>
{
    //Do stuff here with response
});

 

And there you have it, BitBucket API from Windows Phone 7. (The above code will also work in Silverlight/WPF as well as Win forms or ASP.NET depending on the version of RestSharp used.)

CodeTrack–Source control monitor for Windows Phone 7

HomeCodeTrack is a Windows Phone 7 app for monitoring source control repositories.

Recently I have become more and more active in the open source community, with many different projects on the go, be it for work or a side project im working on or something else entirely. So I wanted an application where I could keep up with progress on these projects as well as others, and this is how the idea of CodeTrack came about.

CodeTrack has been designed to be as simple as possible. Users add repos, they appear in their list, commits show up in their feed and they get push notifications when commits happen.

Current Features:

  • Ability to add Repositories from Github (public only) by searching
  • SVN Repository support
  • View commit feed of all “watched” repositories
  • Push Notifications for when new commits arrive
  • Shake to refresh

Planned Future Features:

  • Push Notifications per repository (allowing the user to set which repos they want to be notified of new commits for)
  • Live Tile showing the number of “unread” commits from CodeTrack
  • Commit view screen showing the list of updated files
  • Ability to add private Github Repos
  • More source control providers (TFS, BitBucket, CodePlex)

Watch CodeTrack in action on YouTube.

So where can you get it? Easy, its available from the Windows Phone 7 Marketplace for USD$0.99 (AUD$1.30)

wp7_English_480x80_blue

Easy Email Templates in .NET with FluentEmail

Update: The “Replace” method of templating in Fluent Email has itself been replaced by a Razor Engine Template. See Luke’s Post here about it.

I always seem to forget how to send emails in .NET which to me seems like such a simple task. Lately I’ve been working on updating an older application of mine that’s soul purpose was to read a database and send emails depending on certain events. I had a look at the current code and saw something like this:

sb.Append("A Transaction has been made...<br />");
sb.Append("<table><tr><th>Reservation Number</th><th>Customer Name</th><th>Email</th><th>Sale Date</th><th>Amount</th></tr>");
sb.AppendFormat("<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>",
    transaction.Reservation, transaction.FullName, transaction.Email, transaction.SaleDate, transaction.Amount.ToString("C2"));
sb.AppendFormat("<tr><th>Invoice</th><th>Confirmation</th></tr><tr><td>{0}</td><td>{1}</td></tr></table>", transaction.Invoice, transaction.Confirmation);

Terrible! So I figured while I was updating it I’d work out a better way build up the HTML of the emails. I started with the FluentEmail Project (Luke’s Post about it). From there I added some basic templating features, such as loading a HTML file with placeholders for content and the rest is history…

 

With my recent updated to FluentEmail I was about to turn something that looked like the above code to this: (as always C# is the code of choice)

//Send Email!
var email = Email
            .From(_fromEmail)
            .To(toAddresses)
            .Subject(string.Format("Siriusware Emailer Confirmation #{0}", transaction.Confirmation))
            .UsingTemplate(@"C:\Emailer\TransactionTemplate.htm")
            .Replace("<%Reservation%>", transaction.Reservation)
            .Replace("<%FullName%>", transaction.FullName)
            .Replace("<%SaleDate%>", transaction.SaleDate.ToShortDateString())
            .Replace("<%Amount%>", transaction.Amount.ToString("C2"))
            .Replace("<%Invoice%>", transaction.Invoice)
            .Replace("<%Confirmation%>", transaction.Confirmation)
            .UsingClient(new SmtpClient(_mailhost));
email.Send();

 

The HTML inside TransactionTemplate.htm has the below code. This is a basic example but demonstrates the usage of the templates.

<html>
<head>
    <title></title>
</head>
<body>
    A Transaction has been made...<br />
    <table>
        <tr>
            <th>Reservation Number</th>
            <th>Customer Name</th>
            <th>Email</th>
            <th>Sale Date</th>
            <th>Amount</th>
        </tr>
        <tr>
            <td><%Reservation%></td>
            <td><%FullName%></td>
            <td><%Email%></td>
            <td><%SaleDate%></td>
            <td><%Amount%></td>
        </tr>
        <tr>
            <th>Invoice</th>
            <th>Confirmation</th>
        </tr>
        <tr>
            <td><%Invoice%></td>
            <td><%Confirmation%></td>
        </tr>
    </table>
</body>
</html>

Pretty damn easy if you ask me.

This also give me the flexibility to edit the HTML file in a proper editor instead of concatenating all those strings together. The main idea was inspired by the MailDefinition class built into .NET but I didnt like the face that: 1 it was part of the System.Web.UI.WebControls namespace when its not a Web Control and wouldnt be used as one. And 2, It attempted to use another Control as a worker for it. So I just extended MailMessage to add the functionality.

All you need to do is download FluentEmail from Github

Dropbox API, RestSharp and C# Part 2: The Revenge!

Following on from my previous post where I showed you how to Login and get the Account Info for a Dropbox account. Today we dive into the Box full of files. Uploading, Downloading and Deleting!

 

A lot has changed since my last post in the way of RestSharp with OAuth. OAuth is now available Out-of-the-box (this can be downloaded from Github). Ok, Time for some code…

Download File:

Update: Fixed a bug in the code that only allowed for text based files to be downloaded. Using restClient.DownloadData now instead of Execute to get the response’s raw Data.

public byte[] DownloadFile(string path)
{
    var restClient = new RestClient("http://api-content.dropbox.com");
    //load the JsonDeserializer for all types
    restClient.ClearHandlers();
    restClient.AddHandler("*", new JsonDeserializer());
    if (!path.StartsWith("/")) path = "/" + path;

    restClient.Authenticator = new OAuthAuthenticator(restClient.BaseUrl, _apiKey, _appsecret, _userLogin.Token, _userLogin.Secret);

    var request = new RestRequest(Method.GET);
    request.Resource = "{version}/files/dropbox{path}";
    request.AddParameter("version", _version, ParameterType.UrlSegment);
    request.AddParameter("path", path, ParameterType.UrlSegment);

    var responseData = restClient.DownloadData(request);

    return responseData;
}

Note: This is assuming the user has already logged in and we have the token/secret (_userLogin).

Starting from the top, we create a new Instance of the RestSharp Client with the baseUrl then set the Json Deserializer for all requests. We then set the RestClient’s Authenticator to the OAuthAuthenticator and give it our baseUrl, all our secrets and that is all we need to do for OAuth (the rest is build into RestSharp, awesome?!). Now we create the Request up, its a GET method, set the version and path of the file to download call Execute and you have just downloaded your first Dropbox API file! I then converted this to a stream so save back to a local file.

Delete File:

public bool DeleteFile(string path)
{
    var restClient = new RestClient("http://api.dropbox.com");
    //load the JsonDeserializer for all types
    restClient.ClearHandlers();
    restClient.AddHandler("*", new JsonDeserializer());

    if (!path.StartsWith("/")) path = "/" + path;

    restClient.Authenticator = new OAuthAuthenticator(_restClient.BaseUrl, _apiKey, _appsecret, _userLogin.Token, _userLogin.Secret);

    var request = new RestRequest(Method.GET);
    request.Resource = "{version}/fileops/delete";
    request.AddParameter("version", _version, ParameterType.UrlSegment);

    request.AddParameter("path", path);
    request.AddParameter("root", "dropbox");

    var response = restClient.Execute(request);

    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

Delete is pretty similar to Download, only differences is the Url, the response and this time the path is sent as a parameter instead of part of the Url. The “root” parameter is for applications that only have sandbox access (they would set this to sandbox) who only get access to a “sandbox” folder on the users dropbox account.

Upload File:

Now this is where I had the most difficulties, many “Forbidden” messages later I finally came up with the solution!

public bool UploadFile(string path, FileInfo localFile)
{
    var restClient = new RestClient("http://api-content.dropbox.com");
    //load the JsonDeserializer for all types
    restClient.ClearHandlers();
    restClient.AddHandler("*", new JsonDeserializer());

    if (!path.StartsWith("/")) path = "/" + path;

    //Get the file stream
    byte[] bytes = null;
    FileStream fs = new FileStream(localFile.FullName, FileMode.Open, FileAccess.Read);
    BinaryReader br = new BinaryReader(fs);
    long numBytes = localFile.Length;
    bytes = br.ReadBytes((int)numBytes);

    restClient.Authenticator = new OAuthAuthenticator(_restClient.BaseUrl, _apiKey, _appsecret, _userLogin.Token, _userLogin.Secret);

    var request = new RestRequest(Method.POST);
    request.Resource = "{version}/files/dropbox{path}";
    request.AddParameter("version", _version, ParameterType.UrlSegment);
    request.AddParameter("path", path, ParameterType.UrlSegment);
    //Need to add the "file" parameter with the file name
    request.AddParameter("file", localFile.Name);

    request.AddFile(new FileParameter { Data = bytes, FileName = localFile.Name, ParameterName = "file" });

    var response = restClient.Execute(request);

    return response.StatusCode == System.Net.HttpStatusCode.OK;
}

Ok to start with the “path” variable/parameter is the folder path (not the file).

Starts off the same with the RestClient, JsonDeserializer and the OAuthAuthenticator. We also need to read the file as a byte array. Now this request is a POST so we set that in the RestRequest object then add the version and path Url parameters. We also need to add the Filename as a “file” parameter for this request as well as adding the actual file to the Request. Execute that and: {\"result\": \"winner!\"} we just uploaded a file to dropbox!

 

This code was taken from my Dropbox open source .NET project called DropNet.

Dropbox API and RestSharp for a C# developer

The Dropbox API has foiled my development of “Droppedboxx” for some time now. Mainly because the on site documentation is average for anyone not planning on developing for the iphone (dropbox, you used to be cool). Being a C# developer this was bad news for me but I decided to give it a go anyway and after a few weeks of failed attempts and a few emails to support about my issues I realised the API documentation on the dropbox website is slightly wrong.

So now that I have it working I thought i’d share this with my fellow .NET developers (and anyone else who will care to listen).

What you will need (What i used):

  • RestSharp (What would i do without you…)
  • Oauth Library for C# (this one seems the easiest to use with RestSharp)
  • Access to the Dropbox API and an APIKey/Secret for your app

I guess I should start with the Setup of it, I started this as a Windows Mobile application but I switched to a .NET library so I could test it easier and also use RestSharp (might open source the library if I get around to it).

 

Login, this is possibly the easiest method if you have the right URL (the API documentation give you the wrong URL). We should be using “https://api.getdropbox.com/0/token” Code you say?

Update: Got some helpful advice about using the request.Resource property with parameters instead of a string.format.

public UserLogin Login(string email, string password)
{
    var restClient = new RestClient("https://api.getdropbox.com");
    var request = new RestRequest(Method.GET);
    request.Resource = "{version}/token";
    request.AddParameter("version", _version, ParameterType.UrlSegment);

    request.AddParameter("oauth_consumer_key", _apiKey);

    request.AddParameter("email", email);
    request.AddParameter("password", password);

    var response = restClient.Execute<UserLogin>(request);

    _userLogin = response.Data;

    return response.Data;
}

Seems pretty easy right? Most of thats RestSharp (with the JSONDeserializer), I then have the UserLogin class which is returned by this function.

public class UserLogin
{
    public string Token { get; set; }
    public string Secret { get; set; }
}

And now your user is logged in, you will then want to store the Users Token and Secret (storing UserLogin object would probably be better) as its used for the rest of the requests. I’ll just show you how to get the User Info as the other requests differ from the login (that is where we’ll need the Oauth stuff).

 

Account/Info, I’ll start with the Response classes this time…

public class AccountInfo
{
    public string Country { get; set; }
    public string Display_Name { get; set; }
    public QuotaInfo Quota_Info { get; set; }
    public string Uid { get; set; }
}

public class QuotaInfo
{
    public string Shared { get; set; }
    public string Quota { get; set; }
    public string Normal { get; set; }
}

These are the classes for RestSharp to Deserialize the JSON to. Pretty simple, this is straight off the API Documentation site. Now for the actual request…

public AccountInfo Account_Info()
{
    var restClient = new RestClient("http://api.dropbox.com");
    OAuthBase oAuth = new OAuthBase();
    string nonce = oAuth.GenerateNonce();
    string timeStamp = oAuth.GenerateTimeStamp();
    string normalizedUrl;
    string normalizedRequestParameters;
    string sig = oAuth.GenerateSignature(new Uri(string.Format("{0}/{1}/account/info", restClient.BaseUrl, _version)),
        _apiKey, _appsecret,
        _userLogin.Token, _userLogin.Secret,
        "GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);
    sig = HttpUtility.UrlEncode(sig);

    var request = new RestRequest(Method.GET);
    request.Resource = string.Format("{0}/account/info", _version);
    request.AddParameter("oauth_consumer_key", _apiKey);
    request.AddParameter("oauth_token", _userLogin.Token);
    request.AddParameter("oauth_nonce", nonce);
    request.AddParameter("oauth_timestamp", timeStamp);
    request.AddParameter("oauth_signature_method", "HMAC-SHA1");
    request.AddParameter("oauth_version", "1.0");
    request.AddParameter("oauth_signature", sig);

    var response = restClient.Execute<AccountInfo>(request);

    return response.Data;
}

Now, this request has a different Base Url to the Login function and this uses OAuth. So firstly we create an instance of the RestSharp client and the OAutheBase classes. The OAuthBase class then handles all of the oauth parameters that we need to make the Request (nonce, timestamp, etc.). GenerateSignature is the main 1 that rolls up the request path and the tokens/secrets into a hash for extra security. As for the dropbox part of this, we dont need any extra parameters as we are just getting the logged in users Account Info. Then its just a matter of adding these parameters to the RestRequest object, notice the oauth_token is actually the UserLogin.Token that we got from our Login method?

 

Stay tuned for more, Tales of interest!

 

Update: I have added a Part 2 to this post.

MVC2 Cascading Dropdown Lists with JSON

Today I’m going to show you how to go about creating cascading dropdown lists using JSON in MVC2. Hold onto your hats, its time to begin!

Learning ASP.NET MVC2 I thought I’d start with a relatively simple web application, this application is for keeping track of service usage across the company’s physical sites (ie. Electricity, Gas, Waste, etc.).

Now first things first, I setup the Database and LinqToSql classes for my app. The table structure is MeterTypes > MeterCollections > MeterUsages. Where a MeterType is the top level (ie. Electricity, Gas, Waste, etc.) the MeterCollections are the next level down (a MeterType may contain many of these, for Electricity I have Peak and Off-Peak) and MeterUsage is the actual usage on a meter for that MeterCollection.

 

OK, lets get coding… We will be looking at the Create Page for the MeterUsage object, I started with the create template MVC2 gave me for this object (half of the fields are just textboxes anyway)

public ActionResult Create()
{
    var meterTypesRepo = new Models.Repo<Models.MeterType>();
    var meterTypes = from mt in meterTypesRepo.Many()
                     select new SelectListItem
                     {
                         Value = mt.MeterTypeID.ToString(),
                         Text = mt.Name
                     };
    ViewData["meterTypes"] = meterTypes;

    return View("Create");
} 

Inside the Controller is where the request is handled, Now we need the data for the first list so we may as well get this here. This simply gets all the MeterTypes in the Database and converts them to SelectListItems (this is to make it easier on the page)

<div class="editor-label">
    <label for="meterTypes">Meter Type</label>
</div>
<div class="editor-field">
    <%= Html.DropDownList("meterTypes", "-- Select --")%>
</div>
<div class="editor-label">
    <label for="MeterCollectionID">Meter Collection</label>
</div>
<div class="editor-field">
    <%= Html.DropDownListFor(model => model.MeterCollectionID, new SelectList(new List<UsageInputs.Models.MeterCollection>()))%>
    <%= Html.ValidationMessageFor(model => model.MeterCollectionID) %>
</div>

Markup, Basic use of the Html.DropDownList() function for MeterTypes (this is where using SelectListItems comes in handy. Also added a default option “—Select –”. Then the MeterCollection Dropdown is a little different as this one actually maps to a property on my MeterUsage object so I used the Html.DropDownListFor() function and gave it an empty list so it would create the dropdown list but not have any items (they will be populated with Ajax.

Next is the Javascript, this simply calls my MeterCollections/GetList function with the ID of the MeterType from the selected item in the DropDown list.

$("#meterTypes").change(function () {
    $.ajaxSetup({ cache: false });
    var selectedItem = $(this).val();
    if (selectedItem == "" || selectedItem == 0) {
        //Do nothing or hide...?
    } else {
        $.getJSON('<%= ResolveUrl("~/MeterCollections/GetList/")%>' + $("#meterTypes > option:selected").attr("value"), function (data) {
            meterCollections = data;
            var items = "";             $.each(data, function (i, meterCollection) {
                items += "<option value='" + meterCollection.Value + "'>" + meterCollection.Text + "</option>";
            });
            $("#MeterCollectionID").html(items);
        });
    }
});

It also builds up the html for inside the dropdown list using a JQuery for each loop.

Now the last part is our GetList function to return JSON, so back to the controllers.

[HttpGet]
public ActionResult GetList(int id)
{
    var meterCollsRepo = new Models.Repo<Models.MeterCollection>();
    var meterCollections = from mc in meterCollsRepo.Many()
                           where mc.MeterTypeID == id
                           select new SelectListItem
                           {
                               Text = string.Format("{0} ({1})", mc.Name, mc.Mesurement),
                               Value = mc.MeterCollectionID.ToString()
                           };

    return Json(meterCollections, JsonRequestBehavior.AllowGet);
}

This function then gets all the MeterCollections that have that MeterTypeID. Here I also use the SelectListItem object as its much easier to work with in the Javascript and less work for the Serializer.

 

And just like that you have a Cascading DropDown List in MVC2 using Ajax.

Smack my BitSharp!

Its an open source .NET client for the BandsInTown API.

TBODA currently have a number of web projects that focus on Live music, such as Promote.fm, and through these projects I have worked very closely with a lot of gig guide APIs. So i thought I’d make some of my code reusable but not just by me, thus BitSharp was born.

Now I’m a big fan of RestSharp (The .NET Rest Client) so BitSharp uses it for all the API requests and Responses. BitSharp is still in early development but most of the event and artist functions are working.

 

Now for the code to us it:

var client = new BitClient("API_KEY_HERE");

Artist artist = null;
try
{
    artist = client.Artists_Get("de11b037-d880-40e0-8901-0397c768c457");
}
catch (BitException ex)
{
    Console.WriteLine("BandsInTown Error:" + ex.Message);
    return;
}

Console.WriteLine(artist.Name);
Console.WriteLine(artist.MusicBrainzID);
Console.WriteLine("Bytes received: " + client.DataCount);

 

Starting by creating an instance of the BitClient with the APIKey this object is then what we use to make all the requests to the API so its a good idea to keep this at the global level that way you only need 1 instance.

Then inside the Try/Catch is where we call the Artists_Get function (this function simply gets artist info given the MusicBrainz ID). All the API Functions throw a BitException if an error is returned from the API so this exception is then caught.

Now that we have called the Artists_Get function we get an Artist object returned and its as easy as that.

 

The other BitSharp functions currently implemented include: (Updated)

  • Events_Search (Search for events either by artist(s), location or date)
  • Events_Daily (Returns a list of events that have been created updated or deleted in the last day)
  • Events_Recommended (Gets recommended events either by artist(s), location or date)
  • Artists_Events (Returns an artists upcoming events)
  • Artists_Get (Gets information on a single Artist)
  • Venues_Search (Search for venues by name and/or location)
  • Venues_Events (Returns a venues upcoming events)

 

You can find the source for BitSharp @ Github.