Monthly Archives: January 2008

MVC with Entity Framework … a twist on Brad Abram’s example

I followed the great walkthrough on Brad’s blog showing how to use MVC together with Entity Framework. But I did it my own way – in VB, using a different database and trying to write more effective EF queries. I have a simple solution that renders these views from the AdventureWorksLT database:

Start with a list of customers who have orders in the system (that’s less than 10% of the full customer list)

Then I can click on a customer and see a list of their orders

 

Then drill in to see the order details. (The Edit button is not implemented yet, in case you were wondering!)

 

So here is what’s significantly different from Brad’s walkthrough.

  • My EDM is created from AdventureWorksLT.
  • The relationship from AW’s SalesOrderHeaders to Customer is the same as the relationship from Northwind’s Products to Category. Therefore, where he use Products, I use SalesOrderHeaders and  where he uses Categories, I use Customers.
  • One of the keys for getting data easily to a view is that we need to send ONE object (and not an anoymous type) to the view. Yet what we really desire in the case of the List of Order (which also has the Customer Name) and the list of details (which also has data from the order and the customer) is an object graph.

So on the 2nd page, I need to pass in an set of orders with their related Customer entity so that I can have access to the customer name.

On the 3rd page, I need to pass in a set of order details with their related Order entiteis AND the order’s related customer.

Brad achieves this by starting with the desired entity and then using entity references and some scary looking LINQ to Entities queries.

List<Product> products =TheProducts.Where(c => c.Category.CategoryName == category).ToList();//prepare the view by explicitly loading the categoriesproducts.FindAll(p => p.Category == null).ForEach(p => p.CategoryReference.Load()); 

Only because I’ve spent a lot of time with LINQ to Entities, do I happen to know a little trick.

If I start with the “parent”, i.e. category and query it’s property collection (i.e. products), when I return the property collection, the “parent” entity is still attached.

So taking Brad’s query, I can get the same effect with this query (still in C#):

 var _prod = Northwind.Categories.Where(c => c.CategoryName == id).OrderBy(c => c.CategoryName).Select(c => c.Products).First().ToList(); 

(Update: turns out this only works because of a bug which will get fixed – see THIS POST for an even better way!)

This returns a list of products that belong to the category. However I do not have to do any extra loading to get to Product.Category.CategoryName. Beasue my query began with the Category, it’s already there. (I learned this by trial and error by the way.)

Therefore, in my SalesOrderController (my versoin of his productController), the List ControllerAction code is a little different.

I use the same type of querying to get the order details.

Another thing that I spent some time thinking about and asking about was about the ObjectContext. In a web app you want an ojbectcontext to be as short-lived as possible. I notice that Brad was instantiating in the class level declarations. This is okay because in the background, MVC  instantiates  the class for each ControllerAction and then disposes it when it’s finished. It doesn’t hang around waiting for another method call. (This is one of the key premises of MVC. As Kevin Hoffman explained to me, it works in “short bursts” long enough to get something out to the browser. I have much to learn!)

Brad uses the CategoryName as the basis for the view creation so that he gets a pretty URL http://host/products/list/Beverages.

I’m still seeing if there is a way around this, but I don’t like querying on a string like this. I like my keys! So I’m passing in CustomerID and SalesOrderID and my urls aren’t as pretty.

Here is what my controller looks like and you can see my queries that populate the Customer List, the customer’s order list and the order’s detail list.

Imports System.Web.MvcImports System.LinqImports MvcApplication.awModelNamespace MvcApplication.Controllers Public Class SalesOrdersControllerInherits System.Web.Mvc.Controller
<ControllerAction()> _Sub Index()REM Add Action Logic hereEnd Sub
‘example URL:http://localhost:xxxx/SalesOrders/Customers<ControllerAction()> _Public Sub Customers()Using aw = New awEntitiesDim _customers = aw.Customers. _
Where(Function(c) c.SalesOrderHeaders.Any). _
OrderBy(Function(c) c.CompanyName).ToListRenderView(“Customers”, _customers)End UsingEnd Sub
‘example URL:http://localhost:xxxx/SalesOrders/List/[CustomerID]<ControllerAction()> _Public Sub List(ByVal id As String)Using aw = New awEntitiesDim _salesorders = (From cust In aw.Customers _Where cust.CustomerID = id _Select cust.SalesOrderHeaders).FirstorDefault.ToListRenderView(“SalesOrdersbyCustomer”, _salesorders)End UsingEnd Sub
‘example URL:http://localhost:xxxx/SalesOrders/List/#### (order number)<ControllerAction()> _Public Sub Detail(ByVal id As String)Using aw = New awEntitiesDim _order = (From ord In aw.SalesOrderHeaders.Include(“SalesOrderDetails.Product”) _ Where ord.SalesOrderID = id _ Select ord).FirstDim _order2 = (From cust In aw.Customers.Include(“SalesOrderHeaders.SalesOrderDetails.Product”) _ Where cust.SalesOrderHeaders.Any(Function(so As SalesOrderHeader) so.SalesOrderID = id) _ Select cust.SalesOrderHeaders).First.ToList.FirstRenderView(“SalesOrder”, _order2)End UsingEnd Sub End ClassEnd Namespace 

The markup is not really different from Brad’s since I can drill from the ViewData into my references (Customer, Product, SalesOrder) thanks to my queries (which make me feel so clever!)

The last page just uses tables to do the trick.

<asp:Content ID=”Content1″ ContentPlaceHolderID=”MainContentPlaceHolder” runat=”server”>
<h2><%=ViewData.Customer.CompanyName%></h2>
<h3>
<%=String.Format(“Sales Order #: {0}”, ViewData.SalesOrderNumber)%>
<%=String.Format(“Order Date: {0:d}”, ViewData.OrderDate)%>
<%=String.Format(“Order Total: {0:C2}”, ViewData.TotalDue)%>
</h3>
 <table>
 <tr><td style=”width: 225px”>Product</td><td style=”width: 154px”>Quantity</td>
   <td style=”width: 256px”>Line Item Total</td></tr>
            <% For Each detail As awModel.SalesOrderDetail In ViewData.SalesOrderDetails%>
            <tr>
               <td style=”width: 225px”><%=detail.Product.Name%></td>  
               <td align=”center” style=”width: 154px”><%=detail.OrderQty%></td>
               <td style=”width: 256px”> <%=String.Format(“{0:C2}”, detail.LineTotal)%></td>
            </tr>
        <% Next%>
    </table>
</asp:Content>

As an aside, this was my first time really playing with client side code in VS2008 and I am enamored of all the intellisense in there!

Converting Silverlight InkPresenter images to a PNG file

In the TabletPC SDKs and in WPF it’s very easy to take an ink image and save it to an image format – BMP, JPG, etc.

Then came Silverlight and the InkPresenter and naturally I wanted to do the same. But it wasn’t so easy.

Silverlight itself isn’t bogged down with that functionality. So you first need to get the XAML representation of the Ink and send it to a service where either the TabletPC SDK or the WPF APIs are available. Even then you are not home free because the Silverlight ink is not quite the same as either of the other two. So you then need to extract data from the XAML representation of the Silverlight ink and create a new object for whichever API you choose.

This was all done in Silverlight 1.0. I haven’t pulled this into Silverlight 1.1/2.0 yet, but it should all be the same and you still have to do the conversion on the server side. THe only difference of course, is the javascript needs to be converted to .NET code on the client side.

Even then, there is still some more trickery because there is something strange with using the width from the Silverlight object and I spent hours just experimenting with getting the proportions to display properly in the image. I also spent a lot of time struggling with the colors because the javascript output of the color values doesn’t line up with what WPF wants. You’ll see in the code comments all of the conversions going on.

Once I had all of that worked out (and this represents hours of effort) there were still some issues. Luckily, Stefan Wick, who is the ultimate guru on this topic and finally has a blog – hoorah!, was able to set me straight (and trim some  of my code down significantly).

I hadn’t thought much of this nor, apparently had anyone else, until someone recently emailed asking me how I did it so that he can use it as part of a solution in a competition. (I hope that the requirements of the competition don’t say anything about original work!), so I thought I would blog the steps.

1) Convert the InkPresenter data to XAML . This does two things. FIrst it enables you to serialize it and pass it to a web service and secondly, it is the lowest reasonable common denominator for sharing between different objects. This javascript code comes from Gavin Gear.

This javascript code reads through the StrokeCollection property of an InkPresenter and builds up a string of xml that is the XAML representation of the StrokeCollection. You could also take the resulting string and pass it to CreateFromXAML to recreate the Silverlight StrokeCollection object.

  if (strokeCollection.Count>0)  
{
    var xaml = "<StrokeCollection>";
   if (strokeCollection != null)
   {
for (var i = 0; i < strokeCollection.Count; i++)
{
  var stroke = strokeCollection.GetItem(i);
  if (stroke.Name>"")
    xaml += "<Stroke Name='" + stroke.Name + "'><Stroke.DrawingAttributes>";
  else
    xaml += "<Stroke><Stroke.DrawingAttributes>";
    xaml += "<DrawingAttributes ";
    xaml += "Color='" + BrowserColorConverter
            (stroke.DrawingAttributes.Color) + "' ";
    xaml += "OutlineColor='" + convertColorToHexString
               (stroke.DrawingAttributes.OutlineColor) + "' ";
    xaml += "Width='" + stroke.DrawingAttributes.Width + "' ";
    xaml += "Height='" + stroke.DrawingAttributes.Height + "' ";
    xaml += "/></Stroke.DrawingAttributes>";
    xaml += "<Stroke.StylusPoints>";
    for (var j = 0; j < stroke.StylusPoints.Count; j++)
    {
      var stylusPoint = stroke.StylusPoints.GetItem(j);
      xaml += "<StylusPoint X='" + 
               roundToTwoDecimalPlaces(stylusPoint.X) + "' Y='" +   
roundToTwoDecimalPlaces(stylusPoint.Y) + "' />"; } xaml += "</Stroke.StylusPoints></Stroke>"; } } xaml += "</StrokeCollection>";

2) Pass this string to a web service method that will do the following to it

3) Create a WPF InkObject from the XAML. Now that I’m in the web service, I can use .NET code. Phew. Note that I did this before I knew how to use LINQ to XML so I struggled through XPath to get this. Watch for an upcoming MSDN Mag article that will have updated code.

private static StrokeCollection InkObjectfromXAML(XmlNode StrokeColl)
{
  StrokeCollection objStrokes = new StrokeCollection();
  XmlNodeList strokeElements =StrokeColl.SelectNodes("Stroke");
  foreach (XmlNode strokeNodeElement in strokeElements)
  {
   //step 1: create a new stroke from the stylus point elements in the XAML
    XmlNodeList stylusPointElements = strokeNodeElement
               .SelectNodes("./Stroke.StylusPoints/StylusPoint");
    XmlNode drawAttribs = strokeNodeElement 
               .SelectSingleNode("./Stroke.DrawingAttributes");
    //points node is sent to GetStrokePOints method to convert to a type 
//that can be used by the new stroke
System.Windows.Input.StylusPointCollection strokeData = GetStrokePoints(stylusPointElements); Stroke newstroke = new Stroke(strokeData); //step 2: grab color metadata about stroke from the xaml //color is a hex value //the stroke object requires a System.Windows.Media.Color type //following code performs the conversion string mycolor = drawAttribs.FirstChild.Attributes["Color"].Value; Drawing.Color drwColor = Drawing.ColorTranslator.FromHtml(mycolor); //build the new color from the a,r,g,b values of the drawing.color Windows.Media.Color newColor = new Windows.Media.Color(); newColor.A = drwColor.A; newColor.R = drwColor.R; newColor.G = drwColor.G; newColor.B = drwColor.B; //Step 3: extract width data from xaml, convert to int int myIntWidth; bool parseSuccess = int.TryParse (drawAttribs.FirstChild.Attributes["Width"].Value,
out myIntWidth); //Step 4: apply width & color to stroke //some really wierd unexplainable transformations that I had to get     // around until the final images looked right. if (myIntWidth == 3) newstroke.DrawingAttributes.Width = 1.5; else newstroke.DrawingAttributes.Width = 2; newstroke.DrawingAttributes.Color = newColor; //Step 5: add stroke to the stroke collection objStrokes.Add(newstroke); } return objStrokes; } //The GetStrokePoints method (called from the method above, //is an abstraciton of some sample code from Microsoft.
private static Windows.Input.StylusPointCollection GetStrokePoints(XmlNodeList stylusPointElements) {
Windows.Input.StylusPointCollection pointData = new Windows.Input.StylusPointCollection(); //The object requires HiMetric point values, // create multiplier for conversion double pixelToHimetricMultiplier = (2540d / 96d) / 100; foreach (XmlNode stylusPointElement in stylusPointElements) { string xStr = stylusPointElement.Attributes["X"].Value; string yStr = stylusPointElement.Attributes["Y"].Value; //x and y are in pixels, //we need to multiply them to get them into HIMETRIC //space, which is what the InkAnalyzerBase expects int xInHimetric = (int)(Convert.ToDouble(xStr) * pixelToHimetricMultiplier); int yInHimetric = (int)(Convert.ToDouble(yStr) * pixelToHimetricMultiplier); pointData.Add(new Windows.Input.StylusPoint(xInHimetric, yInHimetric)); } return pointData; }

 Now we have an inkObject that WPF will be happy with!

4) Convert WPF Ink to PNG format bytes This is with a BIG thanks to Stefan – we need to start a separate thread to do the conversion from WPF Ink ojbect to PNG. That conversion happens inside the thread. Also, thank to his deep understanding of the ink object, Stefan was able to accomplish in a much smaller amount of code what I had achieved in about 3 times as much code. I was definitely doing loop-dee-loops, but it was the best I could come up at the time.

Note that I am not saving to an actual file here, just creating the bytes because my goal was to store that in a database.

private static void ThreadforConverttoPNG()
{
  Thread t = new Thread(new ThreadStart(ConverttoPNG));
  t.SetApartmentState(ApartmentState.STA);
// Start ThreadProc.Note that on a uniprocessor, the new 
// thread does not get any processor time until the main thread 
// is preempted or yields.Uncomment the Thread.Sleep that 
// follows t.Start() to see the difference.
t.Start();
   }

private static void ConverttoPNG()
{
  //I had originally achieved this with a LOT more code.
  // This is Stefan's more trimmed down method
  //create temporary InkCanvas
  InkCanvas inkCanvas = new InkCanvas();
  inkCanvas.Strokes = strokes;
  //render InkCanvas to a RenderBitmapTarget
  Rect rect = inkCanvas.Strokes.GetBounds();
  RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
          (int)rect.Bottom, 96d, 96d, Windows.Media.PixelFormats.Default);
  rtb.Render(inkCanvas);
  //endcode as PNG
  BitmapEncoder pngEncoder = new PngBitmapEncoder();
  pngEncoder.Frames.Add(BitmapFrame.Create(rtb)); 
  //save to memory stream
  System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
  pngEncoder.Save(ms);ms.Close();strokeBytes= ms.ToArray();
} 

5) My next step was actually to store the bytes into a database. I wasn’t actually saving out to a file. But to do that is simple. System.IO.File lets you create a new file on the fly from a byte array.

   System.IO.File.WriteAllBytes("C:\\myfile.png",strokeBytes); 

So, those are all of the pieces from converting a silverlight inkpresenter image to an image file.

Jonathan Bruce of DataDirect’s 2008 Predictions

Jonathan Bruce is the .NET wizard at DataDirect, who makes a variety of data providers for .NET.

Among his Predictions for 2008 in this blog post, he includes these four regarding .NET:

1. Data Services changes becomes universal programming model.

2. IBM files a draws together a set of established JDBC experts to establish LINQ for Java, Java Specification Request (JSR)

3. Dynamic LINQ bridges gap between compile-time type checking available in more static LINQ constructs.

4. LINQ to SQL will be forced to open up their lighter weight model to third-party provider-writers.

The last is especially of interest as I muse about whether 3rd party providers will be writing LINQ providers AND EF providers, or just write EF providers and get the LINQ part for free, even though it may mean a little more effort to developers who want to do the more RAD development offered by LINQ to SQL.

While DataDirect is definitely working on EF providers (Oracle, SyBase, SQL Server and DB2). It certainly sounds like DataDirect is interested in writing direct LINQ providers.

Vermont IT Jobs: .NET developer in Burlington

QVAULT in Burlington has an opening for an .Net Developer. “We are looking for more of an Entry Level to Associate Level person, but are willing to see and consider a more experienced person if they are a good match.”

Skills Required

ASP.NET, C#, Web Services

Job Description

If you are an experienced ASP.NET developer, or a soon to be or recent graduate of a programming oriented curriculum, who wants to work for a great Vermont Owned company, read on!

Qvault is looking for a talented software developer who prefers a fast paced and diverse environment, an individual who is a creative self-starter and desires to be an integral part of a team building a young company.

Required skills:

– Understanding of ASP.NET
– C#
– Web Services

Desirable skills:

– AJAX
– XML
– JavaScript
– SQL Fundamentals (MS SQL platform, management tools, jobs)
– SQL Stored Procedures
– HTML/XHTML
– Web standards and cross-browser/platform delivery
– ColdFusion
– IIS6

About Qvault:

Qvault, Inc., a privately held corporation; develops, hosts and supports web based business intelligence, collaboration and document/content management solutions for professional organizations throughout North America.  Please visit our website at www.Qvault.com.  Qvault’s main offices are located in downtown Burlington, Vermont.