系統之間的數據交互往往需要事先定義一些契約,在WCF中我們需要先編寫XSD文件,然后通過自動代碼生成工具自動生成C#對象。對于剛剛接觸契約的人來說,掌握xmlSpy之類的軟件之后確實比手寫XML效率要高,但還是有些學習成本的。此外XML的tag太多,如果設計的類型屬性過多,手寫XSD也不太現實,很難專注于設計。
于是我想能不能先用C#寫好類型,然后自動生成標準格式的XSD呢。經過三天左右的設計和實現,目前實現了以下功能:
1. 支持Class和Enum類型的設計
2. 支持基元類型、自定義類型、泛型列表、自定義類型數組等屬性
3. 支持自定義類型之間的依賴關系
4. 支持契約分組(指定Request/Response分到同一個xsd文件)
5. 支持契約匯總(對于自定義類型,最終體現在一個匯總xsd文件中,并自動引用其它xsd文件)
開源地址:https://github.com/CreateChen/XsdGen。我剛接觸SOA不久,目前只添加了xsd的minOccurs、maxOccurs等基本屬性,對于其它屬性并沒有全部集成進去,集成方式也非常簡單,在Attribute中添加相應的屬性,并在XsdBuilder.cs中添加相應的處理。
先看一下實現的效果,例如我定義了以下類型:FoodOrderRequest、FoodOrderResponse、PayType
using System;using System.Collections.Generic;using XsdAttribute;[assembly: XsdSchema(    TargetNamespace = "http://xx.com/framework/soa/sample/v1",    XmlNamespace = "http://xx.com/framework/soa/sample/v1",    Namespace = "http://xx.com/framework/soa/sample/v1",    Common = "http://xx.com/common/types/v1")][assembly: XsdImport(Id = "SOACommonTypes",    Namespace = "http://xx.com/common/types/v1",    SchemaLocation = "SOACommonTypes_V1.0.0.xsd")]namespace TestDLL{    [XsdComplexType(Annotation = "訂餐申請", FileGroup = "FoodOrder")]    public class FoodOrderRequest    {        [XsdElement(MinOccurs = "1", Annotation = "餐館編號")]        public int RestaurantId { get; set; }        [XsdElement(MinOccurs = "1", Annotation = "餐館名稱")]        public string RestaurantName { get; set; }        [XsdElement(Annotation = "訂餐日期")]        public DateTime OrderDate { get; set; }        [XsdElement(MinOccurs = "0", MaxOccurs = "unbounded", Annotation = "食品編號")]        public List<int> FoodId { get; set; }        [XsdElement(MinOccurs = "1", Annotation = "業務類型")]        public PayType BusinessType { get; set; }    }    [XsdComplexType(Annotation = "訂餐結果", FileGroup = "FoodOrder")]    public class FoodOrderResponse    {        [XsdElement(MinOccurs = "1", Annotation = "訂單編號")]        public int OrderId { get; set; }        [XsdElement(Annotation = "預計送達時間")]        public DateTime DeliveryTime { get; set; }    }    [XsdSimpleType(Annotation = "付款類型", FileGroup = "PayType")]    public enum PayType    {        現金,        支付寶,        微信,        網銀    }}工具自動為我生成了3個文件:
<?xml version="1.0" encoding="utf-8"?><xs:schema id="FoodOrder" targetNamespace="http://xx.com/framework/soa/sample/v1" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xx.com/framework/soa/sample/v1" xmlns:ns="http://xx.com/framework/soa/sample/v1" xmlns:common="http://xx.com/common/types/v1"> <xs:include schemaLocation="PayType.xsd" /> <xs:import id="SOACommonTypes" schemaLocation="SOACommonTypes_V1.0.0.xsd" namespace="http://xx.com/common/types/v1" /> <xs:complexType name="FoodOrderRequestType"> <xs:annotation> <xs:documentation>訂餐申請</xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="RestaurantId" type="xs:int" minOccurs="1"> <xs:annotation> <xs:documentation>餐館編號</xs:documentation> </xs:annotation> </xs:element> <xs:element name="RestaurantName" type="xs:string" minOccurs="1"> <xs:annotation> <xs:documentation>餐館名稱</xs:documentation> </xs:annotation> </xs:element> <xs:element name="OrderDate" type="xs:dateTime"> <xs:annotation> <xs:documentation>訂餐日期</xs:documentation> </xs:annotation> </xs:element> <xs:element name="FoodId" type="xs:int" minOccurs="0" maxOccurs="unbounded"> <xs:annotation> <xs:documentation>食品編號</xs:documentation> </xs:annotation> </xs:element> <xs:element name="BusinessType" type="PayType" minOccurs="1"> <xs:annotation> <xs:documentation>業務類型</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="FoodOrderResponseType"> <xs:annotation> <xs:documentation>訂餐結果</xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="OrderId" type="xs:int" minOccurs="1"> <xs:annotation> <xs:documentation>訂單編號</xs:documentation> </xs:annotation> </xs:element> <xs:element name="DeliveryTime" type="xs:dateTime"> <xs:annotation> <xs:documentation>預計送達時間</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType></xs:schema>
<?xml version="1.0" encoding="utf-8"?><xs:schema id="PayType" targetNamespace="http://xx.com/framework/soa/sample/v1" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xx.com/framework/soa/sample/v1" xmlns:ns="http://xx.com/framework/soa/sample/v1" xmlns:common="http://xx.com/common/types/v1"> <xs:import id="SOACommonTypes" schemaLocation="SOACommonTypes_V1.0.0.xsd" namespace="http://xx.com/common/types/v1" /> <xs:simpleType name="PayType" final="restriction"> <xs:restriction base="xs:string"> <xs:enumeration value="現金" /> <xs:enumeration value="支付寶" /> <xs:enumeration value="微信" /> <xs:enumeration value="網銀" /> </xs:restriction> </xs:simpleType></xs:schema>
<?xml version="1.0" encoding="utf-8"?><xs:schema id="TestDLL" targetNamespace="http://xx.com/framework/soa/sample/v1" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xx.com/framework/soa/sample/v1" xmlns:ns="http://xx.com/framework/soa/sample/v1" xmlns:common="http://xx.com/common/types/v1"> <xs:import id="SOACommonTypes" schemaLocation="SOACommonTypes_V1.0.0.xsd" namespace="http://xx.com/common/types/v1" /> <xs:include schemaLocation="FoodOrder.xsd" /> <xs:include schemaLocation="PayType.xsd" /> <xs:element name="FoodOrderRequest" nillable="true" type="ns:FoodOrderRequestType" /> <xs:element name="FoodOrderResponse" nillable="true" type="ns:FoodOrderResponseType" /></xs:schema>
[AttributeUsage(AttributeTargets.Assembly)]public class XsdSchema : Attribute{    public string TargetNamespace { get; set; }    public string XmlNamespace { get; set; }    public string Namespace { get; set; }    public string Common { get; set; }    //匯總dll中的類型,生成總的xsd    PRivate string _packageId;    /// <summary>    /// 生成XSD的文件名稱    /// </summary>    public string PackageId    {        get { return _packageId; }        set        {            //去除文件名中非法字符            var regex = new Regex(@"/:|/;|//|//|/||/,|/*|/?|/""|/<|/>");            _packageId = regex.Replace(value, "");        }    }    public static XsdSchema Get(Assembly assembly)    {        return (XsdSchema) GetCustomAttribute(assembly, typeof (XsdSchema));    }}前幾個是一些命名空間的定義,可以根據自己公司的業務規則進行設計。默認情況下,匯總文件的targetId、文件名稱以及生成的文件夾名稱都是PackageId決定,如果dll沒有指定該值,默認則是dll的Name。
除了定義Schema,每個xsd文件中可能還需要導入一些默認的公共類型,在這種情況下,可以為assembly添加如下Attribute:
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]public class XsdImport : Attribute{ public string Id { get; set; } public string SchemaLocation { get; set; } public string Namespace { get; set; } public static IEnumerable<XsdImport> Get(Assembly assembly) { var attributes = GetCustomAttributes(assembly, typeof (XsdImport)); return attributes.Cast<XsdImport>(); }}
[AttributeUsage((Attribut
新聞熱點
疑難解答