轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-02 11:59:39.000|閱讀 886 次
概述:Tiny Library使用應(yīng)用服務(wù)層向用戶界面層提供服務(wù),具體實(shí)現(xiàn)是采用Microsoft WCF Services。在Tiny Library的解決方案中,是由TinyLibrary.Services項(xiàng)目為整個(gè)系統(tǒng)提供這一WCF服務(wù)的。按照傳統(tǒng)的應(yīng)用系統(tǒng)分層方法,TinyLibrary.Services項(xiàng)目位于領(lǐng)域模型層之上、用戶界面層之下,它是UI與Domain的交互界面。TinyLibrary.Services的實(shí)現(xiàn)中,與DDD相關(guān)的內(nèi)容主要是數(shù)據(jù)傳輸對(duì)象(DTO),至于如何編寫與實(shí)現(xiàn)WCF服務(wù),那是.NET技術(shù)上的問(wèn)題,本文不會(huì)做太多的討論。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Tiny Library使用應(yīng)用服務(wù)層向用戶界面層提供服務(wù),具體實(shí)現(xiàn)是采用Microsoft WCF Services。在Tiny Library的解決方案中,是由TinyLibrary.Services項(xiàng)目為整個(gè)系統(tǒng)提供這一WCF服務(wù)的。按照傳統(tǒng)的應(yīng)用系統(tǒng)分層方法,TinyLibrary.Services項(xiàng)目位于領(lǐng)域模型層之上、用戶界面層之下,它是UI與Domain的交互界面。TinyLibrary.Services的實(shí)現(xiàn)中,與DDD相關(guān)的內(nèi)容主要是數(shù)據(jù)傳輸對(duì)象(DTO),至于如何編寫與實(shí)現(xiàn)WCF服務(wù),那是.NET技術(shù)上的問(wèn)題,本文不會(huì)做太多的討論。
數(shù)據(jù)傳輸對(duì)象(Data Transferring Object,DTO)
在TinyLibrary.Services中,有一種特殊類型的對(duì)象,我們稱之為數(shù)據(jù)傳輸對(duì)象。根據(jù)Fowler在PoEAA一書中的描述,DTO用于進(jìn)程間數(shù)據(jù)交換,由于DTO是一種對(duì)象,它能夠包含很多數(shù)據(jù)信息,因此,DTO的采用可以有效減少進(jìn)程間數(shù)據(jù)交換的來(lái)回次數(shù),從而在一定程度上提高網(wǎng)絡(luò)傳輸效率。
由于DTO需要跨越進(jìn)程邊界(在我們的案例中,需要跨越網(wǎng)絡(luò)邊界),因此,DTO是可以被序列化/反序列化的,它不能包含上下文相關(guān)的信息(比如,Windows句柄)。正因?yàn)槿绱耍珼TO中的數(shù)據(jù)類型都是很簡(jiǎn)單的,它們可以是原始數(shù)據(jù)類型(Primitive Data Types)或者是其它的DTO。
有些朋友在閱讀Fowler的PoEAA一書時(shí),對(duì)于DTO的理解還是有困難,我在此將我的理解寫下來(lái),供大家參考
在Tiny Library案例中,我選用了WCF的Data Contracts作為DTO的實(shí)現(xiàn)標(biāo)準(zhǔn),因?yàn)檫@樣做不僅能夠基于客戶端需求設(shè)計(jì)合理的DTO結(jié)構(gòu),而且還可以利用WCF的DataContractSerializer實(shí)現(xiàn)DTO的序列化/反序列化。不僅如此,WCF為我們?cè)诜?wù)器與客戶機(jī)通訊上提供了技術(shù)支持和有力保障。
打開(kāi)TinyLibrary.Services項(xiàng)目,我們可以看到一個(gè)IDataObject的泛型接口,其定義如下:
public interface IDataObject<TEntity> where TEntity : IEntity
{
void FromEntity(TEntity entity);
TEntity ToEntity();
}
我們可以要求所有的DTO都實(shí)現(xiàn)這個(gè)接口,以便使其具有將實(shí)體轉(zhuǎn)換為DTO,或者將DTO轉(zhuǎn)換為實(shí)體的能力。在Tiny Library案例中,我并沒(méi)有強(qiáng)制要求所有的DTO都實(shí)現(xiàn)這個(gè)接口(也就是說(shuō),Tiny Library本身不規(guī)定DTO必須實(shí)現(xiàn)這個(gè)接口),我引入這個(gè)接口的目的,就是想說(shuō)明,其實(shí)我們是可以這樣做的:在我們的系統(tǒng)中為DTO設(shè)計(jì)好一個(gè)合理的框架,以便讓DTO獲得更強(qiáng)大的功能。引入這個(gè)接口的另一個(gè)目的就是為了編程方便:實(shí)現(xiàn)基于某個(gè)實(shí)體的DTO,只需要使其實(shí)現(xiàn)IDataObject接口即可,Visual Studio會(huì)自動(dòng)產(chǎn)生方法樁(Method Stubs),無(wú)需手動(dòng)編寫代碼。
請(qǐng)注意TinyLibrary.Services.DataObjects.RegistrationData這個(gè)類,它與BookData、ReaderData有很大的區(qū)別,它并不是Registration實(shí)體的映射體現(xiàn),換句話說(shuō),它所包含的所有狀態(tài)屬性,并不是與Registration實(shí)體所包含的屬性一一對(duì)應(yīng)。例如,RegistrationData這個(gè)DTO中包含書名(BookTitle)以及ISBN號(hào)(BookISBN)的信息,而這些信息都是來(lái)自于Registration的關(guān)聯(lián)實(shí)體:Book。RegistrationData的設(shè)計(jì)完全是為了迎合用戶界面,因?yàn)樵赨I上,我們需要針對(duì)某個(gè)讀者列出他/她的借書信息,而RegistrationData包含了這所有需要的信息。
應(yīng)用層職責(zé)
在《Entity Framework之領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)實(shí)踐》系列文章中,我曾經(jīng)提到過(guò),根據(jù)DDD,應(yīng)用系統(tǒng)分為四層:展現(xiàn)層、應(yīng)用層、領(lǐng)域?qū)雍突A(chǔ)結(jié)構(gòu)層。在Tiny Library案例中,TinyLibrary.Services充當(dāng)了應(yīng)用層的職責(zé),它不負(fù)責(zé)處理任何業(yè)務(wù)邏輯,而是從更高的層面,為業(yè)務(wù)邏輯的正確執(zhí)行提供適當(dāng)?shù)倪\(yùn)行環(huán)境,同時(shí)起到任務(wù)協(xié)調(diào)的作用(比如事務(wù)處理和基礎(chǔ)結(jié)構(gòu)層服務(wù)調(diào)用)。
public void Return(string readerUserName, Guid bookId)
{
try
{
using (IRepositoryTransactionContext ctx = ObjectContainer
.Instance
.GetService<IRepositoryTransactionContext>())
{
IRepository<Book> bookRepository = ctx.GetRepository<Book>();
IRepository<Reader> readerRepository = ctx.GetRepository<Reader>();
Reader reader = readerRepository.Find(Specification<Reader>.Eval(r => r.UserName.Equals(readerUserName)));
Book book = bookRepository.GetByKey(bookId);
reader.Return(book);
ctx.Commit();
}
}
catch
{
throw;
}
}
上面的代碼展示了“還書”操作的具體實(shí)現(xiàn)方式,我們可以看到,位于應(yīng)用層的WCF Services僅僅是協(xié)調(diào)倉(cāng)儲(chǔ)操作和事務(wù)處理,業(yè)務(wù)邏輯由reader.Return方法實(shí)現(xiàn):
public void Return(Book book)
{
if (!book.Lent)
throw new InvalidOperationException("The book has not been lent.");
var q = from r in this.Registrations
where r.Book.Id.Equals(book.Id) &&
r.RegistrationStatus == RegistrationStatus.Normal
select r;
if (q.Count() > 0)
{
var reg = q.First();
if (reg.Expired)
{
// TODO: Reader should pay for the expiration.
}
reg.ReturnDate = DateTime.Now;
reg.RegistrationStatus = RegistrationStatus.Returned;
book.Lent = false;
}
else
throw new InvalidOperationException(string.Format("Reader {0} didn't borrow this book.",
this.Name));
}
配置文件
TinyLibrary.Services是整個(gè)案例的服務(wù)供應(yīng)者(Service Provider),因此,整個(gè)系統(tǒng)服務(wù)器端的配置與初始化應(yīng)該由TinyLibrary.Services啟動(dòng)時(shí)負(fù)責(zé)執(zhí)行。因此,基于服務(wù)器的系統(tǒng)配置應(yīng)該寫在TinyLibrary.Services項(xiàng)目的app.config中。其中包括:Apworks的配置、Unity(或者Castle Windsor)的配置、WCF Services的配置以及Entity Framework所使用的數(shù)據(jù)庫(kù)連接字符串的設(shè)置。
從實(shí)踐角度考慮,在基于CQRS體系結(jié)構(gòu)模式的應(yīng)用系統(tǒng)中,各個(gè)組件的初始化和配置邏輯應(yīng)該位于WCF Services的Global.asax文件中,以便在WCF Service Application啟動(dòng)的時(shí)候,所有組件都能成功地初始化。我將在今后的CQRS案例中進(jìn)一步描述這一點(diǎn)。
至此,Tiny Library的服務(wù)端部分基本介紹完畢,回顧一下,這些內(nèi)容包括:領(lǐng)域建模、倉(cāng)儲(chǔ)實(shí)現(xiàn)和應(yīng)用服務(wù)層。下一講將簡(jiǎn)單介紹一下Tiny Library的Web界面的設(shè)計(jì)與開(kāi)發(fā)。由于本系列文章的重點(diǎn)不是討論某個(gè)技術(shù)的具體實(shí)現(xiàn),因此,在下一講中不會(huì)涉及太多有關(guān)ASP.NET MVC的細(xì)節(jié)內(nèi)容。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載