[WCF Step by Step 读书笔记] Chapter01 WCF 介绍

下面通过搭建一个书中完整的WCF的例子阐述WCF:

1. 建立一个ASP.NET WebSite的的空工程ProductService。

2. 添加一个Class Library的工程,删除其.cs文件,添加一个ADO.NET Entity Model,从数据库选择AdventureWorks数据库,用到的两张表为Product和ProductInventory。其余使用默认值。

3. 在ProductService工程里添加对第二步Class Library的引用。

4. 在ProductService空工程里添加WCF Service项。这个时候,我们会发现项目里多了一个App_Code文件夹,里面存放着IService.cs和Service.cs两个文件,同时多出了一个Service.svc的文件。

image

5. 将IService.cs和Service重命名为IProductService和ProductService。

6. IProductService的内容为:

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

namespace Products
{
    //  Data contract describing the details of a product passed to client applications
    [DataContract]
    public class ProductData
    {
        [DataMember]
        public string Name;

        [DataMember]
        public string ProductNumber;

        [DataMember]
        public string Color;

        [DataMember]
        public decimal ListPrice;
    }

    //  Service contract describing the operations provided by the WCF service
    [ServiceContract]
    public interface IProductsService
    {
        // Get the product number of every product
        [OperationContract]
        List<string> ListProducts();

        // Get the details of a single product
        [OperationContract]
        ProductData GetProduct(string productNumber);

        // Get the current stock level for a product
        [OperationContract]
        int CurrentStockLevel(string productNumber);

        // Change the stock level for a product
        [OperationContract]
        bool ChangeStockLevel(string productNumber, short newStockLevel, string shelf, int bin);
    }
}

这里对WCF Service可以提供的方法和数据类型进行了定义。WCF的runtime在收到相应的请求的Message以后,可以将其中内容传递给这些标注了[OperationContract]的方法,而返回操作时,也可以将结果通过runtime打包到message里返回。

[ServiceContract]表明这是这个类是用来提供WCF的Runtime需要运行的类。而[OperationContract]则是这个Runtime所能执行到方法。这两个Attribute都位于System.ServiceModel名空间里面。

而[DataContract]和[DataMember]用于对需要在Host和Client之间进行传递的数据对象的类型进行定义。他们位于System.Runtime.Serialization名空间里面。可见DataContract修饰的是Class,而DataMember修饰的是Field。

7. ProductService的内容是:

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

using System.Data.Entity;
using ProductsEntityModel;

namespace Products
{
    // WCF service that implements the service contract
    // This implementation performs minimal error checking and exception handling
    public class ProductsServiceImpl : IProductsService
    {
        public List<string> ListProducts()
        {
            // Create a list for holding product numbers
            List<string> productsList = new List<string>();

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Fetch the product number of every product in the database
                    var products = from product in database.Products
                                   select product.ProductNumber;

                    productsList = products.ToList();
                }
            }
            catch
            {
                // Ignore exceptions in this implementation
            }

            // Return the list of product numbers
            return productsList;
        }

        public ProductData GetProduct(string productNumber)
        {
            // Create a reference to a ProductData object
            // This object will be instantiated if a matching product is found
            ProductData productData = null;

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Find the first product that matches the specified product number
                    Product matchingProduct = database.Products.First(
                        p => String.Compare(p.ProductNumber, productNumber) == 0);

                    productData = new ProductData()
                    {
                        Name = matchingProduct.Name,
                        ProductNumber = matchingProduct.ProductNumber,
                        Color = matchingProduct.Color,
                        ListPrice = matchingProduct.ListPrice
                    };
                }
            }
            catch
            {
                // Ignore exceptions in this implementation
            }

            // Return the product
            return productData;
        }

        public int CurrentStockLevel(string productNumber)
        {
            // Obtain the total stock level for the specified product.
            // The stock level is calculated by summing the quantity of the product
            // available in all the bins in the ProductInventory table.

            // The Product and ProductInventory tables are joined over the
            // ProductID column.

            int stockLevel = 0;

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Calculate the sum of all quantities for the specified product
                    stockLevel = (from pi in database.ProductInventories
                                  join p in database.Products
                                  on pi.ProductID equals p.ProductID
                                  where String.Compare(p.ProductNumber, productNumber) == 0
                                  select (int)pi.Quantity).Sum();
                }
            }
            catch
            {
                // Ignore exceptions in this implementation
            }

            // Return the stock level
            return stockLevel;
        }

        public bool ChangeStockLevel(string productNumber, short newStockLevel,
                             string shelf, int bin)
        {
            // Modify the current stock level of the selected product
            // in the ProductInventory table.
            // If the update is successful then return true, otherwise return false.

            // The Product and ProductInventory tables are joined over the
            // ProductID column.

            try
            {
                // Connect to the AdventureWorks database by using the Entity Framework
                using (AdventureWorksEntities database = new AdventureWorksEntities())
                {
                    // Find the ProductID for the specified product
                    int productID =
                        (from p in database.Products
                         where String.Compare(p.ProductNumber, productNumber) == 0
                         select p.ProductID).First();

                    // Find the ProductInventory object that matches the parameters passed
                    // in to the operation
                    ProductInventory productInventory = database.ProductInventories.First(
                        pi => String.Compare(pi.Shelf, shelf) == 0 &&
                              pi.Bin == bin &&
                              pi.ProductID == productID);

                    // Update the stock level for the ProductInventory object
                    productInventory.Quantity += newStockLevel;

                    // Save the change back to the database
                    database.SaveChanges();
                }
            }
            catch
            {
                // If an exception occurs, return false to indicate failure
                return false;
            }

            // Return true to indicate success
            return true;
        }
    }
}

这里是对IProductServic定义的方法的具体实现。

8. 在Service.svc里面将其内容改为:

<%@ ServiceHost Language="C#" Debug="true" Service="Products.ProductsServiceImpl" CodeBehind="~/App_Code/ProductsService.cs" %>

注意这里ServiceHost表明IIS将作为这个WCF的Runtime,提供的Service的具体内容是实现了Product.ProductServiceImpl这个类型,而这个类的代码在ProductsService.cs这个文件里面。

9. 在网站的web.config的配置文件里添加connectionString(这里的ConnectionString实际上可以直接从ClassLibrary工程的App.config直接拷贝过来):

<connectionStrings>
    <add name="AdventureWorksEntities" connectionString="metadata=res://*/ProductsModel.csdl|res://*/ProductsModel.ssdl|res://*/ProductsModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\SQLExpress;Initial Catalog=AdventureWorks;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

</connectionStrings>
注意这里metadata可能会发生链接错误的情况,这时候可以直接将其值改为metadata=res://*/,这样所有的assembly都会成为考虑对象。

10. 右键点击Service.svc运行,将浏览器出现的地址添加到WcfTestClient中,查看WCF提供的相应方法能否运行。

注意如果Visual Studio内的WCF能够运行,但是在IIS上部署以后从数据库得不到数据,注意查看应用程序池的Identity,查看其权限是否足够。

posted on 2011-02-17 21:43  李志鹏  阅读(453)  评论(0)    收藏  举报

导航