如何捕获/处理 WCF 中由于类型强制转换或在通过 postman 调用时将无效值传递给变量而发生的异常

How to catch/handle exceptions in WCF that occur due to type casting or passing invalid values to the variables while calling through postman

提问人:Sanam 提问时间:10/31/2019 最后编辑:Abraham QianSanam 更新时间:11/1/2019 访问量:1385

问:

我是 WCF 的初学者。在构建 RestFul API 时,我遇到了一些崩溃问题。

在我通过 WCF 处理异常的过程中,我从各种来源获得了帮助,如下所示:

WCF 异常处理策略 https://blogs.msdn.microsoft.com/pedram/2008/01/25/wcf-error-handling-and-some-best-practices/ https://riptutorial.com/csharp/example/5460/implementing-ierrorhandler-for-wcf-services

通过实现全局错误处理程序,应用程序的内部异常可以顺利处理(通过在 try catch clock 中处理它们)。但我不确定如何处理铸造异常。即,如果变量获得无效值,则导致应用程序崩溃的异常。

编辑:

我有一个以下 DataContract 类

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;

namespace StilaarAPI.DataContracts
{
    [DataContract]
    public class Products
    {

        [DataMember]
        [Required(ErrorMessage = "product Name is required")]
        [StringLength(50, MinimumLength = 5, ErrorMessage = "Address Feild length should be between 5 and 50")]
        public string ProductName { get; set; }

        [Required(ErrorMessage = "ProductID is requied")]
        [DataMember]
        public int ProductID { get; set; }



    }
    }


然后(启用 Ajax 的 WCF 服务使用上面的 DataContract 类作为输入参数)

[OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
    public string GetProduct(Products pro)
    {
        try
        {

            string test = "Every thing works fine :D";
            return test;

            //ResultDo<List<ProblemTypesDo>> result = new ResultDo<List<ProblemTypesDo>>();
            //var problemTypes = _riderOrderDeliveryBL.GetProblemType();


        }
        catch (NotFoundException ex)
        {
            NotFoundFault fault = new NotFoundFault();
            fault.Error = "Product Not Found";
            fault.StatusCode = HttpStatusCode.NotFound;

            throw new WebFaultException<NotFoundFault>(
                                       fault, HttpStatusCode.NotFound);
        }



    }

从邮递员调用上述服务只是给出流畅的简单结果:

enter image description here

这很好,现在如果我在输入变量上运行不同的输入场景: 从将 null 值设置为产品名称开始,它给了我以下结果enter image description here

不错,因为我的验证有效并且正在处理异常,所以我得到了上述结果。 现在进入下一个场景,如果我将 ID 设置为 null,则会出现以下输出:enter image description here

现在,我的问题是我能做些什么来防止应用程序像这样崩溃:

以下是我的 IError 处理程序类:

public class GlobalErrorBehaviorAttribute : Attribute, IServiceBehavior
{
    private readonly Type errorHandlerType;

    /// <summary>
    /// Dependency injection to dynamically inject error handler if we have multiple global error handlers
    /// </summary>
    /// <param name="errorHandlerType"></param>
    public GlobalErrorBehaviorAttribute(Type errorHandlerType)
    {
        this.errorHandlerType = errorHandlerType;
    }



    #region IServiceBehavior Members

    void IServiceBehavior.Validate(ServiceDescription description,
        ServiceHostBase serviceHostBase)
    {
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription description,
        ServiceHostBase serviceHostBase,
        Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
    {
    }

    /// <summary>
    /// Registering the instance of global error handler in dispatch behavior of the service
    /// </summary>
    /// <param name="description"></param>
    /// <param name="serviceHostBase"></param>
    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description,
        ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandler;

        try
        {
            errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
        }
        catch (MissingMethodException e)
        {
            throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must have a public empty constructor.", e);
        }
        catch (InvalidCastException e)
        {
            throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler.", e);
        }

        foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
            channelDispatcher.ErrorHandlers.Add(errorHandler);
        }
    }

    #endregion IServiceBehavior Members



}




 public class GlobalErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {

        return true;
    }

    public void ProvideFault(Exception error,System.ServiceModel.Channels.MessageVersion version,ref System.ServiceModel.Channels.Message fault)
    {

            //if (error is FaultException)
            //    return;

            var jsonError = new CustomFault
            {

                Error = "Something went wrong",
                Details = error.GetType().FullName

            };
            fault = Message.CreateMessage(version, "", jsonError,
                                          new DataContractJsonSerializer(typeof(CustomFault)));

            // Tell WCF to use JSON encoding rather than default XML
            var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

            // Modify response
            var rmp = new HttpResponseMessageProperty
            {
                StatusCode = HttpStatusCode.BadRequest,
                StatusDescription = "Bad Request",
            };
            rmp.Headers[HttpResponseHeader.ContentType] = "application/json";
            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);


    }
}



public class ExtendedWebHttpBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        // clear default erro handlers.
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();

        // add our own error handler.
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new GlobalErrorHandler());
        //BehaviorExtensionElement
    }
}

当我把断点放在提供错误时,它显示以下异常,好像是因为解析:enter image description here

我该如何处理它,以便我可以向客户端发送干净的错误消息

编辑: 邮递员一般例外:

 ?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">

    <head>
        <title>Request Error</title>
        <style>
            BODY {
                color: #000000;
                background-color: white;
                font-family: Verdana;
                margin-left: 0px;
                margin-top: 0px;
            }

            #content {
                margin-left: 30px;
                font-size: .70em;
                padding-bottom: 2em;
            }

            A:link {
                color: #336699;
                font-weight: bold;
                text-decoration: underline;
            }

            A:visited {
                color: #6699cc;
                font-weight: bold;
                text-decoration: underline;
            }

            A:active {
                color: #336699;
                font-weight: bold;
                text-decoration: underline;
            }

            .heading1 {
                background-color: #003366;
                border-bottom: #336699 6px solid;
                color: #ffffff;
                font-family: Tahoma;
                font-size: 26px;
                font-weight: normal;
                margin: 0em 0em 10px -20px;
                padding-bottom: 8px;
                padding-left: 30px;
                padding-top: 16px;
            }

            pre {
                font-size: small;
                background-color: #e5e5cc;
                padding: 5px;
                font-family: Courier New;
                margin-top: 0px;
                border: 1px #f0f0e0 solid;
                white-space: pre-wrap;
                white-space: -pre-wrap;
                word-wrap: break-word;
            }

            table {
                border-collapse: collapse;
                border-spacing: 0px;
                font-family: Verdana;
            }

            table th {
                border-right: 2px white solid;
                border-bottom: 2px white solid;
                font-weight: bold;
                background-color: #cecf9c;
            }

            table td {
                border-right: 2px white solid;
                border-bottom: 2px white solid;
                background-color: #e5e5cc;
            }
        </style>
    </head>

    <body>
        <div id="content">
            <p class="heading1">Request Error</p>
            <p xmlns="">The server encountered an error processing the request. Please see the <a rel="help-page"
                    href="https://localhost:44326/ServiceContracts/CustomerAccount.svc/help">service help page</a> for
                constructing valid requests to the service.</p>
        </div>
    </body>

    </html>

调试器异常:

不能将值 '' 分析为类型 'Int32'。{“格式化程序 在尝试反序列化消息时抛出异常:有 尝试反序列化参数 :p ro.这 InnerException 消息为“反序列化 StilaarAPI.DataContracts.Products 类型的对象。值 '' 不能 解析为类型“Int32”。有关详细信息,请参阅 InnerException 详细信息。

C# asp.net .NET WCF 异常

评论

0赞 André Sanson 10/31/2019
Wcf 主要用于 SOAP 通信,您可以创建 REST 方法,我建议在 Web API 中执行 RESTFUL。
1赞 Sanam 10/31/2019
让我们说它不是一种选择。由于某种原因,我坚持使用 WCF
0赞 Panagiotis Kanavos 10/31/2019
发布您的代码和异常文本,而不是它们的屏幕截图。该错误抱怨该字段被定义为 int,而传递的值是空字符串。班级在哪里,领域在哪里?addressaddress
0赞 Sanam 10/31/2019
@PanagiotisKanavos请看编辑,谢谢
0赞 Panagiotis Kanavos 10/31/2019
发布代码和异常文本,而不是代码和文本的屏幕截图。屏幕截图无法复制和编译。无法用谷歌搜索错误消息的屏幕截图

答:

0赞 Abraham Qian 10/31/2019 #1

请求正文未以本地 JSON 格式进行身份验证。它不满足 JSON 架构,这意味着请求尚未到达服务器,因此服务器不会根据 IErrorHandler 接口对其进行处理。
它应该像下面的形式一样,以便请求可以到达服务器。

{"Id":null,"Name":"Apple"}

如果有什么我可以帮忙的,请随时告诉我。
更新。
不要干扰 IErrorhandler 接口中的序列化过程,请考虑使用以下代码来处理错误。

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            MyError myerror = new MyError()
            {
                Details = error.Message,
                Error = "Hello"
            };
            fault = Message.CreateMessage(version, "messsagefault", myerror);
        }

或者,我们可以直接发送错误详细信息。

FaultException faultException = new FaultException(error.Message);
            MessageFault messageFault = faultException.CreateMessageFault();            
            fault = Message.CreateMessage(version, messageFault, error.Message);

此外,我们可以处理 IClientMessageFormatter/IDispatcherMessageFormatter 中消息的序列化。
https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/custom-message-formatters

评论

0赞 Sanam 10/31/2019
如何对其进行身份验证?我确实使用了这样的数据注释: [DataMember] [Required(ErrorMessage = “Address type is required”)] public int ProductID { get; set; } 但是当调用 int 的属性时,它没有任何帮助。另一方面,字符串 valkiadtions 工作得很好。
0赞 Panagiotis Kanavos 10/31/2019
@Saman错误没有说明身份验证。它抱怨这是一个 int,但发布的值是一个空字符串。Address
0赞 Abraham Qian 11/1/2019
看来我有一个错误,请求可以到达 IErrorhandler 接口。但我可以通过上面的代码处理所有错误。希望它对你有用。
0赞 Sanam 11/1/2019
@AbrahamQian仍在:(
0赞 Abraham Qian 11/4/2019
@Sanam 在我这边,可以使用 ProvideFault 函数中的代码段正确处理错误。i.stack.imgur.com/GOonD.png