提供WCF Webhttp绑定的例外 [英] Provide exceptions for wcf webhttpbinding

查看:51
本文介绍了提供WCF Webhttp绑定的例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须使用基本身份验证和ssl将wcf Web服务的绑定从tcpbinding更改为webhttpbinding.

I have to change a binding for wcf webservices from tcpbinding to webhttpbinding with basic authentication and ssl.

Web服务是自动托管在控制台应用程序和Windows生产版本的服务中.某些本地服务具有命名管道绑定,即使一个服务调用另一个服务也是如此.

Webservices are self hosted in a console application and in a windows service for production version. Some of local services are with named pipe binding, just if a service call another service.

一切正常,但不能使用全局错误管理器(实现IErrorHandler接口的类)

All works perfectly but not the global error manager (a class that implement IErrorHandler interface)

某些DAL或业务方法在自定义消息中引发异常,并且此消息已正确提供给客户端(一段时间进行单元测试).但是由于更改绑定,单元测试中捕获的异常始终是500错误,内部服务器错误和自定义消息不在异常对象中.

Some of DAL or business methods throw an exception with a custom message and this message was correctly provide to client (unit test for a while). But since I change binding, exceptions caught in unit test are always a 500 error, internal server error and custom messages are not in exception object.

服务器代码:

// Création de l'URI
var baseAddress = new Uri($"https://localhost/blablabla/{typeof(TBusiness).Name}");

// Création du Host avec le type de la classe Business
var host = new ServiceHost(typeof(TBusiness), baseAddress);

// Liaison WebHttpBinding sécurité transport
var binding = new WebHttpBinding
{
   MaxBufferSize = 2147483647,
   MaxReceivedMessageSize = 2147483647,
   Security = new WebHttpSecurity
   {
       Mode = WebHttpSecurityMode.Transport
   },
};

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

// Permet de renvoyer du xml et du json
var webBehavior = new WebHttpBehavior
{
   AutomaticFormatSelectionEnabled = true
};

var ep = host.AddServiceEndpoint(typeof(TContracts), binding, "");
ep.Behaviors.Add(webBehavior);

var sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.HttpHelpPageEnabled = false;

// Activation https
var smb = new ServiceMetadataBehavior
{
   HttpGetEnabled = false,
   HttpsGetEnabled = true,
};

host.Description.Behaviors.Add(smb);

// Ajout de l'authentification
var customAuthenticationBehavior = new ServiceCredentials();
customAuthenticationBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
customAuthenticationBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new SessionAuthentication();
host.Description.Behaviors.Add(customAuthenticationBehavior);

// Démarrage du host
host.Open();

抛出异常的业务方法:

public TOUser GetUserByLogin(string login)
{
  using (var service = new ServiceProviderNamedPipe<IBFSessionManager, BSSessionManager>())
  {
     // Récupération de la DALUsers
     var dal = service.Channel.GetDALUsers(OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name);
     var user = dal.GetUserByLogin(login);

     if (user == null) throw new FaultException(Errors.DALUsers_Err001);

     return BMToolsEntitiesToTO.UserToTOUser(user);
   }
}

错误全局管理器:

public class GlobalErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        // Empèche la propagation de l'erreur
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        var msg = error.Message;

        // Création de l'exception de retour
        var newEx = new FaultException(msg);
        var msgFault = newEx.CreateMessageFault();
        fault = Message.CreateMessage(version, msgFault, newEx.Action);
    }
}

单元测试:

public void GetUserByLoginWithUnknownLoginTest()
{
    TOUser user = null;
    using (var service = new ServiceProviderHTTP<IBFUsers, BSUsers>(_user))
    {
        try
        {
            user = service.Channel.GetUserByLogin("1234");
        }
        catch (Exception e)
        {
            // e.message always provide "Internal server error instead of custom message (Errors.DALUsers_Err001)
            Assert.AreEqual(Errors.DALUsers_Err001, e.Message);
        }

        Assert.IsNull(user);
    }
}

自从我更改绑定以来,所有捕获异常的单元测试都失败了.

All unit tests that catch exception failed since I change binding.

谢谢您的帮助.

推荐答案

经过几次搜索,我发现很多人都遇到同样的问题.

After several search, I saw that a lot of people have same problem.

这是我的解决方法:

在服务器端,始终使用正确的HTTP状态代码抛出此类WebFaultException:

On server side, always throw a WebFaultException like this with correct HTTP Status code :

throw new WebFaultException<string>(myStringMessage, HttpStatusCode.NotFound);

在客户端(仅用于单元测试或MVC项目),强制转换异常以在Response对象上调用GetResponseStream以获取自定义消息:

On client side (only for unit tests or MVC project), cast exception to call GetResponseStream on Response object to get custom message :

var err = (WebException)e;
using (Stream respStream = err.Response.GetResponseStream())
{
    using (var reader = new StreamReader(respStream))
    {
        var serializer = new XmlSerializer(typeof(string));
        var response = reader.ReadToEnd();
        return response.Substring(response.IndexOf('>') + 1).Replace("</string>", "");
    }
}

在IErrorHandler的ProvideFault方法中,我只是添加代码将错误写入文件中,而没有使用Message.CreateMessage方法创建消息.

In ProvideFault method from IErrorHandler, I just add code to write errors in a file but not create a message with Message.CreateMessage method.

它可以正常工作,但会在ProvideFault之后生成EndPointNotFoundException,在其他一些帖子中,我看到可能会抛出ProtocolException.

It works correctly but generate an EndPointNotFoundException after ProvideFault, in some other posts I saw that a ProtocolException could be thrown.

谢谢您的发言.

这篇关于提供WCF Webhttp绑定的例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆