Keyvan Nayyeri

My daily musings about software and technology

Slides of My Talk on Introduction to ASP.NET SignalR

[Update: Video of my talk has been published on UserGroup.TV.]

As I mentioned recently, today I talked at North Dallas .NET Users Group for the second time, and this time it was about ASP.NET SignalR. I tried to introduce this new member of ASP.NET family to the audience.

I started my talk with some slides on why we need a framework like ASP.NET SignalR and then moved on to some theoretical principles about SignalR. After that, I switched to code and implemented two broadcasting examples with PersistentConnection and hubs, and showed how WebSockets and long polling work in action using Fiddler. I concluded the talk by showing an example of connecting to my SignalR application using a .NET library, and answered some questions in the end.

I’ve published the slides of my talk as well as the source code samples that you can download. UserGroup.TV has recorded my talk and it would be available soon. I will update this post with the link when it was published.

2 Comments

Speaking at North Dallas .NET Users Group on ASP.NET SignalR

North Dallas .NET Users GroupIt’s been a busy yet productive part of my life in the past few months since I moved to Dallas. I was settling in the new city and new job and expanding my social network. I couldn’t do much in the area of community activities like blogging or speaking, but I’m slowly coming back.

Those loyal readers of my blog who can stand my posts and keep reading them would remember that in September 2011 I had a talk at North Dallas .NET Users Group on parallel programming in .NET that was eventually sponsored by Match.Com while I had no idea I will start a new job there exactly one year later.

North Dallas .NET Users Group is organized and managed by a group of smart and great people among whom I had some friends even before joining Match and some of them are now my colleagues there. As could be expected from my move to Dallas, I’m going to speak there again on February 6, 2013, and I’ve chosen yet another interesting topic about a new .NET technology which is ASP.NET SignalR.

As you would know, SignalR was started as an open source community project to enable real time communication between clients and servers for ASP.NET applications, but it was added as an official part of ASP.NET technology stack with ASP.NET Fall 2012 Update in BUILD conference. I’ve been working with SignalR in the past couple of months, and found it a great addition to the .NET family.

The title of my talk is Introduction to ASP.NET SignalR, and it will be at Improving Enterprises in Addison, Texas at 6:00 PM and I’ll introduce ASP.NET SignalR to audience, and will try my best to provide enough information to get people started with this new technology.

I have to thank our Human Resources for sponsoring this talk, and encourage you, dear .NET developers, to apply for a position to join our awesome teams.

2 Comments

Merry Christmas

Photo taken from http://www.iamsterdam.com/~/media/carousel/Christmas_general_carousel.jpgIt's been a while since the last time I wrote on this blog. To be quite honest, my priorities in life have changed and blogging doesn't have a very good position there. Besides that, I was busy settling at the new job and new city.

Anyhow, it's the holiday season and I thought I better write a short post and wish everyone happy holidays wherever you are. If you're lucky to spend it with your loved ones and family, I hope you can continue doing that for years to come, and if you're alone like me, I hope you can spend it with happiness and time can bring you back to your loved ones.

I've had a busy and eventful year passing for me with a bunch of good and bad stuff happening. After earning a Master's degree, I moved to Dallas and started a new life at a new job, and I'm at a different position from where I was last year this time.

I wish a very merry Christmas for everyone, and hope that we see peace all over the world. If you're blessed to have the opportunity to help others, I hope you do and give a hand to those in need.

5 Comments

Mash This Episode 16: The NPR API with Javaun Moradi

The 16th episode of Mash This podcast is out and it's featuring Javaun Moradi from National Public Radio to talk about NPR's API.

Javaun holds the position that was previously held by our guest in episode 14 (Daniel Jacobsen). NPR provides a big set of API's for its content and deals with many stations, channels, etc. The volume of traffic and the size of data on NPR make it a big challenge to build a good API for the public. NPR's API is used to create a wide range of mobile applications, widgets, and tools.

In this episode, Lee, Nick, and I talk to Javaun about their API's and discuss some other relevant topics including the state of software design for the cars. This is a very interesting discussion as it covers a wide and nice set of topics.

Episode 16 is also my last episode as one of the main hosts. I appeared on 15 out of 16 episodes so far and has been with the podcast since its early days to now (almost 9 months). Luckily, we had a great set of episodes with prominent guests, and provided a valuable content for our audience. However, I think I have to step down from this regular commitment to focus on other stuff mainly my personal life. I'm happy that we've been able to put the podcast on track, and am sure that other hosts can continue the work after me. I may reappear on the podcast on occasion as a guest or co-host.

You can download episode 16 and have access to the show links that may be helpful.

If you're interested to follow the content on Mash This, you can subscribe to RSS feed or Apple iTunes.

2 Comments

Comma Delimited Cookies in ASP.NET

Cookies are a fundamental part of internet that are being used for various purposes including but not limited to authentication and authorization. It is hard to find a dynamic website that doesn't take advantage of cookie as is a part of HTTP headers, and the bigger a site is, the more extensive the use of cookies is. One common use of cookies is in forms authentication that almost all the developers are familiar with.

All the web server technologies also provide different mechanisms to work with cookies, and facilitate dealing with this HTTP header. ASP.NET is no exception in here, and there are many API's provided to work with cookies in this popular server technology. Forms authentication and some built-in server controls in ASP.NET are a few of the common examples to mention.

On the other hand, cookies are standardized by the development community and there is RFC2309 that documents the way cookies should be constructed by technologies and developers. According to this document, semicolon and comma are both valid characters to be used as a delimiter for cookie keys even though semicolon is the more common approach and the traditional way.

Having said these, ASP.NET does not support comma delimited cookies and as far as I know, this limitation has existed for all the versions of ASP.NET up to this point. If you take a look at the source code for System.Web.HttpRequest class in ASP.NET, you can realize this easily.

Of course, this doesnít seem like a big issue as long as you receive the requests that are a response to your own server with no manipulation of the content because everything will be maintained. But what if by any chance the requests are mangled at a point between client and server? For example, an internet provider can change its software to manipulate the requests and replace semicolons with comma's, and if you donít think this can happen, you're simply wrong! Such a change simply breaks the ASP.NET infrastructure for cookie parsing.

The fix for this problem shouldnít be hard. In essence, a simple parser tool can implement ASP.NET's cookie parsing to also accept comma's rather than semicolons. Such a logic should work as long as nobody is using comma's in the values for cookies. In such a case, the new parser will be confused and cannot parse the cookie header correctly. In this case, there may be different solutions for the problem depending on the business domain of the application, but one possible solution is to remove such cookie keys that include comma values in them, and then parse the cookie. I'd have to mention that this shouldnít happen if developers know the standards and not put comma's in the values of their cookies.

But the parser for comma's can be implemented with different mechanisms, but the simplest way to do it is to add it as an HttpModule that processes each and every request, looks for the existence of comma in cookie header, and then parses and extracts the cookies to put them in the collection. This approach can reuse the source code of ASP.NET with minor modifications. The source code for this HttpModule is presented below.

using System;
using System.Web;

namespace CommaDelimitedCookieParser
{
    public class CookieParser : IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(ParseCookie);
        }

        private void ParseCookie(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            HttpRequest request = application.Request;
            string cookieHeader = string.Empty;
            if (request.Headers["Cookie"] != null)
                cookieHeader = request.Headers["Cookie"];

            try
            {
                CookieParserInternal parser = new CookieParserInternal();
                if (parser.HasCommaDelimitedCookieHeader(cookieHeader))
                    parser.ParseBadCookieHeader(cookieHeader, request.Cookies);
            }
            catch
            {
            }
        }
    }
}

And this module relies on CookieParseInternal class that does most of the internal work for cookie parsing.

using System;
using System.Web;

namespace CommaDelimitedCookieParser
{
    internal class CookieParserInternal
    {
        public bool HasCommaDelimitedCookieHeader(string cookieHeader)
        {
            if (cookieHeader.Contains(","))
                return true;

            return false;
        }

        public void ParseBadCookieHeader(string cookieHeader, HttpCookieCollection cookies)
        {
            cookies.Clear();

            FillInCookiesCollection(cookies, cookieHeader);
        }

        public void FillInCookiesCollection(HttpCookieCollection cookieCollection, string cookieHeader)
        {
            int length;

            string knownRequestHeader = cookieHeader;
            if (knownRequestHeader != null)
            {
                length = knownRequestHeader.Length;
            }
            else
            {
                length = 0;
            }
            int num = length;
            int num1 = 0;
            HttpCookie value = null;
            while (num1 < num)
            {
                string str = ExtractNextCookie(knownRequestHeader, num, ref num1);
                if (str.Length == 0)
                {
                    continue;
                }
                HttpCookie httpCookie = CreateCookieFromString(str);
                if (value != null)
                {
                    string name = httpCookie.Name;
                    if (name != null && name.Length > 0 && name[0] == '$')
                    {
                        if (!EqualsIgnoreCase(name, "$Path"))
                        {
                            if (!EqualsIgnoreCase(name, "$Domain"))
                            {
                                continue;
                            }
                            value.Domain = httpCookie.Value;
                            continue;
                        }
                        else
                        {
                            value.Path = httpCookie.Value;
                            continue;
                        }
                    }
                }
                cookieCollection.Add(httpCookie); //This had to change. Internal
                value = httpCookie;
            }
            return;
        }

        private static string ExtractNextCookie(string knownRequestHeader, int num, ref int num1)
        {
            int i = num1;
            for (i = num1; i < num; i++)
            {
                char chr = knownRequestHeader[i];
                if (chr == ',')
                {
                    break;
                }
            }
            string str = knownRequestHeader.Substring(num1, i - num1).Trim();
            num1 = i + 1;
            return str;
        }

        public HttpCookie CreateCookieFromString(string s)
        {
            int num;
            int length;
            HttpCookie httpCookie = new HttpCookie("");
            if (s != null)
            {
                length = s.Length;
            }
            else
            {
                length = 0;
            }
            int num1 = length;
            int num2 = 0;
            bool flag = true;
            int num3 = 1;
            while (num2 < num1)
            {
                int num4 = s.IndexOf('&', num2);
                if (num4 < 0)
                {
                    num4 = num1;
                }
                if (flag)
                {
                    num = s.IndexOf('=', num2);
                    if (num < 0 || num >= num4)
                    {
                        if (num4 == num1)
                        {
                            httpCookie.Name = s;
                            break;
                        }
                    }
                    else
                    {
                        httpCookie.Name = s.Substring(num2, num - num2);
                        num2 = num + 1;
                    }
                    flag = false;
                }
                num = s.IndexOf('=', num2);
                if (num >= 0 || num4 != num1 || num3 != 0)
                {
                    if (num < 0 || num >= num4)
                    {
                        httpCookie.Values.Add(null, s.Substring(num2, num4 - num2));
                        num3++;
                    }
                    else
                    {
                        httpCookie.Values.Add(s.Substring(num2, num - num2), s.Substring(num + 1, num4 - num - 1));
                        num3++;
                    }
                }
                else
                {
                    httpCookie.Value = s.Substring(num2, num1 - num2);
                }
                num2 = num4 + 1;
            }
            return httpCookie;
        }

        public bool EqualsIgnoreCase(string s1, string s2)
        {
            if (!string.IsNullOrEmpty(s1) || !string.IsNullOrEmpty(s2))
            {
                if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
                {
                    return false;
                }
                else
                {
                    if (s2.Length == s1.Length)
                    {
                        return 0 == string.Compare(s1, 0, s2, 0, s2.Length, StringComparison.OrdinalIgnoreCase);
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            else
            {
                return true;
            }
        }
    }
}

You can download the source code sample of this module from an open source GitHub project that I created for it, and apply that to your application at your own risk. Please note that this approach does not work if you have any comma's used in your cookies values. You can use Fiddler to test whether this module works or not. If you donít know how to do that with Fiddler, you better don't use this module!

In the end, I have to thank Eric Sowell for his cooperation on finding this limitation in ASP.NET and figuring out a fix.

1 Comments