3

【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据

 3 years ago
source link: https://www.cnblogs.com/tcjiaan/p/5577037.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据

有时候,为了让数据可以“跨国经营”,尤其是HTTP Web有关的东东,会将数据内容以 XML 或 JSON 的格式返回,这样一来,不管客户端平台是四大文明古国,还是处于蒙昧时代的原始部落,都可以使用这些数据。

在WCF中实现将数据以XML或JSON格式返回有Y多种方法,不管你用什么方法,只要得到预期结果就好,米芾说了,笔可以八面出锋,当然了,人家指的是绘画。

这里,老周就挑两种方法来演示,仅供参考,没有考古价值,建议司马子长不要把本文收入《史记》。

第一种方法是用到 WebServiceHost 类,它可以自动完成一些与HTTP通信相关的配置,不过,使用该类,要以管理身份运行,不然,会无权限监听。

首先定义一个 Book 类,稍后咱们会把一个Book实例以XML或JSON数据返回。

    public sealed class Book
    {
        public string BookName { get; set; }
        public decimal Price { get; set; }

        public string BarCode { get; set; }
    }

然后,很重要一步,就是声明服务协定,它是个接口,可以对客户端公开,当然客户端也可以重新定义。

    [ServiceContract]
    interface IService
    {
        [OperationContract]
        [WebGet(UriTemplate = "getdata?f={format}")]
        Message GetXml(string format);
    }

加上ServiceContract特性表明它是服务协定,如果没有明确指定Name,则它的名字与接口的名字相同;协定接口中,希望向客户端公开的方法要加上OperationContract特性,否则不会被认为是服务操作,无法被客户端使用。

服务协定接口允许在服务器和客户端使用不同定义,只要协定的名称相同,并且方法的参数和返回值类型和数目相同即可。

WebGet特性指定URI的使用方法,地址为相对路径,假如基址是http://dog.net/,那么访问GetXml方法的路径为 http://dog.net/getdata?f=xml。本来我只想返回XML数据的,所以叫GetXml,后来一想,单返回XML格式的内容也太小气了,索性弄一个参数,来指定格式,可以传入xml或json。?f后面的{format}会自动把值传给方法的format参数,所以,UriTemplate的参数名字不要写错,如果写成 ?f={firmat},那就识别不了参数了。

然后要实现服务,实现协定接口的类型不必向客户端公开,因为它是在服务器上执行的。

    public class MyService : IService
    {
        public Message GetXml(string format)
        {
            WebOperationContext context = WebOperationContext.Current;

            Book b = new Book
            {
                BookName = "卖女孩的小火柴",
                Price = 25.2M,
                BarCode = "2811365801"
            };

            Message msgreturn = null;
            // 判断格式
            if (format.ToLower() == "xml")
            {
                msgreturn = context.CreateXmlResponse<Book>(b);
            }
            else
            {
                msgreturn = context.CreateJsonResponse<Book>(b);
            }

            return msgreturn;
        }
    }

这里通过一个很好玩的方法来完成,所以方法返回类型为Message。静态属性WebOperationContext.Current可以得到与当前调用的操作协定关联的上下文对象,即WebOperationContext实例。它公开了一堆方法,名字都是 CreateXXXResponse,其中XXX是啥取决于返回内容,要返回JSON,就调用CreateJsonResponse方法,返回XML就调用CreateXmlResponse方法。

实例化Book对象后,可以传给带泛型参数的CreateJsonResponse或CreateXmlResponse方法,把类型参数T指定为Book,就会自动把Book对象序列化,然后返回给客户端。

最后,在配置文件中给服务设定一个基址,可以在代码中写,也可以在配置文件中写,此处老周选用配置文件,好处是可以动态修改而不必重新编译应用程序。

  <system.serviceModel>
    <services>
      <service name="getXmlSample.MyService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1888/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>

可能有初学的朋友说WCF的配置文件很难写,其实啊,是有规律的,你不妨细心研究一下,掌握规律后你会发现配置文件并不难写。

service的 name 属性的值就是服务类的Type的名字(类型名,带命名空间名称)。

在Main中实例化WebServiceHost。

        static void Main(string[] args)
        {
            WebServiceHost host = new WebServiceHost(typeof(MyService));

            host.Open();
            Console.WriteLine("服务已打开。");
            Console.Read();
            host.Close();
        }

注意,传给构造函数的Type是服务类的类型,与配置文件中service/name的值相同。

以管理员身份运行这个例子,然后打开浏览器,输入http://localhost:1888/getdata?f=xml,回车后,你会看到这样的内容:

把xml改为json,再看看。

怎么样,好玩吧。下面老周再演示另一种方法。

这种方法没使用WebServiceHost,而是使用普通的ServiceHost类来承载服务,可通过WebHttpBinding来得到HTTP交互的支持,不过,不要忘了给终结点配置WebHttpBehavior行为。

同样,先定义一个类,随后用来做测试。

    [DataContract(Namespace = "http://sample",Name = "student")]
    public sealed class Student
    {
        [DataMember(Name = "stu_id")]
        public int StuID { get; set; }

        [DataMember(Name = "stu_name")]
        public string StuName { get; set; }
    }

这一次,咱们通过将对象进行XML或JSON序列化的方式生成数据,并转为字符串返回。服务协定如下:

    [ServiceContract]
    public interface IData
    {
        [OperationContract]
        [WebGet(UriTemplate = "getdata?f={format}")]
        string GetData(string format);
    }

和前面差不多,只是返回类型改为string。

下面代码实现协定接口:

    public class MyService : IData
    {
        public string GetData(string format)
        {
            string res = null;
            Student stu = new Student
            {
                StuID = 3, StuName = "小白"
            };
            using (MemoryStream ms=new MemoryStream())
            {
                XmlObjectSerializer sz = null;
                if (format != null && format.ToLower() == "xml")
                {
                    sz = new DataContractSerializer(stu.GetType());
                }
                else
                {
                    sz = new DataContractJsonSerializer(stu.GetType());

                }
                sz.WriteObject(ms, stu);
                res = Encoding.UTF8.GetString( ms.ToArray());
            }
            return res;
        }
    }

接着,在配置文件中配置一下。

  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="hb">
          <webHttp automaticFormatSelectionEnabled="true"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="getXmlSample2.MyService">
        <endpoint address="http://localhost:2008" binding="webHttpBinding" contract="getXmlSample2.IData" behaviorConfiguration="hb"/>
      </service>
    </services>
  </system.serviceModel>

behaviors节点下可以配置两种行为——服务行为和终结点行为。此处我们只需配置终结点的行为,需要一个webHttp元素,它映射到 WebHttpBehavior 类。记得要为behavior节点分配名字,随后在/services/service/endpoint节点下,才能通过behaviorConfiguration属性来引用前面的behavior。

实现HTTP交互,应使用webHttpBinding。

在配置webHttp行为时,应该把automaticFormatSelectionEnabled的值设置为true,这样一来,返回给调用方的内容会自动识别格式,其实主要目的是让返回的字符串中能够去掉最外层的双引号。

回到代码,实例化ServiceHost,然后打开服务。

        static void Main(string[] args)
        {
            using (ServiceHost host=new ServiceHost(typeof(MyService)))
            {
                host.Open();
                Console.WriteLine("服务已打开。");
                Console.Read();
            }
        }

运行应用程序,在浏览中输入http://localhost:2008/getdata?f=xml,得到结果如下。

然后再输入http://localhost:2008/getdata?f=json看看。

好了,就演示这两种方法吧,你愿意探索的话,方法是有很多种的。

示例源代码下载地址


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK