前言
本次主要是使用WCF的多层架构。我们将建立以下项目:
A,MVC网站项目 MvcOperation:留言簿表现层
B,类库项目 Contract:定义数据访问服务的契约
C,类库项目 Service:定义数据访问服务
D,类库项目Entity:留言簿实体
E,控制台项目Host:承载数据访问服务
项目之间的引用如下:
A引用B和D;
B引用D和System.ServiceModel程序集
C引用B、D、System.ServiceModel以及System.Data.Linq程序集
D引用System.Data.Linq程序集
E引用C和System.ServiceModel程序集
生成映射文件和实体
打开VS2010命令行提示,执行以下命令:
sqlmetal /conn:server=.;database=GuestBook;uid=sa;pwd=saa /map:c:\guestbook.map /code:c:\guestbook.cs /serialization:Unidirectional
注意到,这里我们使用了serialization开关,告知sqlmetal在生成实体的时候自动把它们标记为WCF数据对象。生成结束后把C:\GUESTBOOK.CS添加到Entity项目中。
这是数据库的表设计 ,一定不要忘记设置主键了哦。
数据访问服务契约
首先我们可以定义出留言簿数据访问服务的契约(接口),把如下的代码保存为IDataAccess.cs放在Contract类库项目中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Contract
{
[ServiceContract]
public interface IDataAccess
{
/// <summary>
/// 添加 or 修改
/// </summary>
/// <param name="gb"></param>
[OperationContract]
void SendMessage(TbGuestBook gb);
/// <summary>
/// 获取所有信息
/// </summary>
/// <returns></returns>
[OperationContract]
List<TbGuestBook> GetData();
/// <summary>
/// 删除
/// </summary>
/// <param name="ID"></param>
[OperationContract]
void DeleteMessage(string ID);
/// <summary>
/// 获取一条记录
/// </summary>
/// <param name="ID"></param>
/// <returns></returns>
[OperationContract]
TbGuestBook GetDataID(string ID);
}
}
然后,我们来实现这个契约,把如下代码保存为DataAccess.cs放在Service类库项目中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Contract;
using System.Data.Linq.Mapping;
using System.IO;
using System.ServiceModel;
namespace Service
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class DataAccess : IDataAccess
{
GuestBook ctx;
public DataAccess()
{
XmlMappingSource xms = XmlMappingSource.FromXml(File.ReadAllText("c:\\GuestBook.map"));
ctx = new GuestBook("server=.;database=GuestBook;uid=sa;pwd=saa", xms);
ctx.Log = Console.Out;
}
public void SendMessage(TbGuestBook gb)
{
TbGuestBook tb =null;
tb = GetDataID(gb.ID.ToString());
if (tb != null)
{
tb.Message = gb.Message;
tb.Reply = gb.Reply;
tb.PostTime = gb.PostTime;
tb.UserName = gb.UserName;
ctx.SubmitChanges();
}
else
{
ctx.TbGuestBook.InsertOnSubmit(gb);
ctx.SubmitChanges();
}
}
public List<TbGuestBook> GetData()
{
var query = from gb in ctx.TbGuestBook orderby gb.PostTime descending select gb;
return query.ToList();
}
public void DeleteMessage(string ID)
{
TbGuestBook gb = ctx.TbGuestBook.Single(message => message.ID == new Guid(ID));
ctx.TbGuestBook.DeleteOnSubmit(gb);
ctx.SubmitChanges();
}
public TbGuestBook GetDataID(string ID)
{
TbGuestBook record = ctx.TbGuestBook.SingleOrDefault(message => message.ID.ToString() ==ID);
return record;
}
}
}
WCF服务端与客户端
打开Host项目中的Program.cs,使用下面的代码来实现WCF的服务端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Service;
using System.ServiceModel;
using Contract;
namespace Host
{
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("net.tcp://localhost:880/DataAccessService");
using (ServiceHost sh = new ServiceHost(typeof(DataAccess), uri))
{
NetTcpBinding ctb = new NetTcpBinding();
sh.AddServiceEndpoint(typeof(IDataAccess), ctb, string.Empty);
sh.Opened += delegate { Console.WriteLine("服务已经启动"); };
sh.Open();
Console.ReadLine();
}
}
}
}
在MvcOption项目中添加一个Helper文件夹下创建一个用户调用服务的类,ServerHelper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Description;
using System.ServiceModel;
using Contract;
namespace MvcOperation.Helper
{
public class ServerHelper
{
public static IDataAccess GetDataAccessService()
{
ServiceEndpoint sep = new ServiceEndpoint(ContractDescription.GetContract(typeof(IDataAccess)),
new NetTcpBinding(),
new EndpointAddress("net.tcp://localhost:880/DataAccessService"));
ChannelFactory<IDataAccess> cf = new ChannelFactory<IDataAccess>(sep);
return cf.CreateChannel();
}
}
}
最后对控制器中的代码进行修正如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Configuration;
using System.IO;
using MvcOperation.Helper;
namespace MvcOperation.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "欢迎使用 ASP.NET MVC!";
//List<tbGuestBook> list = (from gb in ctx.tbGuestBook
// orderby gb.PostTime descending
// select gb).ToList();
return View("Index", ServerHelper.GetDataAccessService().GetData());
}
public ActionResult About()
{
return View();
}
public ActionResult AddBook()
{
return View();
}
public ActionResult DelBook(string id)
{
//tbGuestBook gb = ctx.tbGuestBook.Single(b => b.ID == new Guid(id));
//ctx.tbGuestBook.DeleteOnSubmit(gb);
//ctx.SubmitChanges();
ServerHelper.GetDataAccessService().DeleteMessage(id);
return Index();
}
public ActionResult UpdateBook(string id)
{
TbGuestBook gb = ServerHelper.GetDataAccessService().GetDataID(id);
return View("AddBook",gb);
}
public ActionResult SaveBook(TbGuestBook tb)
{
TbGuestBook gb = null;
if (tb.ID.ToString() != "00000000-0000-0000-0000-000000000000")
{
gb = ServerHelper.GetDataAccessService().GetDataID(tb.ID.ToString());
gb.PostTime = DateTime.Now;
gb.UserName = tb.UserName;
gb.Message = tb.Message;
ServerHelper.GetDataAccessService().SendMessage(gb);
return Index();
}
else
{
tb.ID = Guid.NewGuid();
tb.IsReplied = false;
tb.PostTime = DateTime.Now;
ServerHelper.GetDataAccessService().SendMessage(tb);
}
return Index();
}
}
}