欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解析Silverlight调用WCF/Rest异常的解决方法

程序员文章站 2023-12-17 12:58:52
新建rest服务接口:复制代码 代码如下:[servicecontract]public interface iservice1{    [o...

新建rest服务接口:

复制代码 代码如下:

[servicecontract]
public interface iservice1
{
    [operationcontract]
    string getdata(int value);
}

接着新建一个服务实现类:
复制代码 代码如下:

public class service1 : iservice1
{
    public string getdata(int value)
    {
        int i = 0;
        int j = 5 / i;
        return string.format("you entered: {0}", value);
    }
}

在这里让service1 抛出”divided by zero exception:”
复制代码 代码如下:

<system.servicemodel>
    <behaviors>
      <servicebehaviors>
        <behavior name="servicebehavior">
          <servicedebug includeexceptiondetailinfaults="true" />
          <servicemetadata httpgetenabled="true" />
        </behavior>
      </servicebehaviors>
    </behaviors>
    <services>
      <service behaviorconfiguration="servicebehavior" name="wcfservice1.service1">
      </service>
    </services>
  </system.servicemodel>

在这里注意<servicedebug includeexceptiondetailinfaults="true" />

在silverlight 客户端添加服务引用,名称为:servicereference1.

在页面上添加一个按钮,按钮的click事件代码如下:

复制代码 代码如下:

private void button_click(object sender, routedeventargs e)
{
     service1client client = new servicereference1.service1client();

     client.getdatacompleted += new eventhandler<getdatacompletedeventargs>(client_getdatacompleted);
     client.getdataasync(35); //try getdata
}

void client_getdatacompleted(object sender, servicereference1.getdatacompletedeventargs e)
{
}


运行,结果如下:

解析Silverlight调用WCF/Rest异常的解决方法

可以看到实际的异常是“尝试除以0”,但是由于浏览器限制,所有的异常都是notfound。

在msdn上有两种方法可以解决这个问题,

最简单的就是在app.xaml.cs代码里面使用registerprefix来使用备用客户端 http 堆栈

复制代码 代码如下:

public app()
        {
            bool bregisterprefix = webrequest.registerprefix(http://localhost:9541/,

webrequestcreator.clienthttp);
            //other code
        }


再次运行代码:解析Silverlight调用WCF/Rest异常的解决方法

这是sl调用wcf服务如何处理异常的方式,那么调用rest服务呢?

首先要修改web.config 节点下的servicemodel以让它支持rest。

复制代码 代码如下:

 <system.servicemodel>

    <behaviors>

      <endpointbehaviors>
        <behavior name="endpointbehavior">
          <webhttp helpenabled="true" defaultoutgoingresponseformat="json"
          faultexceptionenabled="true" />
        </behavior>
      </endpointbehaviors>

      <servicebehaviors>
        <behavior name="servicebehavior">
          <servicedebug includeexceptiondetailinfaults="true" />
          <servicemetadata httpgetenabled="true" />
        </behavior>
      </servicebehaviors>

    </behaviors>

    <services>
      <service behaviorconfiguration="servicebehavior" name="wcfservice1.service1">
        <endpoint behaviorconfiguration="endpointbehavior" binding="webhttpbinding"
        bindingconfiguration="" name="rest" contract="wcfservice1.iservice1" />
      </service>
    </services>

  </system.servicemodel>

在这里要设置webhttp 节点的faultexceptionenabled=true.并且设置servicedebug 的includeexceptiondetailinfaults 为true。

ok,服务的web.config文件已经配置完毕了,接下来要为getdata方法添加webget特性修饰了。

复制代码 代码如下:

public class service1 : iservice1
        {
            [webget()]
            public string getdata(int value)
            {
                int i = 0;
                int j = 5 / i;

                return string.format("you entered: {0}", value);
            }
        }

运行:

地址为:http://localhost:9541/service1.svc/help

解析Silverlight调用WCF/Rest异常的解决方法

接着输入地址:http://localhost:9541/service1.svc/getdata?value=3

解析Silverlight调用WCF/Rest异常的解决方法

可以看到得到了异常信息了。

注意:别忘记了添加跨域和授权文件:crossdomain.xml 和 clientaccesspolicy.xml 到网站根目录。

同样,修改sl客户端页面,添加一个button,button的代码事件为:

复制代码 代码如下:

private void btnrest_click(object sender, routedeventargs e)
        {
            webclient wc = new webclient();

            wc.downloadstringcompleted += new downloadstringcompletedeventhandler(

wc_downloadstringcompleted);
            wc.downloadstringasync(new uri("http://localhost:9541/service1.svc/getdata?value=3"));
        }

        void wc_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
        {
            if (e.error != null)
            {
                throw e.error;
            }
        }

运行,点击btnrest

解析Silverlight调用WCF/Rest异常的解决方法

可以看到,rest 调用的结果仍然是notfound。

提示让我们查看response属性和status属性。

就看看respone属性的responsestrem是什么吧。

解析Silverlight调用WCF/Rest异常的解决方法

可以看到errormessage 就是返回的错误,很明显,我们需要对它反序列化成exception的对象。

首先尝试使用datacontractserializer来反序列化为faultexception类

解析Silverlight调用WCF/Rest异常的解决方法

因为我们尝试反序列化为faultexception类,但是xml数据的element名称为fault。所以失败,难道是有fault类 ?可是找了很久也没发现fault类。

但是在readobject方法中发现了一个verifyobjectname的重载。

将代码修改为:

复制代码 代码如下:

datacontractserializer serializer = new datacontractserializer(
typeof(faultexception));

//object deserializerobject = serializer.readobject(errorstream);
object deserializerobject = serializer.readobject(xmlreader.create(errorstream),false);

重新运行:

解析Silverlight调用WCF/Rest异常的解决方法

可以发现虽然序列化是成功的,但是序列化后的值全部是错误的。

最后没办法既然有xml的异常数据,那么可以尝试解析xml数据并使用自定义异常。

首先新建slfaultexception 类,继承exception:代码如下:

复制代码 代码如下:

public class slfaultexception : exception
        {
            public exceptiondetail detail { get; set; }

            public slfaultexception() { }
            public slfaultexception(string message) : base(message) { }
            public slfaultexception(string message, exceptiondetail detail)
                : base(message)
            {
                detail = detail;
            }
        }


完整的代码如下:
复制代码 代码如下:

void wc_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
        {
            if (e.error != null)
            {
                if (e.error is webexception)
                {
                    webresponse errorresponse = ((webexception)e.error).response;

                    stream errorstream = errorresponse.getresponsestream();

                    xelement rootelement = xelement.load(errorstream);
                    xelement detailelement = rootelement
                    .descendants()
                    .first(el => el.name.localname == "exceptiondetail");

                    datacontractserializer serializer = new datacontractserializer(
                    typeof(exceptiondetail));
                    exceptiondetail exceptiondetail = (exceptiondetail)serializer.readobject(

detailelement.createreader(), true);

                    slfaultexception faultexception = new slfaultexception(

exceptiondetail.message, exceptiondetail);

                    throw faultexception;
                }
            }
        }


虽然序列化为faultexception是失败的,但是xml节点的exceptiondetail是可以被反序列回来的,当然上面的处理webexception的过程是可以被封装的,读者自己尝试下吧,呵呵。

结果如下图:

解析Silverlight调用WCF/Rest异常的解决方法

上一篇:

下一篇: