WCF服务向客户端抛出自定义异常

时间:2017-09-29 15:31:23

标签: c# wcf

我试图将自定义异常从WCF服务抛出到客户端应用程序。我将尝试描述尽可能多的代码,因为我认为可以与此相关。

例外:

using System.Runtime.Serialization;

namespace App.Exceptions
{
    /// <summary>
    /// General App exception
    /// </summary>
    [DataContract]
    public class AppException : System.Exception
    {
        private string strMessage = "An unknown exception occurred";

        /// <summary>
        /// Creates a new instance of a App Exception
        /// </summary>
        public AppException()
        { }

        /// <summary>
        /// Creates a new instance of a App Exception
        /// </summary>
        /// <param name="Message">Message to send as exception</param>
        public AppException(string Message)
        { strMessage = Message; }

        public override string Message
        { get { return strMessage; } }
    }
}

服务代码:

(...)
using App.Exceptions;

namespace App.Services
{
    public class Service1 : IService1
    {
        public Service1 () 
        { }

        public void TestFunction() 
        {
            throw new AppException();
        }
    }
}

serviceInterface等:

(...)

namespace App.Services.Interfaces
{
    [ServiceContract]
    public interface IService1
    {   
        [OperationContract]
        void TestFunction();
    }
}

客户端:

(...)
using App.Exceptions;
(...)

try 
{
    service.TestFunction();
}
catch (AppException ex) 
{

}

一切运行良好,在服务上调用函数并抛出异常。客户端和服务器上的引用完全相同。我已经在同一个名字上引用了AppException,所以它应该没问题。

我已经尝试过服务app.config来设置<serviceDebug includeExceptionDetailInFaults="True" />并将其设置为False只是为了看看我是否得到了不同的例外情况,事实上它是不同的所以我是&#39; m没有真正理解为什么AppException的捕获点上设置的断点从未被击中。

修改

服务配置:

  <service name="App.Services.Service1">
    <endpoint address="" binding="basicHttpBinding" contract="App.Services.Interfaces.IService1">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:8733/Design_Time_Addresses/App.Services/Service1/" />
      </baseAddresses>
    </host>
  </service>

客户端配置:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IService1" />
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:8733/Design_Time_Addresses/App.Services/Service1/"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
            contract="Services.IService1" name="BasicHttpBinding_IService1" />
    </client>
</system.serviceModel>

1 个答案:

答案 0 :(得分:0)

由于安全性和互操作性的原因,您不能将任何未处理的异常或.net或任何类似的异常从服务器抛出到客户端(如果客户端想要知道激活),默认情况下这些异常不会传播到客户端wcf服务。

WCF不是传播异常,而是将它们序列化为SOAP错误并将SOAP错误发送到客户端。因此,您需要在SOAP错误中包含此自定义异常。

首先让servicecontract知道哪个操作可以抛出哪些SOAP错误。

namespace App.Services.Interfaces
{
    [ServiceContract]
    public interface IService1
    {   
        [FaultContract(typeOf(AppException))]
        [OperationContract]
        void TestFunction();
    }
}


using System.ServiceModel;
public class Service1 : IService1
    {
        public Service1 () 
        { }

        public void TestFunction() 
        {
            try
            {
             service.TestFunction();
            }
            catch(Exception ex)
             {
               AppException app=new AppException();
               app.strMessage =ex.Message;
               throw new FaultExcpetion<AppException>(app);
             }
        }
    }

此外,您可以获得故障详细信息以及故障错误。在客户端捕获上述异常。

//client side

     try
                {
                  //call wcf service contract.
                }
                catch (FaultException<ServiceReference.AppException> ex)
                {

                   label.Text=ex.Detail.strMessage ;
                }

另一种方法是使用自定义WCF IErrorHandler实现。请参阅此https://stackoverflow.com/a/8764782/6086968以便集中处理异常。

Edit1:需要为元数据正确配置app.config。

    <service name="App.Services.Service1" behaviorConfiguration="mexendpoint">
        <endpoint address="" binding="basicHttpBinding" contract="App.Services.Interfaces.IService1">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/Design_Time_Addresses/App.Services/Service1/" />
          </baseAddresses>
        </host>
      </service>
<behaviors>
  <serviceBehaviors>  
    <behavior name="mexendpoint">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
     </serviceBehaviors>
</behaviors>
</system.serviceModel>