Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Sunday, 23 June 2013

C# Console app that displays twitter feed using Linq To Twitter (using Single User Authorization)


I recently had to add a twitter feed to my existing ASP.NET MVC 4 application. All I had to do was pull the last 10 tweets for a given user. It took me a while (shamefully, 3 hours) to get it working so I thought of writing a simple tutorial that explains how to pull a twitter feed for a console app using LINQ to Twitter.

LINQ to Twitter is an open source 3rd party LINQ Provider for the Twitter micro-blogging service. It uses standard LINQ syntax for queries and includes method calls for changes via the Twitter API

What took me long to figure out was the way twitter has implemented authentication using OAuth. Before you do anything, make sure you read the Learning to use OAuth document.

In my example, I used Single User Authorization. Single User Authorization is designed for scenarios where you'll only ever have one account accessing Twitter. i.e. if your Web site does periodic Twitter updates, regardless of user or you have a server that monitors general information. 

Before we begin coding, we'll need to set-up this authorization scheme on twitter & generate certain tokens as shown below:

Start by creating a twitter account that your application will be using to access Twitter. This is easy-peasy. Log on to https://twitter.com/ and setup your account. I've created a dummy account for this (_roehit).

Once your account is setup, navigate to https://dev.twitter.com and sign in with your twitter credentails. 

You now need to create an application. This can be done at https://dev.twitter.com/apps by clicking "Create a new application".



You need to enter your application details. You need a Name, Description & a Website (Your application's publicly accessible home page). You can add a Callback URL but its not really required. (Note: The name can't include the word "twitter".)



Remember to agree to the terms and conditions.

You should now get directed to the application page. By default, the first tab ("Details" tab) is visible. You must click the "Api Keys" tab and then click the "Create my access token" button (you will need to scroll down). This in turn generates the access tokens (you may need to refresh the page). Your Keys and Access Tokens should now be available for use.







Once created, navigate to the "OAutth tool" tab to view your OAuth Settings. We will need the generated tokens for our applications. (Note: My tokens are crossed out to maintain their integrity.)

Take note of the following tokens as we will need these later:
  • Consumer key
  • Consumer secret
  • Access token
  • Access token secret


Now we begin coding. In this example we've created a simple C# console application.

Start by creating a new project. Choose the "Console Application" template. 

Use NuGet to add the linqtotwitter package to our application. 



And now add the code shown below:
/// <summary>
/// Controls the flow of the program.
/// </summary>
/// <param name="args">The args.</param>
static void Main(string[] args)
{
    // This is a super simple example that
    // retrieves the latest tweets of a given 
    // twitter user.

    // SECTION A: Initialise local variables
    Console.WriteLine("SECTION A: Initialise local variables");

    // Access token goes here .. (Please generate your own)
    const string accessToken = "Access token goes here .. (Please generate your own)";
    // Access token secret goes here .. (Please generate your own)
    const string accessTokenSecret = "Access token secret goes here .. (Please generate your own)";

    // Api key goes here .. (Please generate your own)
    const string consumerKey = "Api key goes here .. (Please generate your own)";
    // Api secret goes here .. (Please generate your own)
    const string consumerSecret = "Api secret goes here .. (Please generate your own)";

    // The twitter account name goes here
    const string twitterAccountToDisplay = "roeburg"; 


    // SECTION B: Setup Single User Authorisation
    Console.WriteLine("SECTION B: Setup Single User Authorisation");
    var authorizer = new SingleUserAuthorizer
    {
        CredentialStore = new InMemoryCredentialStore
        {
            ConsumerKey = consumerKey,
            ConsumerSecret = consumerSecret,
            OAuthToken = accessToken,
            OAuthTokenSecret = accessTokenSecret
        }
    };

    // SECTION C: Generate the Twitter Context
    Console.WriteLine("SECTION C: Generate the Twitter Context");
    var twitterContext = new TwitterContext(authorizer);

    // SECTION D: Get Tweets for user
    Console.WriteLine("SECTION D: Get Tweets for user");
    var statusTweets = from tweet in twitterContext.Status
                        where tweet.Type == StatusType.User &&
                                tweet.ScreenName == twitterAccountToDisplay &&
                                tweet.IncludeContributorDetails == true &&
                                tweet.Count == 10 &&
                                tweet.IncludeEntities == true
                        select tweet;

    // SECTION E: Print Tweets
    Console.WriteLine("SECTION E: Print Tweets");
    PrintTweets(statusTweets);
    Console.ReadLine();
}

/// <summary>
/// Prints the tweets.
/// </summary>
/// <param name="statusTweets">The status tweets.</param>
/// <exception cref="System.NotImplementedException"></exception>
private static void PrintTweets(IQueryable<Status> statusTweets)
{
    foreach (var statusTweet in statusTweets)
    {
        Console.WriteLine(string.Format("\n\nTweet From [{0}] at [{1}]: \n-{2}",
            statusTweet.ScreenName,
            statusTweet.CreatedAt,
            statusTweet.Text));
                
        Thread.Sleep(1000);
    }
}

This should now display the last 10 tweets for the specified user.

A copy of the project is available at http://1drv.ms/NPUIVW (download the Linq2Twitter zip). This is a Visual Studio 2013 Console Application with a target framework of .NET 4.5.1 using LinqToTwitter package verison 3.0.2.

Disclaimer: The code shown above is quite crude & includes no error handling of any sort. This is just to give you a starting point. You can extend the functionality as you desire.





Tuesday, 4 June 2013

Deploying an ASP.NET MVC Application using Powershell


Personally, I'm not a big fan of batch files. Don't get me wrong, while batch files are super cool at getting things done, I personally prefer the flexibility that powershell provides.

The script shown below can be used as a template to automate the website deployment process.

I have however assumed that you have MVC installed on the machine. If you do not, then you will need to add the dlls necessary to bin deploy MVC. 
There are a set of assemblies you’ll need to include with your application for it to run properly, unless they are already installed in the Global Assembly Cache (GAC) on the server. Have a look at http://haacked.com/archive/2011/05/25/bin-deploying-asp-net-mvc-3.aspx
The script leverages the appcmd utility. You need to be mindful that:
  • When running the script, you may need to set your execution policy.
  • When running this script using other automated deployment environments you may only have access to the command line so you can invoke it like so:
cmd /c powershell -ExecutionPolicy "UnRestricted" .\ApplicationDeployment.ps1 \\Path\To\Binaries\Folder 

A copy of the sample file is available here ... http://sdrv.ms/11UZKW7





Tuesday, 26 March 2013

Formatting TFN and ABN

I'm not entirely sure if I've mentioned this before BUT I happen to LOVE extension methods.

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

I recently had to write some of them up for Formating TFN and ABNs.

Here are the TfnAbnExtnesion Methods. (I could have also used regular expression to accomplish this but I chose to keep it simple/maintainable.)
 
public static class TfnAbnExtensions
{
    /// <summary>
    /// Formats the TFN.
    /// If the length is 9 char, return XXX XXX XXX
    /// If the length is 8 char, return XXX XXX XX
    /// </summary>
    /// <param name="tfn">The TFN.</param>
    /// <returns></returns>
    public static string FormatTfn(this string tfn)
    {
        // Ignore null/empty strings
        if (string.IsNullOrWhiteSpace(tfn))
        {
            return string.Empty;
        }

        // Remove any existing whitespaces
        var newtfn = tfn.UnFormatAbnTfn();
            
        var result = string.Empty;
        var tfnCharArray = newtfn.ToCharArray();

        for (int i = 0; i < tfnCharArray.Length; i++)
        {
            if (i % 3 == 0 && i != 0)
            {
                result += " ";
            }

            result += tfnCharArray[i].ToString(CultureInfo.InvariantCulture);
        }

        return result;
    }


    /// <summary>
    /// Formats the ABN.
    /// </summary>
    /// <param name="abn">The ABN.</param>
    /// <returns></returns>
    public static string FormatAbn(this string abn)
    {
        // Ignore null/empty strings
        if (string.IsNullOrWhiteSpace(abn))
        {
            return string.Empty;
        }

        // Un-format the ABN
        var newtfn = abn.UnFormatAbnTfn();
            
        var result = string.Empty;
        var abnCharArray = newtfn.ToCharArray();
        var tempCounter = 0;

        for (int i = 0; i < abnCharArray.Length; i++)
        {
            // Second character & then every 3rd char
            if (i == 2 || tempCounter == 3)
            {
                result += " ";
                tempCounter = 0;
            }

            tempCounter++;
            result += abnCharArray[i].ToString(CultureInfo.InvariantCulture);
        }

        return result;
    }


    /// <summary>
    /// Un formats the ABN or TFN by removing blank spaces
    /// </summary>
    /// <param name="abnTfn">The ABN or TFN.</param>
    /// <returns></returns>
    public static string UnFormatAbnTfn(this string abnTfn)
    {
        return string.IsNullOrWhiteSpace(abnTfn) ? abnTfn :
            abnTfn
            .Replace(" ", string.Empty)
            .Replace("-", string.Empty)
            .Replace("/", string.Empty);
    }
    
}

References: Extension Methods (C# Programming Guide)

Thursday, 7 February 2013

Problem with delegate within foreach

The picture shown below represents my data. Data that I have and the expected result at the end:




The logic being, that for every date in the list of dates, find the associated price tuple where the effective date is less than or equal to the date and is the max date.

The structure of Price is shown below.

 
public class Price
{
    public int PriceId { get; set; }

    public DateTime EffectiveDate { get; set; }

    public double PriceAmount { get; set; }

    public DateTime CreatedOn { get; set; }
}

I have a static method that gets me the data that I need
 
static List<Price> GetPrices()
{
    return new List<Price>()
    {
        new Price()
        {
            PriceId = 1, EffectiveDate = new DateTime(2012,1,1),
            PriceAmount = 100, CreatedOn = new DateTime(2012,1,1)
        },
        new Price()
        {
            PriceId = 2, EffectiveDate = new DateTime(2012,1,1),
            PriceAmount = 200, CreatedOn = new DateTime(2012,1,1)
        },
        new Price()
        {
            PriceId = 3, EffectiveDate = new DateTime(2012,1,2),
            PriceAmount = 300, CreatedOn = new DateTime(2012,1,2)
        },
        new Price()
        {
            PriceId = 4, EffectiveDate = new DateTime(2012,1,3),
            PriceAmount = 400, CreatedOn = new DateTime(2012,1,3)
        },
        new Price()
        {
            PriceId = 5, EffectiveDate = new DateTime(2012,1,4),
            PriceAmount = 500, CreatedOn = new DateTime(2012,1,4)
        },
        new Price()
        {
            PriceId = 6, EffectiveDate = new DateTime(2012,1,5),
            PriceAmount = 600, CreatedOn = new DateTime(2012,1,5)
        },
        new Price()
        {
            PriceId = 7, EffectiveDate = new DateTime(2012,1,16),
            PriceAmount = 700, CreatedOn = new DateTime(2012,1,16)
        },
        new Price()
        {
            PriceId = 8, EffectiveDate = new DateTime(2012,1,27),
            PriceAmount = 800, CreatedOn = new DateTime(2012,1,27)
        },
        new Price()
        {
            PriceId = 9, EffectiveDate = new DateTime(2012,1,28),
            PriceAmount = 900, CreatedOn = new DateTime(2012,1,28)
        },
    };
}

This is the original code that I wrote to get me the information that I needed:

 
// This represents your List of dates
var listOfDates = new List<DateTime>()
                        {
                        new DateTime(2012,1,2),
                        new DateTime(2012,1,10),
                        new DateTime(2012,1,15),
                        new DateTime(2012,1,27)
                        };

// This represents your prices
var prices = GetPrices();

// Initialise the expected result set
var expectedResultSet = new List<Price>();

// Get your expected result set
listOfDates.ForEach(date =>
                        {
                            // In each date, find the price that you're after
                            var price = prices
                                .Where(p => p.EffectiveDate <= date)
                                .OrderByDescending(result => result.EffectiveDate)
                                .FirstOrDefault();

                            if(price != null)
                            {
                                // Fix the Date
                                price.EffectiveDate = date;

                                // Add it to the expected result
                                expectedResultSet.Add(price);
                            }
                        });

// Print the Result
Print(expectedResultSet);

If you check the output, this does NOT give you the result you were expecting!!!
Now to get the result you're after, you'll need to iterate through the list in a different manner:

(This is just one option ... )

 
// Get Dates and Prices
listOfDates = GetListOfDates();
prices = GetPrices();

// Step A: Get a Tuple of Date & Price
List<Tuple<DateTime, Price>> datesWithAssociatedPrice;
datesWithAssociatedPrice = listOfDates
    // Step 1: Select the Requested Date and Price(S) 
    // where the Price's Effective Date <= the date (from range)
    // [One Date .. Many Prices]
.Select(eachDate => new
{
    RequestedDate = eachDate,
    AssociatedPrices = prices.Where(p => p.EffectiveDate <= eachDate)
})

// Step 2: Now iterate through the list of Date, List & in each tuple,
    // find the first instance of Price with the Max Effective date
.Select(dateAndPrice => new
{
    RequestedDate = dateAndPrice.RequestedDate,
    AssociatedPrice = dateAndPrice
        .AssociatedPrices
        .First(price => price.EffectiveDate ==
            dateAndPrice.AssociatedPrices.Max(item => item.EffectiveDate))
})

// Step 3: Now get the data you need as a List<Tuple<DateTime, Price>> tuple
.Select(tuple => 
    new Tuple<DateTime, Price>(tuple.RequestedDate, 
        tuple.AssociatedPrice)).ToList();

// Print using an extension method :)
Print(datesWithAssociatedPrice.ToPriceList());

And now the result is what is expected.


The complete source is available here: http://snipt.org/zQjc0#expand


References: http://stackoverflow.com/questions/2571398/problem-with-anonymouse-delegate-within-foreach


Monday, 7 January 2013

Unit Testing HttpContext.Current.Session in MVC3 .NET

We recently changed some functionality where during the "CREATE" process, we go through a wizard to save application data. This data is saved only to the session in the final step when the user clicks the final submit.

This was easy enough to implement but when I started writing unit tests for my static methods that Add, Update, Delete or Modify the contents of our application data in the session, I got the following error:

System.NullReferenceException: Object reference not set to an instance of an object.


Turns out I had forgotten to setup the HttpContext.

The following "TestInitialise" method fixed my problem :)

 
[TestInitialize]
public void TestSetup()
{
    // We need to setup the Current HTTP Context as follows:            

    // Step 1: Setup the HTTP Request
    var httpRequest = new HttpRequest("", "http://localhost/", "");

    // Step 2: Setup the HTTP Response
    var httpResponce = new HttpResponse(new StringWriter());

    // Step 3: Setup the Http Context
    var httpContext = new HttpContext(httpRequest, httpResponce);
    var sessionContainer = 
        new HttpSessionStateContainer("id", 
                                       new SessionStateItemCollection(),
                                       new HttpStaticObjectsCollection(), 
                                       10, 
                                       true,
                                       HttpCookieMode.AutoDetect,
                                       SessionStateMode.InProc, 
                                       false);
    httpContext.Items["AspSession"] = 
        typeof(HttpSessionState)
        .GetConstructor(
                            BindingFlags.NonPublic | BindingFlags.Instance,
                            null, 
                            CallingConventions.Standard,
                            new[] { typeof(HttpSessionStateContainer) },
                            null)
        .Invoke(new object[] { sessionContainer });

    // Step 4: Assign the Context
    HttpContext.Current = httpContext;
}
 
[TestMethod]
public void BasicTest_Push_Item_Into_Session()
{
    // Arrange
    var itemValue = "RandomItemValue";
    var itemKey = "RandomItemKey";
            
    // Act
    HttpContext.Current.Session.Add(itemKey, itemValue);
            
    // Assert
    Assert.AreEqual(HttpContext.Current.Session[itemKey], itemValue);
}



References: http://stackoverflow.com/questions/9624242/setting-the-httpcontext-current-session-in-unit-test

Thursday, 6 December 2012

Find Overlapping Date Ranges



I recently had to implement a "DateRange" validator to check for any overlaps in the date ranges.

Here is my approach to it :

I started with a custom DateRange class.
 
public class DateRange
{
    public int SortOrder { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public DateRange() {}

    public DateRange(DateTime sTime, DateTime eTime)
    {
        Start = sTime;
        End = eTime;
    }
} 

Then I call the "HasOverlap" method on my validator to check for overlaps.
 
/*
* LOGIC:
* 
* 1. Take a List of date ranges. Example:
            [Tuple A]         --------         [Sort Order 1]
            [Tuple B]--------                  [Sort Order 2]
            [Tuple C]     --------             [Sort Order 3]
            [Tuple D]     --------             [Sort Order 4]
            [Tuple E]             --------     [Sort Order 5]
            [Tuple F]     ----------           [Sort Order 6]
         
* 2. Now sort the range by start + End Dates. This results in:
            [Tuple B]--------                  [Sort Order 1]
            [Tuple C]     --------             [Sort Order 2]
            [Tuple D]     --------             [Sort Order 3]
            [Tuple F]     ----------           [Sort Order 4]
            [Tuple A]         --------         [Sort Order 5]
            [Tuple E]             --------     [Sort Order 6]    
         
* 3. The Logic is that there will be an overlap IF EVEN ONE of 
*    the 2 base conditions are met:
*      (a) After sorting the list, a given tuple (TUPLE X) 
*          will be deemed overlapping 
*              if the END-DATE of (TUPLE X) is GREATER THAN the START-DATE 
*              of ANY tuple WHERE the sort order is GREATER THAN that of (TUPLE X)
*          
*      --- OR ---
*      
*      (b) After sorting the list, a given tuple (TUPLE X) 
*          will be deemed overlapping 
*              if the START-DATE and END-DATE of (TUPLE X) MATCHES 
*              the START-DATE and END-DATE of ANY tuple 
*              WHERE the sort order is GREATER THAN that of (TUPLE X)
*/
private bool HasOverlap(IList<DateRange> ranges)
{
    // 1. Sort Dates based on Start & End Dates
    var sortedRange = ranges
                        .OrderBy(p => p.Start)
                        .ThenBy(p => p.End)
                        .ToList();

    var sortCounter = 0;
    sortedRange.ForEach(e =>
    {
        e.SortOrder = sortCounter;
        sortCounter++;
    });


    // 2. Check if the end dates are > any start dates except the same one 
    return sortedRange
        .Any(tuple => (from innerLoop in sortedRange
                        where (
                                tuple.End > innerLoop.Start &&
                                innerLoop.SortOrder > tuple.SortOrder
                                ) ||
                                (
                                tuple.End == innerLoop.End &&
                                tuple.Start == innerLoop.Start &&
                                innerLoop.SortOrder > tuple.SortOrder
                                )
                        select innerLoop).Any());
}

Additionally I also pass my DateRanges through a sanity check to ensure that the start < end dates.