gpt4 book ai didi

当 WCF 方法抛出异常时,jQuery 成功回调以空响应调用

转载 作者:行者123 更新时间:2023-12-03 21:58:50 25 4
gpt4 key购买 nike

我正在把我的头发扯下来,所以请耐心等待(这是一篇很长的帖子)。

基础信息

  • ASP.NET 3.5 与 WCF 服务在 ASP.NET 兼容模式下
  • 将 jQuery 与 this service proxy 一起使用用于 AJAX 请求
  • 定制 IErrorHandlerIServiceBehavior捕获异常并提供错误的实现,这些错误被序列化为 JSON
  • 我正在使用 Cassini 进行本地测试(我已经看到一些讨论在本地调试时发生但在生产环境中工作正常的问题的线程)。

  • 我遇到的问题是,每当我的 WCF 服务抛出异常时, 成功 $.ajax 的处理程序调用被触发。响应为空,状态文本为“成功”,响应代码为 202/Accepted。
    IErrorHandler实现确实得到了使用,因为我可以逐步完成并观察 FaultMessage 的创建。最后发生的是 success回调会抛出错误,因为当它需要一个 JSON 字符串时,响应文本是空的。 error回调永远不会触发。

    提供一点洞察力的一件事是删除 enableWebScript来自端点行为的选项。当我这样做时,发生了两件事:
  • 响应不再被包装(即没有 { d: "result" } ,只有 "result" )。
  • error回调被触发,但响应只是来自 IIS 的 400/Bad Request 蓝屏死机的 HTML,而不是我的序列化错误。

  • 关于关键字“jquery ajax asp.net wcf faultcontract json”的随机组合,我已经尝试了与 Google 的前 10 个或更多结果中显示的一样多的东西,所以如果您打算在谷歌上搜索答案,请不要打扰.我希望 SO 上的某个人以前遇到过这个问题。

    最终我想要实现的是:
  • 能够抛出任何类型的Exception在 WCF 方法中
  • 使用 FaultContact
  • ShipmentServiceErrorHandler 中捕获异常
  • 返回一个序列化的 ShipmentServiceFault (作为 JSON)到客户端。
  • error调用回调以便我可以处理项目 4。

  • 可能与以下有关:
  • WCF IErrorHandler Extension not returning specified Fault


  • 更新 1

    我检查了跟踪 System.ServiceModel 事件的输出,在调用 UpdateCountry 方法后,有一次抛出异常,消息为

    Server returned an invalid SOAP Fault.



    就是这样。一个内部异常提示序列化器期望不同的根元素,但我无法从中破译很多其他内容。

    更新 2

    因此,随着更多的困惑,我得到了一些工作,尽管不是我认为理想的方式。这是我所做的:
  • 删除了 <enableWebScript /> web.config 的端点行为部分中的选项。
  • 删除了 FaultContract来自服务方法的属性。
  • 实现了 WebHttpBehavior 的子类(称为 ShipmentServiceWebHttpBehavior )并覆盖 AddServerErrorHandlers添加 ShipmentServiceErrorHandler 的函数.
  • 更改了 ShipmentServiceErrorHandlerElement返回类型为 ShipmentServiceWebHttpBehavior 的实例而不是错误处理程序本身。
  • 已搬家 <errorHandler />从 web.config 的服务行为部分到端点行为部分的行。

  • 这并不理想,因为现在 WCF 忽略了 BodyStyle = WebMessageBodyStyle.WrappedRequest我想要我的服务方法(尽管我现在可以完全省略它)。我还必须更改 JS 服务代理中的一些代码,因为它正在寻找响应中的包装器 ( { d: ... } ) 对象。

    这是所有相关的代码( ShipmentServiceFault 对象是不言自明的)。

    服务

    我的服务非常简单(截断版):
    [ServiceContract(Namespace = "http://removed")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ShipmentService
    {

    [OperationContract]
    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    [FaultContract(typeof(ShipmentServiceFault))]
    public string UpdateCountry(Country country)
    {
    var checkName = (country.Name ?? string.Empty).Trim();
    if (string.IsNullOrEmpty(checkName))
    throw new ShipmentServiceException("Country name cannot be empty.");

    // Removed: try updating country in repository (works fine)

    return someHtml; // new country information HTML (works fine)
    }

    }

    错误处理
    IErrorHandler, IServiceBehavior执行情况如下:
    public class ShipmentServiceErrorHandlerElement : BehaviorExtensionElement
    {
    protected override object CreateBehavior()
    {
    return new ShipmentServiceErrorHandler();
    }

    public override Type BehaviorType
    {
    get
    {
    return typeof(ShipmentServiceErrorHandler);
    }
    }
    }

    public class ShipmentServiceErrorHandler : IErrorHandler, IServiceBehavior
    {
    #region IErrorHandler Members

    public bool HandleError(Exception error)
    {
    // We'll handle the error, we don't need it to propagate.
    return true;
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
    if (!(error is FaultException))
    {
    ShipmentServiceFault faultDetail = new ShipmentServiceFault
    {
    Reason = error.Message,
    FaultType = error.GetType().Name
    };

    fault = Message.CreateMessage(version, "", faultDetail, new DataContractJsonSerializer(faultDetail.GetType()));

    this.ApplyJsonSettings(ref fault);
    this.ApplyHttpResponseSettings(ref fault, System.Net.HttpStatusCode.InternalServerError, faultDetail.Reason);
    }
    }

    #endregion

    #region JSON Exception Handling

    protected virtual void ApplyJsonSettings(ref Message fault)
    {
    // Use JSON encoding
    var jsonFormatting = new WebBodyFormatMessageProperty(WebContentFormat.Json);

    fault.Properties.Add(WebBodyFormatMessageProperty.Name, jsonFormatting);
    }

    protected virtual void ApplyHttpResponseSettings(ref Message fault, System.Net.HttpStatusCode statusCode, string statusDescription)
    {
    var httpResponse = new HttpResponseMessageProperty()
    {
    StatusCode = statusCode,
    StatusDescription = statusDescription
    };

    httpResponse.Headers[HttpResponseHeader.ContentType] = "application/json";
    httpResponse.Headers["jsonerror"] = "true";

    fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
    }

    #endregion

    #region IServiceBehavior Members

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    // Do nothing
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
    IErrorHandler errorHandler = new ShipmentServiceErrorHandler();

    foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
    {
    ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

    if (channelDispatcher != null)
    {
    channelDispatcher.ErrorHandlers.Add(errorHandler);
    }
    }
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
    // Do nothing
    }

    #endregion
    }

    JavaScript

    调用 WCF 方法开始于:
        function SaveCountry() {
    var data = $('#uxCountryEdit :input').serializeBoundControls();
    ShipmentServiceProxy.invoke('UpdateCountry', { country: data }, function(html) {
    $('#uxCountryGridResponse').html(html);
    }, onPageError);
    }

    我之前提到的服务代理处理了很多事情,但在核心,我们到了这里:
    $.ajax({
    url: url,
    data: json,
    type: "POST",
    processData: false,
    contentType: "application/json",
    timeout: 10000,
    dataType: "text", // not "json" we'll parse
    success: function(response, textStatus, xhr) {

    },
    error: function(xhr, status) {

    }
    });

    配置

    我觉得问题可能出在这里,但我已经尝试了几乎所有可以在有示例的网络上找到的设置组合。
    <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <behaviors>
    <endpointBehaviors>
    <behavior name="Removed.ShipmentServiceAspNetAjaxBehavior">
    <webHttp />
    <enableWebScript />
    </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
    <behavior name="Removed.ShipmentServiceServiceBehavior">
    <serviceMetadata httpGetEnabled="true"/>
    <serviceDebug includeExceptionDetailInFaults="false"/>
    <errorHandler />
    </behavior>
    </serviceBehaviors>
    </behaviors>
    <services>
    <service name="ShipmentService" behaviorConfiguration="Removed.ShipmentServiceServiceBehavior">
    <endpoint address=""
    behaviorConfiguration="Removed.ShipmentServiceAspNetAjaxBehavior"
    binding="webHttpBinding"
    contract="ShipmentService" />
    </service>
    </services>
    <extensions>
    <behaviorExtensions>
    <add name="errorHandler" type="Removed.Services.ShipmentServiceErrorHandlerElement, Removed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    </behaviorExtensions>
    </extensions>
    </system.serviceModel>

    备注

    我注意到这个问题越来越受欢迎。我确实找到了这个问题的解决方案,我希望在找到一些时间时提供答案。敬请关注!

    最佳答案

    我不熟悉 ASP 或 WCF,但我对 jQuery 非常熟悉。关于您的问题,我印象最深的一件事是您的服务正在返回 202 Success当抛出异常时。 jQuery 根据从服务器返回的 HTTP 状态代码选择要调用的回调( successerror )。 202被认为是一个成功的响应,因此 jQuery 将调用 success .如果你想让 jQuery 调用 error回调,你需要让你的服务返回一个 40x50x状态码。咨询 http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html获取 HTTP 状态代码列表。

    关于当 WCF 方法抛出异常时,jQuery 成功回调以空响应调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4361756/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com