一.最近在使用Wcf創建數據服務,但是在和EF框架搭建數據訪問時遇到了許多問題
下面是目前整理的基本框架代碼,經供參考使用,源代碼地址:http://git.oschina.net/tiama3798/Wcf_EFDemo
說明:框架搭建中使用EF訪問數據庫,簡單工廠模式組織代碼
WCFThree.Entity:簡單工廠模式的實體層、EF的實體模板、WCF的數據契約
WCFThree.Abstract:簡單工廠模式的抽象接口層、WCF服務操作契約
WCFThree.Factory:簡單工廠模式的實現層、WCF服務器契約實現
WCFThree.Proxy:WCF的客戶端代理封裝
WCFThree.Service:WCF的服務端定義
WCFThree.Test:測試程序
部分代碼說明:
1.為了使客戶端和服務端使用相同的代理類,EF框架中禁用動態代理類實例,同時延遲加載也失效
public BaseContext() : base("name=BaseContext") { //在Wcf中禁用EF的代理類和延遲加載 this.Configuration.ProxyCreationEnabled = false; }
2.為了解決序列化的循環引用問題,顯示指定數據契約以及對應的屬性,這樣還有一個好處就是從服務端向客戶端數據輸出可以帶着關聯表數據(因為沒法延遲加載,所以在服務器端需要再查詢一次關聯表數據)
[Table("student")] [DataContract(IsReference = true)] public partial class student { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public student() { scores = new HashSet<score>(); } [Key] [StringLength(3)] [DataMember] public string sno { get; set; } [Required] [StringLength(100)] [DataMember] public string sname { get; set; } [StringLength(2)] [DataMember] public string ssex { get; set; } public DateTime? sbirthday { get; set; } [Column("class")] [StringLength(5)] [DataMember] public string _class { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] [DataMember] public virtual ICollection<score> scores { get; set; } }
3.客戶端代理使用BasicHttpBinding創建
public class RemoteServiceFactory { private string GetUrl(string Operate) { return string.Format("http://localhost:8733/Design_Time_Addresses/WCFThree.Service/{0}/", Operate); } /// <summary> /// 獲取學生操作 /// </summary> /// <returns></returns> public IStudent GetStudent() { string url = GetUrl("Student"); return CreateService<IStudent>(url); } public IScore GetScore() { return CreateService<IScore>(GetUrl("Score")); } public IUserInfo GetUserInfo() { return CreateService<IUserInfo>(GetUrl("UserInfo")); } private T CreateService<T>(string url) { var binding = new BasicHttpBinding(); binding.MaxReceivedMessageSize = maxReceivedMessageSize; binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas(); binding.ReaderQuotas.MaxStringContentLength = maxReceivedMessageSize; binding.ReaderQuotas.MaxArrayLength = maxReceivedMessageSize; binding.ReaderQuotas.MaxBytesPerRead = maxReceivedMessageSize; ChannelFactory<T> chan = new ChannelFactory<T>(binding, new EndpointAddress(url)); //異常處理注冊 //cha.Endpoint.EndpointBehaviors.Add(); foreach (var op in chan.Endpoint.Contract.Operations) { var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior; // 獲取或設置對象圖中要序列化或反序列化的最大項數。 if (dataContractBehavior != null) dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue; } chan.Open(); return chan.CreateChannel(); } private const int maxReceivedMessageSize = 2147483647; }
4.測試及結果說明
RemoteServiceFactory _remote = new RemoteServiceFactory(); IStudent _IStudent = _remote.GetStudent(); ////1.添加學生 WCFThree.Entity.student stu1 = new Entity.student() { sno = "110", sname = "李四", ssex = "男", sbirthday = DateTime.Now, _class = "95033" }; _IStudent.Add(stu1); ////2.獲取列表 List<WCFThree.Entity.student> stuList = _IStudent.GetList(); foreach (var item in stuList) { //編號-姓名---學習的課程數量(獲取關聯表數據失效) Console.WriteLine(string.Format("{0}-{1}--{2}", item.sno, item.sname, item.scores.Count)); } //3.獲取指定對象及關聯數據----方式1:獨立請求 WCFThree.Entity.student stu2 = _IStudent.GetModel("101"); Console.WriteLine(stu2.sname); IScore _IScore = _remote.GetScore(); List<WCFThree.Entity.score> scoreList = _IScore.GetList_Stu(stu2.sno); foreach (var item in scoreList) { Console.WriteLine(string.Format("{0}-{1}", item.sno, item.degree)); } //獲取關聯表數據方式2 WCFThree.Entity.student stu3 = _IStudent.GetModel_Related("101"); Console.WriteLine(stu3.sname); Console.WriteLine(stu3.scores.Count); Console.WriteLine(stu3.scores.First().degree);
二.其他參考實例:
http://www.cnblogs.com/guozili/archive/2012/09/03/2667429.html