Archive

Archive for June, 2011

Working with large Entity Framework models in Visual Studio

June 23, 2011 4 comments

Entity Framework has come a long way. It has provided a lot of flexibility and now with Code First, it is getting closer and closer to the flexibility of NHibernate. It still lacks some features that will hopefully be in the next drop.

An issue that I have run into in dealing with very large models in my projects is the lack of good designer support. Take the following screen shot from the AdventureWorks database:

When the model is this small, Visual Studio give us the ability to navigate between entities using the Property dropdown selector as seen here:

However if you have a model that is considerably larger model like the following screen shot:

The dropdown will no longer work as seen here:

Luckily there is still a way to navigate your large model without needing to drop everything and recreate. Let me introduce you to the Model Browser. To see the Model Browser, simply right click on the designer surface as shown below:

Select the Model Browser menu option. You then see a new Model Browswer tab:

If you expand the Entity Types folder you get the following view:

Finally, if you want to navigate to a particular entity, simply right click the entity as shown below:

Select the Show In Browser menu option and the designer will navigate and select the corresponding entity:

Now we are back in business. It isn’t as easy as the Property selector but it still gets the job done. It certainly has made my life easier.

This took me a while to figure out. I am not sure why but we had this horrible workflow trying to update one or two entities without dropping the whole model when the property selector stopped working.

Hope this helps….

Creating a simple Doodle (drawing) like application using Silverlight and Reactive Framework (Rx)

June 10, 2011 2 comments

I had a great time speaking with the Charlotte ALT.NET User Group last night.

Here are the slides and sample code for download or if you just want to see the slides online.

Thanks to all who came out!

Getting something better than “Server not found.” from WCF in Silverlight redux

June 6, 2011 1 comment

I have had a lot of question lately about my blog post concerning “Server not found.” messages coming from WCF to Silverlight. I decided to create a quick post that provides a sample application that has everything wired up with some test buttons.

Here is a screen shot of the application:

Here is a screen shot with an error thrown from the server:

The application just has some buttons at the bottom of the screen that make calls to the service operations. Here is what the code looks like for the WCF service:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
using Web.Core;

namespace ServerExceptions.Web
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "BusinessService" in code, svc and config file together.
    [WcfErrorBehavior()]
    [WcfSilverlightFaultBehavior()]
    public class BusinessService : IBusinessService
    {
        public void RaiseException()
        {
            throw new Exception("Can't log in to the database.");
        }

        public string RaiseInvalidOperation()
        {
            throw new InvalidOperationException("You can't call this method!");
        }

        public void RaiseIndexOutOfRange()
        {
            throw new IndexOutOfRangeException();
        }

        public string GetCustomerName()
        {
            return "Matt Duffield";
        }

    };
}

This is a contrived example but the most important thing to note are the attributes above the service definition.

  • WcfErrorBehavior
  • WcfSilverlightFaultBehavior

It is these attributes that give us the ability to capture the error and send it back down the wire to the client. If you comment out the attributes and try any example that throws an error you will get our favorite message:

Here is what the calling code looks like after you have created a client side reference to the WCF service:

#region Button Click events

private void RaiseException_Click(object sender, RoutedEventArgs e)
{
    BusinessServiceClient client = new BusinessServiceClient();
    client.RaiseExceptionCompleted += (s, ea) =>
    {
        if (ea.Error != null)
        {
            Message = ea.Error.Message;
        }
        else
        {
            Message = "No exceptions.";
        }
    };
    client.RaiseExceptionAsync();
}

private void RaiseInvalidOperation_Click(object sender, RoutedEventArgs e)
{
    BusinessServiceClient client = new BusinessServiceClient();
    client.RaiseInvalidOperationCompleted += (s, ea) =>
    {
        if (ea.Error != null)
        {
            Message = ea.Error.Message;
        }
        else
        {
            Message = "No exceptions.";
        }
    };
    client.RaiseInvalidOperationAsync();
}

private void RaiseIndexOutOfRange_Click(object sender, RoutedEventArgs e)
{
    BusinessServiceClient client = new BusinessServiceClient();
    client.RaiseIndexOutOfRangeCompleted += (s, ea) =>
    {
        if (ea.Error != null)
        {
            Message = ea.Error.Message;
        }
        else
        {
            Message = "No exceptions.";
        }
    };
    client.RaiseIndexOutOfRangeAsync();
}

private void GetCustomerName_Click(object sender, RoutedEventArgs e)
{
    BusinessServiceClient client = new BusinessServiceClient();
    client.GetCustomerNameCompleted += (s, ea) =>
    {
        if (ea.Error != null)
        {
            Message = ea.Error.Message;
        }
        else
        {
            Message = ea.Result;
        }
    };
    client.GetCustomerNameAsync();
}

#endregion

The code is pretty simple and I am not going into the classes behind the attributes. Please refer to this post if you are interested in them. One thing I will point out is that the code that gives us the ability to send these error across the wire is in the Core folder. I did this so that you could pull this out and put it in it own assembly. That way you can use this for all of your projects and not need to write this code over and over.

On the server, you can have a lot of complex logic going on and use as many third parties as you want. I would simply wrap my service methods with a try/catch block and then return the friendly message I want displayed in my user interface.

You can download the sample application here.

Hope this helps….

Using ICustomTypeProvider in Silverlight 5 beta with JSON and ASP.NET MVC 3

June 3, 2011 6 comments

One of the really powerful new features in Silverlight 5 is the new interface ICustomTypeProvider. This allow us to have a dynamic way to bind to objects that we don’t know the shape of until at runtime. There are three blog posts that you need to read before continuing forward. Please read this post by Alexandra Rusina. In it she provides a nice implementation for ICustomTypeProvider. The other post is by Jeremy Likness. In his post he expounds a little more on what Alexandra provided and gives us the ability to parse JSON. The last post, basically gives us an easy way to format our JSON so that we can see it in a human readable format instead of what it looks like once we pull it from the stream.

This post basically will takes us from the point where Jeremy and Alexandra left us and use ASP.NET MVC 3 to act as our service host for getting data across the wire.

Ok, let’s get started. First of all, I created a blank solution called “CustomTypeProvider”.

Next, I added a new Silverlight 5 project. When asked, I changed the host to be a ASP.NET MVC project. I gave the name of the Silverlight project, “CustomerTypeProvider.Silverlight” and the web host, “CustomTypeProvider.Web”.

I like to use Caliburn.Micro whenever I can and I opted to use the latest version of Caliburn.Micro in my Silverlight project. I used NuGet to pull down the package. It is as easy as right-clicking your References and selecting, “Add Library Package Reference”. Once the dialog appeared, I changed it to online and entered, “Caliburn.Micro” in the search and installed it once it appeared.

I basically followed the steps provided in the web page that comes up in Visual Studio once Caliburn.Micro’s package is installed. I also added the following assembly references:

  • System.Json
  • System.ComponentModel.DataAnnotations
  • System.Windows.Controls.Data

Let’s look at the code necessary for the web first:

namespace CustomerTypeProvider.Web.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Collections;
    using System.Data.SqlClient;

    [HandleError]
    public class HomeController : Controller
    {
        public JsonResult GetCustomers()
        {
            var data = LoadCustomers();
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        public JsonResult GetOrders()
        {
            var data = LoadOrders();
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        public JsonResult GetQuery(string query)
        {
            var data = LoadQuery(query);
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        private List<Customer> LoadCustomers()
        {
            List<Customer> result = new List<Customer>();
            result.Add(new Customer() { FirstName = "Matt", LastName = "Duffield" });
            result.Add(new Customer() { FirstName = "Dean", LastName = "Duffield" });
            return result;
        }
        private List<Order> LoadOrders()
        {
            List<Order> result = new List<Order>();
            result.Add(new Order() { ContactName= "Matt Duffield",
              OrderDate= DateTime.Now, OrderNumber = 100 });
            result.Add(new Order() { ContactName = "Dean Duffield",
              OrderDate = DateTime.Now, OrderNumber = 101 });
            return result;
        }
        private ArrayList LoadQuery(string query)
        {
            ArrayList objs = new ArrayList();

            //SqlConnection conn = new SqlConnection("Data Source=(local);Initial Catalog=Northwind;User Id=myUsername;Password=myPassword;");
            SqlConnection conn = new SqlConnection("Data Source=(local);Initial Catalog=Northwind;Integrated Security = SSPI;");
            //SqlCommand cmd = new SqlCommand("SELECT TOP 10 [CustomerID],[CompanyName],[Address],[City],[Region],[PostalCode],[Country]  FROM [Customers]", conn);
            SqlCommand cmd = new SqlCommand(query, conn);
            conn.Open();
            SqlDataReader r = cmd.ExecuteReader();
            while (r.Read())
            {
                objs.Add(new
                {
                    CustomerID = (r["CustomerID"] is DBNull ? "" : r["CustomerID"]),
                    CompanyName = (r["CompanyName"] is DBNull ? "" : r["CompanyName"]),
                    Address = (r["Address"] is DBNull ? "" : r["Address"]),
                    City = (r["City"] is DBNull ? "" : r["City"]),
                    Region = (r["Region"] is DBNull ? "" : r["Region"]),
                    PostalCode = (r["PostalCode"] is DBNull ? "" : r["PostalCode"]),
                    Country = (r["Country"] is DBNull ? "" : r["Country"])
                });
            }
            r.Close();
            conn.Close();

            return objs;
        }

        public class Customer
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
        public class Order
        {
            public int OrderNumber { get; set; }
            public DateTime OrderDate { get; set; }
            public string ContactName { get; set; }
        };
    };
}

Okay, so there is a little going on but we will start from the top. We basically have three public methods at the top:

  • GetCustomers()
  • GetOrders()
  • GetQuery(string query)

The first two call helper methods that basically create a generic List<> with some sample data and pass it back to the calling method.  The third is a little more dynamic in that it uses ADO.NET to create a SqlConnection, SqlCommand, and finally a SqlDataReader.  It executes the query passed in and then loops through the data reader to shapes a new object that gets added to an ArrayList.  The ArrayList then gets passed back to the calling method. One thing to note about the data reader loop is that we are checking for DBNull and giving it a default value. This is necessary on the client side so that we can infer the type information.

In each of the corresponding methods above, a new Json object is created passing in the data that was returned from the helper methods as well as a second parameter is set to allow the Get verb.

Now let’s move on to the client side.  In the client side, I have to folders that are of interest:

  • Formatting
  • Framework

In the Formatting folder is the logic necessary to format the JSON stream that comes from the web make it human readable.

In the Framework folder is the logic that I took from Alexandra Rusina’s and from Jeremy Likness’ blog posts.  I won’t go into detail in these classes since there are separate posts by each of them dedicated to the classes.  What I will show you is the ShellView and ShellViewModel to see how we get this data and render on screen.

Let’s take a look at the ShellView:

<UserControl x:Class="CustomerTypeProvider.Silverlight.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    >
    <Grid Background="White" Margin="5">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <sdk:DataGrid AutoGenerateColumns="True"
            ItemsSource="{Binding Path=ResultsPaneItems}"
            IsReadOnly="True"
            />
        <TextBox x:Name="JsonResult" AcceptsReturn="True"
                 Grid.Column="1" Grid.Row="0" 
                 Width="400" VerticalScrollBarVisibility="Auto" 
                 HorizontalScrollBarVisibility="Auto"/>
        <StackPanel Grid.Column="0" Grid.Row="1" Orientation="Horizontal">
            <Button x:Name="LoadCustomers" Content="Load Customer" Margin="5" />
            <Button x:Name="LoadOrders" Content="Load Orders" Margin="5" />
            <Button x:Name="LoadQuery" Content="Load Query" Margin="5" />
        </StackPanel>
    </Grid>
</UserControl>

Because I am using Caliburn.Micro, my XAML is very clean.  We see a DataGrid that has it’s ItemsSource property bound to collection property called, “ResultsPaneItems” object.  We also see a TextBox that is bound to a property called, “JsonResult” as well.  Finally, we see three buttons that call the three corresponding web methods.
Looking at the ShellViewModel we see the following:

namespace CustomerTypeProvider.Silverlight 
{
    using System.ComponentModel.Composition;
    using System.Collections.ObjectModel;
    using Core.Framework;
    using Core.Framework.Formatting;
    using Caliburn.Micro;
    using System;
    using System.Net;
    using System.Json;
    using System.IO;
    using System.Diagnostics;

    [Export(typeof(IShell))]
    public class ShellViewModel : Screen, IShell 
    {
        public ObservableCollection<CustomType> ResultsPaneItems { get; private set; }
        private string _jsonResult;
        public string JsonResult
        {
            get { return _jsonResult; }
            set
            {
                _jsonResult = value;
                NotifyOfPropertyChange(() => JsonResult);
            }
        }

        #region ctor

        public ShellViewModel()
        {
            ResultsPaneItems = new ObservableCollection<CustomType>();

        }

        #endregion

        public void LoadCustomers()
        {
            LoadResultsPane("/home/GetCustomers");
        }

        public void LoadOrders()
        {
            LoadResultsPane("/home/GetOrders");
        }
        public void LoadQuery()
        {
            string query = "SELECT TOP 10 [CustomerID],[CompanyName],[Address],[City],[Region],[PostalCode],[Country]  FROM [Customers]";
            LoadResultsPane("/home/GetQuery?query=" + query);
        }

        private void LoadResultsPane(string uri)
        {
            ResultsPaneItems = new ObservableCollection<CustomType>();
            NotifyOfPropertyChange("ResultsPaneItems");

            Uri serviceUri = new Uri(uri, UriKind.Relative);
            WebClient downloader = new WebClient();
            downloader.OpenReadCompleted += (s, e) =>
            {
                // Load the JsonArray from the service call.
                StreamReader sr = new StreamReader(e.Result);
                var content = sr.ReadToEnd();
                JsonResult = new JsonFormatter(content).Format();
                var jsonArray = JsonArray.Load(e.Result) as JsonArray;
                Debug.WriteLine(content);
                if (jsonArray == null) return;

                // Pull the first record as a template.
                var template = jsonArray[0] as JsonObject;
                if (template == null) return;

                // Use the template to get type information.
                var jsonHelper = new JsonHelper<CustomType>(template);

                // Iterate over the results and add to the underlying collection.
                foreach (var item in jsonArray)
                {
                    var customType = new CustomType();
                    jsonHelper.MapJsonObject(customType.SetPropertyValue, item);
                    ResultsPaneItems.Add(customType);
                }
            };
            // Retrieve the data.
            downloader.OpenReadAsync(serviceUri);
        }

    };
}

Okay, let’s start from the top and work our way down. First we see that declaration of the ResultsPaneItems collection. Next we see the property for the JsonResult string. In the constructor, we initialize the collection.

Next, we have the three methods that respond to the corresponding buttons. All three of them call a helper method called, “LoadResultsPane(string uri)”. It is this method that does all of the heavy lifting. The only difference in the methods is that the last one also passes in the query as part of the query string to the GetQuery method on the controller.

In the LoadResultsPane(…) method, we are initializing the ResultsPaneItems to a new collection. Note that this collection is of type CustomType. This is important since we want each button click to load a fresh set of data. Next we use the Uri and WebClient objects to perform the OpenReadAsync(…) call. This is an asynchronous call and that is we we have an anonymous delegate in the form of a lambda expression stating what to do when the call comes back. Inside the expression, we create a StreamReader object off of the Result. We read the stream so that we can use our formatter class and display the raw JSON that was just returned to us. Next we create a JsonArrary and load the same Result object trying to cast it to a JsonArrary object. If that is successfuly, then we use the first row as a representation of the data so that we can type it accordingly. If you recall, this is why we had the test for DBNull in the data reader loop on the controller. Finally, we loop over the JsonArrary and create a CustomType object. We use the JsonHelper provided by the previous blog posts and then add it to our collection.

That is all there is to it. You now have a very dynamic model in which you can data bind to any object that is sent from the server. You no longer need to know about it. The server-side code could be further abstracted so that you had a completely generic solution instead of the hard-coding I have shown in the loop of the data reader.

Here is a sample screen shot of the application:

You can download the sample code here. Don’t forget that this solutions works only for Silverlight 5 beta.
Hope you enjoy…