NOTE: Since SP1 of .net 3.5 came out this post has become outdated. You no longer have to add the Microsoft.Data.WebClient into the project and you no longer have to create your class outside of VS and bring it in. It has become a lot easier. You can now reference the data service just like any other service in VS by add a new service reference and pointing to the data service URI. This will create the underlying model for you on the client side. I appologize for any confusion as this blog was written pre .net 3.5 SP1. Life is so much easier now!
In My last 2 blogs I have introduced ADO.Net DataServices and I have showed you how to read and manipulate the data in a browser. This blog will be a continuation of those blogs. In order to follow along in this blog you will have to minimally run through Part 1 to create the data service that will be used in this blog. I did not intend this blog to be self contained, it is part of a larger series of blogs. So, please read the first two parts of this series before attempting to work through this one. Thanks!
-
Make sure the ADO.Net Data Service from Part 1 of this blog is running – you can do this by hooking it up in your IIS or just debugging it from Visual Studio.
-
Open up Visual Studio 2008.
-
Click File/New/Project
-
Choose a Windows Forms Application and click OK. NOTE: I am showing this in a Windows Forms Application to prove a point that any .net application can be the client. You could do this in a WPF, Web Application, Silverlight App, etc….
-
Add a reference to the Microsoft.Data.WebClient
-
The Microsoft.Data.WebClient gets put on your computer when you install the ASP.Net Extensions
-
It is located at %ProgramFiles%\Reference Assemblies\Microsoft\Framework\ASP.NET 3.5 Extensions
-
Right click on the References folder and choose Add Reference…\
-
Browse to the location of the dll and add the Microsoft.Data.WebClient.dll
-
-
Next we are going to generate a new object layer classes that can be used on our client app. We are going to do this with a command line tool that is installed on the computer when you installed the ASP.Net Extensions. Microsoft will be rolling this into Visual Studio eventually, but for right now this is the best way to do this. You could do this manually by creating each class individually, but this command line tool will interrogate the Data Service to create these classes for you.
-
Make sure the ADO.Net Data Service from Part 1 of this blog is running – you can do this by hooking it up in your IIS or just debugging it from Visual Studio.
-
Open a Command Prompt (note to Vista users – make sure you do this as an administrator)
-
Browse to %ProgramFiles%\Microsoft ASP.NET 3.5 Extensions
-
Run this command: WebDataGen.exe /mode:ClientClassGeneration /outobjectlayer:AdventureWorks.cs /uri:http://localhost:61823/DemoDataService.svc
-
Import the generated class into your project
-
Right click on the project and choose Add/Existing Item…
-
Browse to %ProgramFiles%\Microsoft ASP.NET 3.5 Extensions and find the AdventureWorks.cs that was created. Then click Add.
-
Note: replace your localhost and DataService with the URI in the command above -
-
Right click on the project and choose Add/New Item…
-
Choose a class and call the class AdventureWorksServiceProcessor.
-
Add a using statement to the class in order to have it reference the classes created in step 6 - using AdventureWorksModel;
-
Add a using statement to the class in order to have it reference the WebClient dll we created in step 5 – using Microsoft.Data.WebClient;
-
Add the following member to the class – AdventureWorksEntites context;
-
Add a constructor to the class in order to open the dataservice and set the reference to the objects.
-
Your class should look like this now (of course, change the string in the URI to point to your localhost port and service):
-
Create some retrieve methods. For this example we are going to retrieve two different ways. The first way will be with a WebDataQuery (this is just like what we did in the browser in Part 2 of this blog). The second way will be with LINQ queries. Add them both into your class because they are doing two different things (one is querying the products and the other is querying the categories).
-
WebDataQuery way:
-
LINQ way:
public IList GetProducts(string productName, ProductSubcategory category) { int categoryId = category.ProductSubcategoryID; WebDataQuery products = context.CreateQuery("/ProductSubcategory(" + categoryId + ")/Product?$filter=contains(Name,'" + productName + "') or '' eq '" + productName + "'"); List productsSet = new List(); foreach (Product p in products) { context.LoadProperty(p, "ProductSubcategory"); productsSet.Add(p); } return productsSet; }public IList GetCategories() { var ProductCategories = from c in context.ProductSubcategory select c; return ProductCategories.ToList(); } -
-
Create the add, update, and delete methods. In the end your AdventureWorksServiceProcessor class should look like this:
-
Now you can create your WebForm however you want and call out to your AdventureWorksServiceProcessor as your Data Access layer. For example: Add a combo box onto your WebForm. Then in the code behind set the datasource for the combo box to the GetCategories method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Data.WebClient;
using AdventureWorksModel;
namespace WindowsFormsApplication1
{
class AdventureWorksServiceProcessor
{
AdventureWorksEntities context;
public AdventureWorksServiceProcessor()
{
Uri serviceUri = new Uri("http://localhost:61823/DemoDataService.svc");
context = new AdventureWorksEntities(serviceUri);
context.MergeOption = MergeOption.AppendOnly;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Data.WebClient;
using AdventureWorksModel;
namespace WindowsFormsApplication1
{
class AdventureWorksServiceProcessor
{
AdventureWorksEntities context;
public AdventureWorksServiceProcessor()
{
Uri serviceUri = new Uri("http://localhost:61823/DemoDataService.svc");
context = new AdventureWorksEntities(serviceUri);
context.MergeOption = MergeOption.AppendOnly;
}
public IList GetProducts(string productName, ProductSubcategory category)
{
int categoryId = category.ProductSubcategoryID;
WebDataQuery products =
context.CreateQuery("/ProductSubcategory(" + categoryId + ")/Product?$filter=contains(Name,'" + productName + "') or '' eq '" + productName + "'");
List productsSet = new List();
foreach (Product p in products)
{
context.LoadProperty(p, "ProductSubcategory");
productsSet.Add(p);
}
return productsSet;
}
public IList GetCategories()
{
var ProductCategories = from c in context.ProductSubcategory
select c;
return ProductCategories.ToList();
}
public void DeleteProduct(Product product)
{
context.AttachObject("Product", product);
context.DeleteObject(product);
context.SaveChanges();
}
public void UpdateProduct(Product product)
{
ProductSubcategory newCategory = product.ProductSubcategory;
context.AttachObject("Product", product);
context.LoadProperty(product, "ProductSubcategory");
if (newCategory.Name != product.ProductSubcategory.Name)
{
context.DeleteBinding(product, "ProductSubcategory", product.ProductSubcategory);
context.AttachObject("ProductSubcategory", newCategory);
context.AddBinding(product, "ProductSubcategory", newCategory);
}
context.UpdateObject(product);
context.SaveChanges();
}
public void AddProduct(Product product)
{
product.rowguid = Guid.NewGuid();
context.AddObject("Product", product);
context.AttachObject("ProductSubcategory", product.ProductSubcategory);
context.AddBinding(product, "ProductSubcategory", product.ProductSubcategory);
context.SaveChanges();
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AdventureWorksServiceProcessor awsProcessor = new AdventureWorksServiceProcessor();
comboBox1.DataSource = awsProcessor.GetCategories();
comboBox1.DisplayMember = "Name";
}
}
Now you can play around with different form variations and call out to the methods in the AdventureWorksServiceProcessor class. Also, you could take this class to a different type of .net application (Silverlight, Web Application, WPF) and as long as you bring the AdventureWorks.cs class along and set the correct references up, it should all work just the same.






