前言

本次主要是使用WCF的多层架构。我们将建立以下项目:

一步一步学Linq to sql(十):多层架构MVC WCF Linq_Linq To Sql

 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项目中。

一步一步学Linq to sql(十):多层架构MVC WCF Linq_程序集_02

这是数据库的表设计 ,一定不要忘记设置主键了哦。

数据访问服务契约

首先我们可以定义出留言簿数据访问服务的契约(接口),把如下的代码保存为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();
}
}
}