Cᴏʀ*_*ᴏʀʏ 16 wcf jquery json asp.net-3.5
我把头发撕成了这个,所以忍受我(这是一个很长的帖子).
IErrorHandler和IServiceBehavior实现以捕获异常并提供序列化为JSON的Fault我遇到的问题是,无论何时从我的WCF服务抛出异常,都会触发调用的成功处理程序$.ajax.响应为空,状态文本为"成功",响应代码为202 /已接受.
该IErrorHandler实现不习惯,因为我可以逐步通过它,观看FaultMessage获得创建.最后发生的是success回调引发错误,因为响应文本在期望JSON字符串时为空.该error回调永远不会触发.
提供一点洞察力的一件事是enableWebScript从端点行为中删除选项.我这样做时发生了两件事:
{ d: "result" },只是"result").error回调被触发,但响应只是从IIS,不是我的错连载400 /错误的请求黄色屏幕的死亡的HTML.我尝试过关于关键字"jquery ajax asp.net wcf faultcontract json"的随机组合的前10个或更多结果中显示的内容,所以如果你打算谷歌搜索答案,不要打扰.我希望SO上的某个人之前遇到过这个问题.
最终我想要达到的目标是:
Exception在WCF方法中抛出任何类型FaultContactShipmentServiceErrorHandlerShipmentServiceFault(作为JSON)返回给客户端.error调用,所以我可以处理项目4的回调.可能与:
更新1
我检查了跟踪System.ServiceModel活动的输出,并在调用UpdateCountry方法后的一个点上抛出了一个异常,消息是
服务器返回了无效的SOAP错误.
就是这样.一个内部异常抱怨序列化器期望一个不同的根元素,但我不能破译其他许多东西.
更新2
因此,随着更多的麻烦,我得到了一些工作,虽然不是我认为理想的方式.这是我做的:
<enableWebScript />从web.config的端点行为部分中删除了该选项.FaultContract从服务方法中删除了该属性.WebHttpBehavior(调用ShipmentServiceWebHttpBehavior)的子类并覆盖AddServerErrorHandlers函数以添加ShipmentServiceErrorHandler.ShipmentServiceErrorHandlerElement为返回类型的实例ShipmentServiceWebHttpBehavior而不是错误处理程序本身.<errorHandler />行从web.config的服务行为部分移动到端点行为部分.这不是理想的,因为现在WCF忽略了BodyStyle = WebMessageBodyStyle.WrappedRequest我想要的服务方法(虽然我现在可以完全省略它).我还必须更改JS服务代理中的一些代码,因为它{ d: ... }在响应中寻找一个wrapper()对象.
这是所有相关代码(该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)
}
}
Run Code Online (Sandbox Code Playgroud)
将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
}
Run Code Online (Sandbox Code Playgroud)
调用WCF方法始于:
function SaveCountry() {
var data = $('#uxCountryEdit :input').serializeBoundControls();
ShipmentServiceProxy.invoke('UpdateCountry', { country: data }, function(html) {
$('#uxCountryGridResponse').html(html);
}, onPageError);
}
Run Code Online (Sandbox Code Playgroud)
我之前提到的服务代理负责很多事情,但核心是我们到达这里:
$.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) {
}
});
Run Code Online (Sandbox Code Playgroud)
我觉得问题可能就在这里,但我已经尝试过几乎所有我可以在网上找到的设置组合.
<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>
Run Code Online (Sandbox Code Playgroud)
笔记
我注意到这个问题得到了一些收藏.我确实找到了这个问题的解决方案,我希望在找到一些时间后给出答案.敬请关注!
我在不同的情况下有相同的症状,所以这可能有帮助,也可能没有帮助。
以下是我正在做的事情和我们的解决方案的简要总结:
我正在发布一个 WCF 服务的 REST 实现,该服务是我们从经典 ASP 页面托管的。我发现我必须将输入设置为流并从中读取,完成后处理该流。我相信此时我收到了 202 响应,其中包含“成功”文本,正如您所描述的那样。我发现通过不处理流,我得到了我期望的错误条件响应。
以下是最终代码的摘要:
[WebHelp(Comment="Expects the following parameters in the post data:title ...etc")]
public int SaveBook(Stream stream)
{
NameValueCollection qString;
StreamReader sr = null;
string s;
try
{
/**************************************************************************************
* DO NOT CALL DISPOSE ON THE STREAMREADER OR STREAM *
* THIS WILL CAUSE THE ERROR HANDLER TO RETURN A PAGE STATUS OF 202 WITH NO CONTENT *
* IF THERE IS AN ERROR *
* ***********************************************************************************/
sr = new StreamReader(stream);
s = sr.ReadToEnd();
qString = HttpUtility.ParseQueryString(s);
string title = qString["title"];
//Do what we need
//Then Return something
int retRecieptNum = UtilitiesController.SubmitClientEntryRequest(entryReq);
return retRecieptNum;
}
catch (Exception ex)
{
throw new WebProtocolException(System.Net.HttpStatusCode.Forbidden, ex.Message, this.GetExceptionElement(true, "BookRequest", ex.Message), false, ex);
}
finally
{
}
}
Run Code Online (Sandbox Code Playgroud)
希望这对您有帮助,也许尝试使用流并看看效果如何。
| 归档时间: |
|
| 查看次数: |
4123 次 |
| 最近记录: |