Я новичок в WCF. При создании RestFul Apis я столкнулся с некоторой проблемой сбоев.
На моей охоте на Обработка исключений через 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 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; }
}
}
И далее (служба WCF с поддержкой Ajax использует вышеупомянутый класс 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);
}
}
Вызов вышеуказанной службы из почтальона просто дает гладкий простой результат:
Что хорошо, теперь, если я запускаю разные входные сценарии для входной переменной: начиная с установки нулевого значения для имени продукта, я получаю следующий результат
Неплохо, так как моя проверка работала, а исключение обрабатывалось, поэтому я получил вышеуказанный результат. Теперь, переходя к следующему сценарию, если я установил ID в null, получится следующий вывод:
Теперь мой вопрос: что я могу сделать, чтобы предотвратить сбой приложения таким образом? :
Ниже приведены мои классы IError Handler:
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
}
}
Когда я ставлю точку останова, чтобы выдать ошибку, она показывает следующее исключение, как если бы оно было из-за синтаксического анализа:
Как мне справиться с этим, чтобы я мог отправить чистое сообщение об ошибке клиенту
Редактировать: Почтальон общее исключение:
?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'. {"Средство форматирования выдало исключение при попытке десериализации сообщения: при попытке десериализации параметра произошла ошибка: pro. Сообщение InnerException было« Произошла ошибка при десериализации объекта типа StilaarAPI.DataContracts.Products. Значение »не может быть проанализирован как тип 'Int32'. '. Для получения более подробной информации см. InnerException. "}