Beth's Chinese blog
I’ll be speaking again this year at Silicon Valley Code Camp! Only 37 days left to register: http://siliconvalley-codecamp.com/
This free event will be at Foothill College again this year. There are over 100 sessions currently listed covering topics including .Net, Java, JavaScript, Oracle, Facebook, Iphone, Scala, Ruby and many other technologies. There are already almost 800 people registered! Last year we had over a thousand people take over the college campus. It’s a lot of fun and a great way to explore new technologies and learn more about the ones you already work with.
I’ll be presenting at least two sessions:
And I’ll probably show off more of my favorite Visual Studio 2010 features too ;-). There are also a ton of other awesome speakers and sessions. Including, Douglas Crawford, for a fourth year in a row, the inventor of JSON, will be presenting on the Good Parts of JavaScript. Bill Venners, Artima president will be doing a session on Scala and ScalaTest. Mike Van Riper, Founder and co-leader of JUG, will be presenting on Java Apps in the Google App Engine. Lino Tadros, renowned author and speaker will be presenting on Silverlight 3. Plus a ton of other great topics from the developer community.
Register now. If you have registered, come back to the site and let us know what sessions you are interested in.
Hope to see you there!
Yesterday we released a couple more videos onto the Visual Basic Developer Center on building WPF data-entry forms with Entity Framework:
That makes 5 videos total on working with EF in WPF applications. Others released previously:
These videos are based on articles I’ve posted here in the past. So if you like reading better that watching videos here you go:
There are also additional resources listed on the How Do I video pages themselves pointing to topics in the MSDN Library.
Enjoy!
The Winforms ReportViewer in Visual Studio Pro will allow you define client reports with a variety of data sources. If you’re not familiar with creating client-side reports using the ReportViewer, take a look at these videos:
(The ReportViewer can also display server-based reports a la SQL Reporting Services and has a whole boatload of features that I’m not going to talk about here. For more information on this freely redistributable control, please read ReportViewer Controls (Visual Studio) in the MSDN library.)
ADO.NET Data Services was released with Visual Studio 2008 SP1 and is basically a framework for exposing your data models via RESTful web services. So if you are building a remote CRUD data access layer then this is a technology that will make that super-simple, especially if you just want to expose a few data entities as read-only report sources. (I’ve written a lot about how to use ADO.NET Data Services in a variety of ways so check out these posts if you’re interested.) Entity Framework was released at the same time and you can use EF as the data model behind your ADO.NET Data Service and expose it easily. If you’ve never created one before, check out this quick start here.
What’s the Problem?
If you’ve ever tried to use the ReportViewer to design a client-side report with an ADO.NET Data Service data source (or use an Entity Data Model directly) you may be disappointed. If you try to design a new report, the wizard may crash Visual Studio when selecting an entity. Yikes!
Let me show you what I mean, but don’t try this at home. I have an ADO.NET Data Service based on the Northwind database like the one I created here and in the quick start. I then added a Windows Forms client project to the same solution (File –> Add –> New Project, then select Windows Forms App). Now open Form1 in the client and from the toolbox under the Reporting tab, drop the Microsoft ReportViewer control onto the form and from the smart tag select “Design a New Report”.
This will open the Report Wizard. The first thing I need to do is tell it what data source to use, so I’ll select Service and click Next. This will open the Add Service Reference dialog box where I can add the reference to my data service and Visual Studio will generate the proxy objects for me. In this example my service is in the same solution as the client so I can just click the Discover button and Visual Studio will see it. I named it NorthwindService. Click OK then click Finish.
At this point I’m brought back to the Report Wizard:
Hmmmm…. I’m a little lost at this point because -- didn’t I just select the data source? Why don’t I see it?
Maybe I should have added the service reference first from the Solution Explorer instead of through the Report Wizard? You can do that and you’ll get to the same screen at this point.
So okay, I’ll click the Add Data Source button that’s calling to me. Granted, I like clicking buttons that have the ellipsis (…) on them because I’m always curious to see what’s under them, but this seems redundant.
This opens the same dialog as before but this time I’ll choose Object instead of Service. I’m choosing object this time because I’m going to try and bind to the client proxy types that were generated for me when I added the service reference. After selecting Object, click Next and expand the service namespace.
For this report I want to just display a list of Customers in the system so I’ll select Customers and then click Next.
Then… then…… are you ready?… you better sit down for this…. click Finish……. wait for it…. wait for it….. not responding…. uh ohhhh…..
Visual Studio has encountered a problem and needs to close. Darn!
Now that was fun.
How Do I Fix this?
Unfortunately the Report Wizard in Visual Studio 2008 doesn’t know how to work with many-to-many relationships and that’s exactly what we have defined in our EF Entity Data Model which is what is backing our ADO.NET Data Service. Customers have many CustomerDemographics and vice versa in Northwind. You can actually define a couple classes yourself manually and create a many-to-many association between them:
Public Class Class1 Private _class2 As List(Of Class2) Public ReadOnly Property Class2() As List(Of Class2) Get Return _class2 End Get End Property End Class Public Class Class2 Private _class1 As List(Of Class1) Public ReadOnly Property Class1() As List(Of Class1) Get Return _class1 End Get End Property End Class
Try to use either class above as the data source of the report and it will crash too. Woah! So when the report designer tries to read these associations I’m guessing it gets into an infinite loop walking the association references back and forth and then it crashes. So it’s not an error with the generated proxy objects per se, the root cause is our object model. If I would have chosen Categories instead, it would have worked.
So what do we do? We could create another layer of classes without the associations on both sides if we wanted and then use those types instead but then we’d have to write code that IMO is pretty useless, just to shape the data again how we want on the client.
My recommendation is to create a separate data model for your reports that doesn’t have many-to-many associations at all. You’re going to end up with a lot of different looking entities anyways for your reports because they will most likely pull from multiple database Views and/or stored procedures. You’ll always be displaying one side of the many-to-many relationship on paper anyways.
Creating a Reporting Data Model
So let’s go back to the data service project and add a new Entity Data Model to the web project called NorthwindReport. This time I’ll just select the Customers, Orders and Order Details and all the Views defined in the database.
Next I’ll add the ADO.NET Data Service and call it NorthwindReport and configure it so that we’re only allowing read-only access to our data by setting the entity access rule like so:
Imports System.Data.Services Imports System.Linq Imports System.ServiceModel.Web Public Class NorthwindReport Inherits DataService(Of NorthwindReportEntities) Public Shared Sub InitializeService(ByVal config As IDataServiceConfiguration) config.SetEntitySetAccessRule("*", EntitySetRights.AllRead) End Sub End Class
Now back on the client we can add the service reference to this service instead. After we add the service reference we can run the Report Wizard again by selecting “Design a New Report” smart tag on the ReportViewer control like I showed in the beginning. Select Object as the data source (or Service if you didn’t add the service reference first, then you’ll have to click “Add Data Sources…” again and then select Object) and you should see the list of entities exposed in the NorthwindReport data model. Now when we select Customer, we don’t have a problem.
Design the report how you like (see the documentation for more details) by clicking through the wizard and then go back to the smart tag on the ReportViewer and you should see the report you just created in the dropdown. Next go to the code-behind for the form and in the Load handler we just set the BindingSource.DataSource property to the results of the ADO.NET Data Service LINQ query:
Imports NorthwindClient.NorthwindReportService Public Class Form1 Private Sub Form1_Load() Handles MyBase.Load 'TODO: put in My.Settings Dim uri As New Uri("http://localhost:1933/NorthwindReport.svc/") 'Create the service reference Dim db As New NorthwindReportEntities(uri) 'Set the report's DataSource to the results of the query Me.BindingSource.DataSource = From c In db.Customers _ Where c.Country = "USA" _ Order By c.CompanyName Me.ReportViewer1.RefreshReport() End Sub End Class
Now hit F5 to run this baby and you’ll see the report pull the data from the service and display in the form:
Recap & Resources
ADO.NET Data Services are a great way to quickly and easily expose data on the web, especially if it’s just read-only data used for remote reporting clients. The key to using the ReportViewer with ADO.NET Data Services (or an Entity Data Model directly, or even your own object model) is to make sure there are no many-to-many associations on the entities. Here are the resources you need to get started with ReportViewer and ADO.NET Data Services:
This month I have an article on DevProConnections:
Taking Advantage of LINQ and XML in Microsoft Office 2007
In this article, I talk about how a lot of applications that need to take advantage of Microsoft Office can do so without going through COM. Many programs that need to process documents often require manipulation of the file formats directly and doing that through the Office component object model won’t scale very well. It also requires that Microsoft Office be installed to run. A better route in a lot of these cases is to use the Open XML SDK. With the release of Office 2007, Word documents, Excel spreadsheets and PowerPoint presentations are based on an open standard for packaging XML files called Open XML. Using Visual Basic’s powerful and simple implementation of LINQ to XML you can work with these new document formats much easier than ever before.
I show a couple practical examples of reading data from Word documents and updating a database as well as reading data from a database to create Word documents – all without COM. No Office applications need to be installed in order to read and write to these formats directly.
This article is based on the two episodes I did on DnrTV:
[UPDATE: Here's code samples (also includes a presentation pptx)]
More resources:
I just finished a couple more How Do I videos on using EF with WPF using VS2008 SP1 (they’ll be published soon) and while I was translating my VB code to C# I stumbled upon an error in C# that does not happen in VB. This of course got me curious and so I thought I’d share what I found out.
I have an EDM defined with a parent entity Order and child OrderDetails that I created with the designer – very basic – like I show in this video. In the example I was working on, I was putting the results of an order query into a generic list but also including the OrderDetails so I end up with an EntityCollection called OrderDetails on every Order.
OMSEntities db = new OMSEntities(); var results = from o in db.Orders.Include("OrderDetails") select o; List<Order> orderList = new List<Order>(results);
However if I want to get the first Order’s first OrderDetail, I get an error in C#: “Cannot apply indexing with [] to an expression of type 'System.Data.Objects.DataClasses.EntityCollection<EFTestDAL.OrderDetail>'” when I write this line:
//ERROR Console.WriteLine(orderList[0].OrderDetails[0].OrderDetailID);
However, the VB code works perfectly.
Dim db As New OMSEntities Dim results = From o In db.Orders.Include("OrderDetails") _ Select o Dim orderList As New List(Of Order)(results) 'No Error Console.WriteLine(orderList(0).OrderDetails(0).OrderDetailID)
So what gives in C#? At first I thought it was something with the way the EntityCollection was being generated in each of the designer code-behind for the languages, maybe I found a bug? So I created a single solution and used C# as the data access layer project and then added a C# client and a VB client project and still the same issue. VB worked fine against the C# defined EntityCollection. Hmmmm……
Next Stop, BING. I searched for the error message and no luck. Okay well it helps to actually read these error messages so let’s put on my glasses and break out my Microsoft Compiler Error Message Magic Translator* and yeah, as the title of this post suggests, the EntityCollection doesn’t actually implement an indexer. Okay so again, why does it work in VB?
The VB Compiler loves to help. It’s like uber-helpful (sometimes to its own fault, I admit), but this time it’s really helping in a good way. The way to get this to work in C# is to call the ElementAt or ElementAtOrDefault extension methods. So in C# to get the OrderDetail by index you write:
//No ERROR Console.WriteLine(orderList[0].OrderDetails.ElementAt(0).OrderDetailID);
So what Visual Basic is doing for you is exactly that. Actually it’s calling ElementAtOrDefault for you if the collection does not implement an indexer of its own. So you can write the same syntax for all collections. This help topic on the Extension Indexer Property gave us the clue we needed. So, if an IEnumerable or IQueryable doesn't define an indexer property, VB will translate the indexer syntax to the ElementAtOrDefault operator. Good to know!
So I asked Diego on the EF team why the EntityCollection doesn’t implement an indexer. I was told that the EF team decided long time ago that since there was conceptually no guarantee on the ordering of EntityCollections, they didn’t want to give the illusion that such ordering existed by exposing an indexer. The internal implementation of EntityCollection(Of T) uses HashSet(Of T), which is super-fast and doesn’t have an indexer.
*No there is no such thing as a Microsoft Compiler Error Message Magic Translator that I know of so please don’t ask! But please feel free to create one on CodePlex. ;-)
I was cleaning up my desk today and in the piles of mail and gobs of paper I found the SDN Magazine “Women in Technology” issue 101 that featured an article I wrote that was released in print back in May. Well, I just noticed today that near the end of June they made most of the articles available online, including mine. :-)
Using Windows Presentation Foundation and Line-of-Business Data in Microsoft Office Clients
In this article I talk about how to expose Line-of-Business data via ADO.NET Data Services to an Excel client using WPF. Office solutions you build with Visual Studio are designed to work with Windows Forms controls but you can also use WPF controls in your solutions as well. Any UI element that can host Windows Forms controls in an Office solution (VSTO) can also host WPF controls using the Winforms ElementHost as a container.
Using WPF controls in Office allows you to think out of the box and provide world-class data visualizations that are not possible with Windows Forms controls. And you can do it easily in an instantly familiar end-user application like those in the Office family. But what if you don’t have any fancy data visualizations? Even the simplest controls that display data are often better off as WPF controls in Office applications because they better match the UI styles used in the latest versions of Office. Using WPF can make your add-ins look built into the Office applications themselves, providing a better user experience.
This article describes one piece of the Northwind Office Business Application (OBA) we created in the beginning of the year so if you’re interested in OBA development with Outlook, Word, Excel and Sharepoint I’d suggest reading these as well:
The full sample application, built with Visual Studio 2008, is here: http://code.msdn.microsoft.com/OBANorthwind
Of course, the rest of the magazine is pack full of awesome articles from very well known women in technology (scroll to the bottom of this page for the whole list). I’m honored to be featured with them in this issue. Thanks again to Marianne van Wanrooij and the folks at SDN for putting this together and I’ll see you in October at the SDN Conference!
Window 7 is available to MSDN subscribers today! My friend is so excited she pinged me in IM and told me she was refreshing her browser all morning on MSDN’s home page until the headline showed up. LOL!
Everyone is so excited maybe that’s why Twitter went down today and made the morning local news.
Anyways, I’m so ready to repave my main laptop with Windows 7. I’ll be doing a network install when it’s available on Microsoft’s corpnet this month. It’s so much easier that way, MSIT takes care of bundling all the drivers and software I need into an unattended install you start by booting from the network. Yes I’m excited but also lazy. :-) Goodbye VM, hello metal.
BTW, check out Scott's post if you're upgrading a Vista box to Windows 7 that has Visual Studio 2010 Beta 1.
Have fun downloading from MSDN today everyone!
This month’s MSDN Magazine has a particularly good article in there by Danny Simmons, Development Manager on the Entity Framework team, on N-Tier Application Patterns with Entity Framework that I recommend reading through. He explains the design considerations you need to take into account when building n-tier applications and also discusses some of the improvements that are coming in .NET Framework 4.0 that will make building n-tier applications with EF much much easier. I’m personally looking forward to self-tracking entities myself, hooray!
Tim Mallalieu also has a good best practices article in this issue that I just started digging into regarding the next version of Entity Framework.
Today Justin updated the Silverlight Toolkit on CodePlex with samples in Silverlight 3 that you can run live directly on the site. Check out all the live tutorials:
And best of all, the samples show a Visual Basic code view:
Support for Visual Basic in the toolkit itself was available in March, but now the live samples are also updated. Clicking the VB.Net button changes the code sample to Visual Basic and saves this preference so all code samples will default to the selected language:
I’m just starting to play with Silverlight (and .NET RIA Services) myself so I’m glad to see these interactive samples in VB come online. Another really fun addition to the samples is an interactive DLR console for IronPython and IronRuby. If you're just getting your feet wet with these dynamic languages you should check this out, it even has some basic intellisense to help you.