一步一步学Linq to sql(十):多层架构MVC WCF Linq
前言
本次主要是使用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(); } } }
示例代码下载地址https://files.cnblogs.com/aehyok/MVCLinqWCF.rar