表現層的設計(一)——常用的模式、Json與DTO


上幾篇博文介紹了 業務邏輯層和數據訪問層,我認為寫博文的作用主要是向業界的讀者交流一種思想,點到為止,至於學習架構設計,通過幾篇博文是講不清楚的,還需要【基礎】扎實的情況下,【反復】研究【權威】的書籍。

你會發現我寫隨筆的特點就是喜歡單一,講NHibernate就絕不會把easyui參合進來,而這次要談得json也不會和MVC有什么關系。

而實戰當中,你會發現我確實可以將他們分開,在需要的時候重新組合各種類庫和框架來達到我的目的。

 

表現層(Presentation Layer)

它主要由兩部分組成:

1.界面UI

2.表現層邏輯

 

界面UI在.NET中包括的幾種形式:WEB(ASP.NET)、WPF、WinForm、Mobile

而表現層邏輯通常需要用后台代碼做一些事情。

理論上我們應該盡量解除兩者之間的依賴,以便於UI更容易切換。

 

關於表現層的一些誤區

1. 覺得拖控件比較低端

由於許多培訓學校在解說JAVA和.NET的區別的時候,通常會講一個能拖控件而一個不能,不能拖控件需要程序員自己寫更加高端。

而事實上“拖控件”有個學名的,叫 快速應用程序開發(Rapid Application Development,RAD)。

樓主從學生年代VB/Delphi/C++都是控件拖過來的,到現在也不會覺得它低端,它一種戰術。

實際上在傳統的ASP.NET中也可以使用MVP模式來做到分離關注點,高不高端,取決於寫程序的人,而不在於用什么工具。

就好像昔年兵器譜排名第三的小李飛刀,他的飛刀也只不過是大治的鐵匠花了三個時辰打造而成的。

 

2.關於json的誤區

很多人認為json只有在Web開發中有效,甚至認為Easyui+ASP.NET MVC3中間通過json傳輸數據是唯一的情況。

而事實上我們可以用它作為跨平台的傳輸格式,WCF正是利用了這一點。

所以對象序列化json的時候,可能ASP.NET MVC3並不是必須的。

設計類庫時應該避開對其他框架的依賴。

 

3.MVC就是ASP.NET MVC x

實際上MVC只是一個模式,而微軟對它進行了改進,設計出了ASP.NET MVC框架。

MVC也只不過是WEB應用程序才使用的一種模式,夠作為架構設計師,可能需要了解更多。

另外MVC還延伸出幾種模式,分別是MVP模式、PM模式。

 

表現層常用的模式

1.web中

使用傳統的ASP.NET,可以適當使用MVP模式分離關注點;

或者使用ASP.NET MVC框架;

 

2.windows中

使用winForm同樣是適當使用MVP模式;

使用WPF可以考慮MVVM模式;

 

3.移植的考慮

如果你希望你的winForm程序可以移植到Linux換成GTK的話,MVP模式也許是唯一的選擇了。

 

json與DTO的想法

關於Json:ASP.NET MVC框架只能用於WEB應用程序,而json則可以更廣泛地應用,所以json序列化的類庫與框架的依賴並不是很好的設計。

在winform的項目中,這樣的類庫拿過來顯然就編譯不能通過了。

關於DTO:DTO,數據傳輸對象。理論上在表示層得到數據時應該是DTO,在服務層已經將DataTable/ORM的Model轉化成DTO。但實際上這是一個很大的工作量,實際上可能直接使用ORM的Model傳輸給表現層。

另外服務器端與瀏覽器傳輸數據是使用ViewModel,它可以是直接使用ORM的model,也可以是DTO,當然,更復雜的情況是在View需要的數據模型與DTO或者數據庫模型不匹配時將組織DTO或者Model根據View需要的屬性建立一個ViewModel。

所以我們設計Json序列化類的時候需要考慮幾個問題:

1.我們接受的要序列化對象可能是DTO,也可能是ORM的領域模型,而領域模型經常會出現循環依賴,延遲加載。直接用微軟自帶的序列化類庫報錯,而使用MVC框架來指定要序列化的屬性那么如果不能使用MVC框架又該怎么辦?

2.服務器向客戶端傳輸數據的性能考慮,則不應該傳輸多余的數據。Json序列化時該如何排除不需要的屬性?

3.如果是老系統使用.NET,沒有微軟自帶的Json序列化類庫,使用第三方類庫。

 

給出簡單的解決方案

這里使用了Newtonsoft.Json,並對前人類庫進行一些整理,忽略對象循環依賴,能夠支持移除不需要的屬性。

        [Test]
        public void XLH()
        {
            DictionaryRepository rep = new DictionaryRepository();
            Dictionary dic = rep.GetByCodeLazy("bianma1", "code1");
            string json = Util.Json.Json.Serializer(new { dic ,total=3}, new string[] { "Category" });
            Console.WriteLine(json);
        }

        [Test]
        public void FXLH()
        {
            string json="{\"Index\":1.0,\"Description\":\"描述1\",\"Id\":\"160954d1-5e73-4ac8-a426-197f5bd616f9\",\"Name\":\"字段1\",\"Code\":\"code1\"}";
            Dictionary dc=Util.Json.Json.DeSerializer<Dictionary>(json, null);
        }
序列化與反序列化

下面兩個類可以直接使用。

using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using System.IO;


namespace Util.Json
{
    public class Json
    {
        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="settings"></param>
        /// <returns></returns>
        public static string Serializer(object obj, JsonSerializerSettings settings)
        {
            JsonSerializer scriptSerializer = JsonSerializer.Create(settings);
            StringWriter sw = new StringWriter();
            scriptSerializer.Serialize(sw, obj);
            string str = sw.ToString();
            sw.Close();
            return str;
        }

        /// <summary>
        /// 序列化(忽略對象循環依賴,忽略空值)
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string Serializer(object obj)
        {
            JsonSerializerSettings Settings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore,
                DateTimeZoneHandling = DateTimeZoneHandling.Local
            };
            return Serializer(obj, Settings);
        }

        /// <summary>
        /// 序列化(忽略對象循環依賴,忽略空值,排除指定列)
        /// </summary>
        /// <param name="obj">序列化目標對象</param>
        /// <param name="lstExclude">要排除的屬性名列表</param>
        /// <returns></returns>
        public static string Serializer(object obj,string[] lstExclude)
        {
            ExcludePropertiesContractResolver exclude = new ExcludePropertiesContractResolver(lstExclude);

            JsonSerializerSettings Settings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore,
                DateTimeZoneHandling = DateTimeZoneHandling.Local,
                ContractResolver = exclude
            };
            return Serializer(obj, Settings);
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <param name="Settings"></param>
        /// <returns></returns>
        public static T DeSerializer<T>(string str, JsonSerializerSettings Settings)
        {
            JsonSerializer scriptSerializer = JsonSerializer.Create(Settings);
            JsonTextReader sr = new JsonTextReader(new StringReader(str));
            T obj = scriptSerializer.Deserialize<T>(sr);
            sr.Close();
            return obj;
        }

    }
}
類庫1
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;

namespace Util.Json
{
    /// <summary>
    /// 重寫創建屬性列表函數,使之支持排除指定屬性
    /// </summary>
    public class ExcludePropertiesContractResolver : DefaultContractResolver
    {
        string[] lstExclude;

        public ExcludePropertiesContractResolver(string[] excludedProperties)
        {
            lstExclude = excludedProperties;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {

            IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);

            foreach (string item in lstExclude)
            {
                JsonProperty temp = null;
                foreach (JsonProperty jp in list)
                {
                    if (jp.PropertyName == item)
                    {
                        temp = jp;
                    }
                }
                if (temp != null)
                {
                    list.Remove(temp);
                }
            }
            return list;
        }
    }
}
類庫2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM