问题描述
我正在实施IErrorHandler
以便将WCF服务的所有错误处理集中在一处.效果很好:
I am implementing IErrorHandler
in order to centralize all of the error handling for my WCF service in one place. This works fairly well:
public class ServiceErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
// ..Log..
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// ..Provide fault..
}
}
现在,我们正在使用Ninject在服务的其余部分中注入依赖项,我想在这里做同样的事情.由于WCF是根据我的配置构造对象的,并且我认为我对此过程没有任何迷惑,因此我需要使用属性注入:
Now, we're using Ninject to inject dependencies in the rest of the service, and I'd like to do the same here. Since WCF is constructing the objects based on my configuration, and I don't think I have any hooks into this process, I need to use property injection:
[Inject]
public ILoggingService Logger { get; set; }
但是,这似乎从未被注入.我尝试使用Ninject的MVC扩展来设置ServiceErrorHandler
以允许像过滤器一样进行注入,但是似乎并没有解决问题.有没有办法做到这一点?
However, this never seems to get injected. I tried using Ninject's MVC extensions to set ServiceErrorHandler
to allow injection like a filter, but that didn't seem to do the trick. Is there a way to make this happen?
推荐答案
最新的答案,但是您可以通过创建自定义的ServiceHost
(例如TestServiceHost
)将依赖项注入到IErrorHandler
中.
Late answer, but you can inject dependencies into IErrorHandler
by creating your custom ServiceHost
, let's say TestServiceHost
.
在您的TestServiceHost
中,您需要执行以下操作:
In your TestServiceHost
you need to do:
- 使用
IErrorHandler
参数实现构造函数. - 在内部,创建一个名为
ErrorHandlerBehaviour
*的私有嵌套类,该类需要同时实现IServiceBehavior
和IErrorHandler
.它还必须具有带有IErrorHandler
参数的构造函数. - 覆盖
OnStarting()
方法,您可以在其中将ErrorHandlerBehaviour
添加到服务行为中.必须在base.OnStarting()
之前添加所有行为.
- Implement constructor with
IErrorHandler
parameter. - Inside, create a private nested class named
ErrorHandlerBehaviour
*, which needs to implement bothIServiceBehavior
andIErrorHandler
. It also must have constructor withIErrorHandler
parameter. - Override
OnStarting()
method, where you will addErrorHandlerBehaviour
to service behaviours. All behaviours must be added beforebase.OnStarting()
.
*这个想法来自Juval Lowy在编程WCF服务"一书中的示例.您可以在此处找到有关故障和错误扩展的更多信息.
*the idea came from Juval Lowy's example in book - "Programming WCF Services". More information about Faults and Error extensions you can find there.
这是正在运行的主机控制台应用程序.我不在这里使用IoC,只是 Pure DI ,但是您可以轻松地使用以下方法解决记录器您想要的任何IoC:
Here is the working host console application. I don't use IoC there, just Pure DI, but you can easily resolve logger with any IoC you want:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace ConsoleHost
{
class Program
{
static void Main(string[] args)
{
var logger = new DummyLogger();
var errorHandler = new TestErrorHandler(logger);
ServiceHost host = new TestServiceHost(errorHandler, typeof(TestService), new Uri("net.tcp://localhost:8002"));
host.Open();
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
string Test(int input);
}
public class TestService : ITestService
{
public string Test(int input)
{
throw new Exception("Test exception!");
}
}
public class TestErrorHandler : IErrorHandler
{
private ILogger Logger { get; }
public TestErrorHandler(ILogger logger)
{
Logger = logger;
}
public bool HandleError(Exception error)
{
Logger.Log(error.Message);
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException fe = new FaultException();
MessageFault message = fe.CreateMessageFault();
fault = Message.CreateMessage(version, message, null);
}
}
public class TestServiceHost : ServiceHost
{
private readonly IErrorHandler errorHandler;
public TestServiceHost(IErrorHandler errorHandler, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
this.errorHandler = errorHandler;
}
protected override void OnOpening()
{
Description.Behaviors.Add(new ErrorHandlerBehaviour(errorHandler));
base.OnOpening();
}
class ErrorHandlerBehaviour : IServiceBehavior, IErrorHandler
{
private readonly IErrorHandler errorHandler;
public ErrorHandlerBehaviour(IErrorHandler errorHandler)
{
this.errorHandler = errorHandler;
}
bool IErrorHandler.HandleError(Exception error)
{
return errorHandler.HandleError(error);
}
void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
errorHandler.ProvideFault(error, version, ref fault);
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(this);
}
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
// Dummy logger
public interface ILogger
{
void Log(string input);
}
public class DummyLogger : ILogger
{
public void Log(string input) => Console.WriteLine(input);
}
}
和配置:
<system.serviceModel>
<services>
<service name="ConsoleHost.TestService">
<endpoint address="net.tcp://localhost:8002/TestService"
binding="netTcpBinding"
contract="ConsoleHost.ITestService" />
</service>
</services>
</system.serviceModel>
顺便说一句.确保已将System.Runtime.Serialization
添加到引用中
Btw. Make sure you added System.Runtime.Serialization
to your references
这篇关于将依赖项注入IErrorHandler实现中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!