zoukankan      html  css  js  c++  java
  • 【.net 深呼吸】聊聊WCF服务返回XML或JSON格式数据

    【.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看看。

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

    示例源代码下载地址

  • 相关阅读:
    hdu 3714
    sql 函数 DATEADD 使用
    mvc的IIS 配置问题 runAllManagedModulesForAllRequests 与 HtmlFileHandler
    移动端日历控件 mobiscroll 的简单使用、参数设置
    sql中判断是否存在某个对象
    SQLServer中的变量:局部变量,全局变量
    键盘对照表
    [PyQt]在Windows系统中安装Eric6
    [Python]使用QRCode生成彩色二维码
    [PyQt]PyQt5连接SQL Server数据库,并读取所有数据库名称
  • 原文地址:https://www.cnblogs.com/grj001/p/12223784.html
Copyright © 2011-2022 走看看