现在的位置: 首页 > 综合 > 正文

WCF一步一步往前爬(二)

2013年09月04日 ⁄ 综合 ⁄ 共 12501字 ⁄ 字号 评论关闭

第二步:

WCF宿主程序用哪种类型比较好? 主要的托管宿主包括,IIS,控制台程序,WPF,Windows Forms,NT Service,Windows服务,COM+作为宿主。IIS部署简单,可以向发布Web Service一样部署,但是仅仅支持HTML协议,而且宿主进程在客户请求时候启动。控制台作为宿主托管简单,一般做简单WCF 编程时候使用。Windows Forms宿主可以提供管理宿主状态的UI,操作更加直观。一般企业WCF宿主会采用Windows服务或者COM+,Windows服务可以长期运行在后台,支持所有的绑定协议,但是安装部署相对复杂。COM+,作为宿主,我们可以利用COM+组建的一些特性,例如对象池等。 
一般企业开发选择IIS,Windows服务,性能要求的时候可以考虑COM+,作为宿主。  个人学习IIS和控制台程序相对开发简单,配置便捷。

在这里我们实践一把WCF宿主方式:IIS中的WAS(net.tcp),自己写的wpf程序(http或net.tcp),windows服务(net.pipe)

 

IIS中的WAS(net.tcp)

1、确定Windows Process Activation Service在windows组件中已经安装。如图:

2、打开IIS对于已经在第一步发布到IIS中的ProductsService服务,点击“高级设置”在“已启用的协议”设置“http,net.tcp”。如图:

3、ProductsClient项目app.config.添加一个endpoint节点

<client>
<endpoint address="http://localhost/ProductsService/ProductsService.svc"
binding="basicHttpBinding"bindingConfiguration="BasicHttpBinding_IProductsService"
contract="ProductsService.IProductsService"name="BasicHttpBinding_IProductsService" />

<endpointaddress="net.tcp://localhost/ProductsService/ProductsService.svc"
binding="netTcpBinding"contract="ProductsService.IProductsService"
name="NetTcpBinding_IProductsService" />
</client>

IIS中WAS(net.tcp)中宿寄wcf服务就大功告成

 

wpf程序(http或net.tcp)

1、新建类库ProductsServiceLibrary,引入NBuilder.dll。分别添加tblProduct.cs,tblProductInventory.cs,IProductsService.cs和ProductsService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ProductsServiceLibrary
{
    /// <summary>
    ///tblProduct 的摘要说明
    /// </summary>
    public class tblProduct
    {
        public tblProduct()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }

        public int ProductID;

        public string Name;

        public string ProductNumber;

        /// <summary>
        /// 0 = 产品是购买的。1 = 产品是内部生产的。
        /// </summary>
        public bool MakeFlag;

        /// <summary>
        //0 = 产品不可销售。1 = 产品可销售。
        /// </summary>
        public bool FinishedGoodsFlag;

        public string Color;

        ////最小库存量。
        public int SafetyStockLevel;

        /// <summary>
        /// 触发采购订单或工作订单的库存水平。
        /// </summary>
        public int ReorderPoint;

        /// <summary>
        /// 产品的标准成本。
        /// </summary>
        public decimal StandardCost;

        /// <summary>
        /// 销售价格。
        /// </summary>
        public decimal ListPrice;

        /// <summary>
        /// 产品的规格。
        /// </summary>
        public string Size;

        /// <summary>
        /// Size 列的测量单位。
        /// </summary>
        public string SizeUnitMeasureCode;

        /// <summary>
        /// Weight 列的测量单位。
        /// </summary>
        public string WeightUnitMeasureCode;

        /// <summary>
        /// 产品的重量。
        /// </summary>
        public decimal Weight;

        /// <summary>
        /// 生产产品所需的天数。
        /// </summary>
        public int DaysToManufacture;

        /// <summary>
        /// R = 平地 M = 山地 T = 旅行 S = 标准
        /// </summary>
        public string ProductLine;

        /// <summary>
        /// H = 高 M = 中 L = 低
        /// </summary>
        public string Class;

        /// <summary>
        /// W = 女式 M = 男式 U = 通用
        /// </summary>
        public string Style;

        /// <summary>
        /// 产品所属的产品子类别。指向 ProductSubCategory.ProductSubCategoryID 的外键。
        /// </summary>
        public int ProductSubcategoryID;

        /// <summary>
        /// 产品所属的产品型号。指向 ProductModel.ProductModelID 的外键。
        /// </summary>
        public int ProductModelID;

        /// <summary>
        /// 产品开始销售的日期。
        /// </summary>
        public DateTime SellStartDate;

        /// <summary>
        /// 产品停止销售的日期。
        /// </summary>
        public DateTime SellEndDate;

        /// <summary>
        /// 产品停产的日期。
        /// </summary>
        public DateTime DiscontinuedDate;

        /// <summary>
        /// 行的上次更新日期和时间。
        /// </summary>
        public DateTime ModifiedDate;
    }
}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ProductsServiceLibrary
{
    /// <summary>
    ///ProductInventory 的摘要说明
    /// </summary>
    public class tblProductInventory
    {
        public tblProductInventory()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }

        /// <summary>
        /// 产品标识号。指向 Product.ProductID 的外键。
        /// </summary>
        public int ProductID;

        /// <summary>
        /// 库存位置标识号。指向 Location.LocationID 的外键。
        /// </summary>
        public int LocationID;

        /// <summary>
        /// 库存位置中的存储间。
        /// </summary>
        public string Shelf;

        /// <summary>
        /// 库存位置中架子上的存储容器。
        /// </summary>
        public int Bin;

        /// <summary>
        /// 库存位置中的产品数量。
        /// </summary>
        public int Quantity;

        /// <summary>
        /// 行的上次更新日期和时间。
        /// </summary>
        public DateTime ModifiedDate;
    }
}

 

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

namespace ProductsServiceLibrary
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService”。
    [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);
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using FizzWare.NBuilder;
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、服务和配置文件中的类名“Service”。
namespace ProductsServiceLibrary
{
    [DataContract]
    public class ProductData
    {
        [DataMember]
        public string Name;
        [DataMember]
        public string ProductNumber;
        [DataMember]
        public string Color;
        [DataMember]
        public decimal ListPrice;
    }

    public class ProductsServiceImpl : IProductsService
    {
        static IList<tblProduct> ps = Builder<tblProduct>.CreateListOfSize(50).Build();
        static IList<tblProductInventory> pis = Builder<tblProductInventory>.CreateListOfSize(50).Build();

        public List<string> ListProducts()
        {
            var p = ps.Select(item => item.ProductNumber).ToList();

            return p;
        }

        public ProductData GetProduct(string productNumber)
        {
          
            ProductData productData = null;
            tblProduct matchingProduct = ps.First(item => string.Compare(item.ProductNumber, productNumber) == 0);

            productData = new ProductData()
            {
                Name = matchingProduct.Name,
                ProductNumber = matchingProduct.ProductNumber,
                Color = matchingProduct.Color,
                ListPrice = matchingProduct.ListPrice
            };

            return productData;
        }

        public int CurrentStockLevel(string productNumber)
        {
            int stockLevel = 0;
          
          

         
            // Calculate the sum of all quantities for the specified product
            stockLevel = (from pi in pis
                          join p in ps
                          on pi.ProductID equals p.ProductID
                          where String.Compare(p.ProductNumber, productNumber) == 0
                          select (int)pi.Quantity).Sum();

            return stockLevel;
        }

        public bool ChangeStockLevel(string productNumber, short newStockLevel, string shelf, int bin)
        {
            //var pr = Builder<tblProduct>.CreateListOfSize(50).Build();
            //var pri = Builder<tblProductInventory>.CreateListOfSize(50).Build();
            int productID = (from p in ps
                             where String.Compare(p.ProductNumber, productNumber) == 0
                             select p.ProductID).First();
            // Find the ProductInventory object that matches the parameters passed
            // in to the operation
            tblProductInventory productInventory = pis.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

            return true;
        }
    }
}

 

2、新建WPF应用程序项目ProductsServiceHost,添加对ProductsServiceLibrary类库引用

MainWindow前台:

 <Grid>
        <Button Height="23" HorizontalAlignment="Left" Margin="51,60,0,0" Name="start" VerticalAlignment="Top" Width="75" Click="start_Click">Start</Button>
        <Button Height="23" HorizontalAlignment="Right" Margin="0,60,56,0" Name="stop" VerticalAlignment="Top" Width="75" IsEnabled="False" Click="stop_Click">Stop</Button>
        <Label Height="23" HorizontalAlignment="Left" Margin="43,0,0,111" Name="label1" VerticalAlignment="Bottom" Width="88">Service Status:</Label>
        <TextBox IsReadOnly="True" Margin="133,0,59,107" Name="status" Text="Service Stopped" Height="26" VerticalAlignment="Bottom"></TextBox>
    </Grid>

 

MainWindow后台:

ServiceHost productsServiceHost = null;
        private void start_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                productsServiceHost = new ServiceHost(typeof(ProductsServiceImpl));
                productsServiceHost.Open();
                stop.IsEnabled = true;
                start.IsEnabled = false;
                status.Text = "Service Running";
            }
            catch (Exception ex)
            {
                handleException(ex);
            }
        }

        private void handleException(Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

        private void stop_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                productsServiceHost.Close();
                stop.IsEnabled = false;
                start.IsEnabled = true;
                status.Text = "Service Stopped";
            }
            catch (Exception ex)
            {
                handleException(ex);
            }

        }

3、app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
      <services>
        <service name="ProductsServiceLibrary.ProductsServiceImpl">

          <endpoint address="net.tcp://localhost:8080/TcpService"
          binding="netTcpBinding"
          bindingConfiguration="" name="NetTcpBinding_IProductsService"
          contract="ProductsServiceLibrary.IProductsService" />

          <endpoint address="http://localhost:8000/ProductsService/Service.svc"
          binding="basicHttpBinding" name="BasicHttpBinding_IProductsService"
          contract="ProductsServiceLibrary.IProductsService" />

        </service>
      </services>
      <behaviors>
 
      </behaviors>
    </system.serviceModel>
</configuration>

 

注意这里面设置了两个endpoint,系统会对这两个地址启动wcf服务。客户端选择任何一个地址引入service都可以

<client>
   <endpoint address="net.tcp://localhost:8080/TcpService"
                binding="netTcpBinding" contract="ProductsService.IProductsService"
                name="NetTcpBinding_IProductsService" />

          <endpoint address="http://localhost:8000/ProductsService/Service.svc"
                binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IProductsService"
                contract="ProductsService.IProductsService"
                name="BasicHttpBinding_IProductsService" />

</client>

 

至于windows服务作为宿主

1、新建windows服务项目WindowsProductsService,添加ProductsServiceLibrary类库引用,将Service1.cs重命名ServiceHostController.cs

public partial class ServiceHostController : ServiceBase
    {
        private ServiceHost productsServiceHost;
        public ServiceHostController()
        {
            InitializeComponent();
            // The name of the service that appears in the Registry
            this.ServiceName = "ProductsService";
            // Allow an administrator to stop (and restart) the service
            this.CanStop = true;
            // Report Start and Stop events to the Windows event log
            this.AutoLog = true;
        }

        protected override void OnStart(string[] args)
        {
            productsServiceHost = new ServiceHost(typeof(ProductsServiceImpl));
            NetNamedPipeBinding binding = new NetNamedPipeBinding();
            productsServiceHost.AddServiceEndpoint(typeof(IProductsService),
            binding, "net.pipe://localhost/ProductsServicePipe");
            productsServiceHost.Open();
        }

        protected override void OnStop()
        {
            productsServiceHost.Close();
        }

 

2、在ServiceHostController.cs[设计],右键添加安装。点击serviceInstaller1,修改其属性ServiceName为ServiceHostController;点击serviceProcessInstaller1,修改Account

为LocalSystem。生成项目。

3、用管理员权限打开Visual Studio 命令提示。切到WindowsProductsService项目Debug文件夹下,运行installutil WindowsProductsService.exe。windows服务则安装完成

4、在前面的ProductsClient客户端配置文件中添加一个endpoint

        <endpoint address="net.pipe://localhost/ProductsServicePipe"
              binding="netNamedPipeBinding"
              contract="ProductsService.IProductsService"
              name="NetNamedPipeBinding_IProductsService" />

ok,这样就大功告成了。欣慰一下吧。

 

小提示:如果你想卸载windows服务,可以运行installutil /u WindowsProductsService.exe

抱歉!评论已关闭.