ExpandoObject basically says you can add properties ad hoc. When that happens, how do I know when a property on the object exists or not? The value of static typing goes down with ad hoc properties.
Sure; if every object was an ExpandoObject, the value of your "static typing" would be nil. The point is that you can just make an ExpandoObject if you really need ad hoc properties in one place, and it cooperates with the rest of your statically-typed code.
To illustrate the value of such a thing, I invite you to look at the ADO.NET libraries for data access, which provided a verbose, painful "dynamic property bag" experience as far back as .NET 1.0; you had DataTables with columns that you would pass a type to, and then you had DataRows that you indexed into with strings to put objects in and get them out, and you had to cast them back and forth as you did it -- all of it ugly, none of it checked at compile-time. The value of C# dynamic (besides interop) is that now you can have such a thing in a fairly concise form with syntax that doesn't make you sob uncontrollably when you use it.
And people do use it. I have worked on a mind bending .NET call centre application within which the entire state of the program is stored within untyped, globally accessible datatables.
It's down to the old "with great power comes great responsibility" idea.
This ruby comparison might make sense if people were to use C#'s dynamic all over the place, but it's just a single feature intended for specific situations. Most of the code will remain as sensibly static as ever.