gpt4 book ai didi

c# - IErrorHandler 在 HTTP 状态代码为 401 Unauthorized 时返回错误的消息正文

转载 作者:太空狗 更新时间:2023-10-29 19:47:44 25 4
gpt4 key购买 nike

我已经实现了 IErrorHandler 来处理在我的 restful WCF 服务的构造函数中抛出的授权异常。当捕获到一般异常时,我的自定义类型按预期返回,但 ContentType header 不正确。

HTTP/1.1 500 Internal Server Error
Content-Type: application/xml;
...

{"ErrorMessage":"Error!"}

然而,当错误处理程序尝试返回 401 Unauthorized http 状态代码时,消息正文将被覆盖为默认类型,但 ContentType header 是它应该的。

HTTP/1.1 401 Unauthorized
Content-Type: application/json;
...

{"Message":"Authentication failed.","StackTrace":null,"ExceptionType":"System.InvalidOperationException"}

显然这里有问题,但我不确定是什么。

我如何实现 IErrorHandler 以使其在 json 中返回带有正确 header 的自定义类型?

BaseDataResponseContract 对象:

[Serializable]
[DataContract( Name = "BaseDataResponseContract" )]
public class BaseDataResponseContract
{
[DataMember]
public string ErrorMessage { get; set; }

} // end

这是我要返回的对象。我的应用程序中的所有其他对象都继承自该对象。当抛出异常时,我们真正关心的是 http 状态代码和错误消息。

IErrorHandler 实现(为简洁起见未显示日志记录):

namespace WebServices.BehaviorsAndInspectors
{
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;

} // end

public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
{
// Create a new instance of the object I would like to return with a default message
var baseDataResponseContract = new BaseDataResponseContract { ErrorMessage = "Error!" };

// Get the outgoing response portion of the current context
var response = WebOperationContext.Current.OutgoingResponse;

// Set the http status code
response.StatusCode = HttpStatusCode.InternalServerError;

// If the exception is a specific type change the default settings
if (ex.GetType() == typeof(UserNotFoundException))
{
baseDataResponseContract.ErrorMessage = "Invalid Username!";
response.StatusCode = HttpStatusCode.Unauthorized;
}

// Create the fault message that is returned (note the ref parameter)
fault = Message.CreateMessage(version, "", baseDataResponseContract, new DataContractJsonSerializer(typeof(BaseDataResponseContract)));

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

// Add ContentType header that specifies we are using json
var httpResponseMessageProperty = new HttpResponseMessageProperty();
httpResponseMessageProperty.Headers[HttpResponseHeader.ContentType] = "application/json";
fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponseMessageProperty);

} // end

} // end class

} // end namespace

IServiceBehavior 实现:

namespace WebServices.BehaviorsAndInspectors
{
public class ErrorHandlerExtensionBehavior : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}

protected override object CreateBehavior()
{
return this;
}

private IErrorHandler GetInstance()
{
return new ErrorHandler();
}

void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end

void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
var errorHandlerInstance = GetInstance();

foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(errorHandlerInstance);
}
}

void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end

} // end class

} // end namespace

网络配置:

<system.serviceModel>

<services>
<service name="WebServices.MyService">
<endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
</service>
</services>

<extensions>
<behaviorExtensions>
<!-- This extension if for the WCF Error Handling-->
<add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>

<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<ErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
</behaviors>

....
</system.serviceModel>

最后,我在使用 WebFaultException 时看到了类似的行为。我的想法是,这是一些深藏不露的 .Net 恶作剧的结果。我选择实现 IErrorHandler,这样我就可以捕获任何其他可能无法处理的异常。

引用:

https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx

http://www.brainthud.com/cards/5218/25441/which-four-behavior-interfaces-exist-for-interacting-with-a-service-or-client-description-what-methods-do-they-implement-and

其他例子:

IErrorHandler doesn't seem to be handling my errors in WCF .. any ideas?

How to make custom WCF error handler return JSON response with non-OK http code?

How do you set the Content-Type header for an HttpClient request?

最佳答案

我不太确定您的应用程序是如何实现的。根据你的描述,我建议使用visual studio调试你的ErrorHandler,看看异常是否到达你的回调。

如果是,请以您想要的方式手动构建 soap 故障或响应。

如果不是,则意味着异常发生在到达您的服务操作之前,它可能已经在 Channel 堆栈中失败,在这种情况下,一种简单的方法是添加额外的 HttpModule 来自定义或映射响应。或者您可以尝试在 channel 堆栈中自定义编码器。

关于c# - IErrorHandler 在 HTTP 状态代码为 401 Unauthorized 时返回错误的消息正文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38231970/

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