В настоящее время у меня простой пример использования.Замок Windsor WCF Facility не обрабатывает односторонние операции
1) Клиентское приложение, которое подключается к службе WCF с использованием опции AsWcfClient от Castle.
2) Служба WCF «А», которая размещается с использованием замка и вводит одну зависимость. Эта зависимость является клиентским прокси-сервером для другой службы WCF (вызов службы «B»).
3) Сервис «B» выполняет некоторые работы.
Для визуализации: клиент -> Сервис "А" с замком впрыскивается прокси -> Сервис "B"
Простой правильно? Работает без разрешения IF, и это большой, если хост службы «B» запущен и работает.
Поведение, которое я видел и могу воспроизвести по требованию, заключается в том, что если служба «B» не работает, цепочка вызовов завершается без какого-либо намека на наличие какой-либо проблемы. Чтобы сказать это по-другому, исключение исключений, заброшенное Замком, и исключение WCF. Я выделил это для обработки операций IsOneWay = true.
Это серьезная проблема, поскольку вы считаете, что все выполнено правильно, но на самом деле ни один из ваших кодов не был выполнен!
Ожидается ли такое поведение? Может быть, я могу включить какой-либо вариант в Castle, чтобы он выдавал и исключался, когда прокси-сервер WCF-клиента является разрешенной зависимостью? Какой-то другой вариант?
Еще одно замечание: единственный ключ, который у вас есть, это проблема, когда/если вы используете Container.Release() на прокси-сервере клиента, поскольку он генерирует исключение. Это не может зависеть от вас по разным причинам, не стоит здесь заходить.
Thank!
Также ниже приведен код, который воссоздает эту проблему. Чтобы запустить его 1) Создайте новый проект тестирования модулей в Visual Studio 2) Добавьте объект интеграции Castle Wondersor WCF через NuGet 3) Вставьте код снизу в файл .cs, все в одном, чтобы было легко. 4) Запустите два модульных теста, SomeOperation_With3Containers_NoException() работает как служба зависимостей (служба «B» сверху). SomeOperation_With2Containers_NoException() не работает .Release 5) Установите точки останова, и вы увидите, что в реализациях не попадает ни один код.
**** ОБНОВЛЕНИЕ ****: Основной способ, которым это необходимо обработать, - это имплантация IErrorHandler (как упоминалось в комментариях к Roman). Подробности и пример можно найти здесь: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.110).aspx
Используйте эту реализацию, чтобы регистрировать любые исключения в операции One Way и использовать эти данные для принятия соответствующих мер.
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace UnitTestProject1
{
[ServiceContract]
public interface IServiceContractA
{
[OperationContract(IsOneWay = true)]
void SomeOperation();
}
[ServiceContract]
public interface IServiceDependancy
{
[OperationContract]
void SomeOperation();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceContractAImplementation : IServiceContractA
{
private IServiceDependancy ServiceProxy;
public ServiceContractAImplementation() { }
public ServiceContractAImplementation(IServiceDependancy dep)
{
ServiceProxy = dep;
}
public void SomeOperation()
{
ServiceProxy.SomeOperation();
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceDependancyImplementation : IServiceDependancy
{
public void SomeOperation()
{
//do nothing, just want to see if we can create an instance and hit the operation.
//if we need to do something, do something you can see like: System.IO.File.Create(@"d:\temp\" + Guid.NewGuid().ToString());
}
}
public class ServiceCastleInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true, HttpHelpPageEnabled = true };
container.Register(Component.For<IServiceBehavior>().Instance(returnFaults));
//local in-proc service hosting
var namedPipeBinding = new NetNamedPipeBinding();
//it works using Named Pipes
var serviceModelPipes = new DefaultServiceModel().AddEndpoints(
WcfEndpoint.BoundTo(namedPipeBinding).At("net.pipe://localhost/IServiceContractA")
).Discoverable();
container.Register(Component.For<IServiceContractA>()
.ImplementedBy<ServiceContractAImplementation>()
.LifeStyle.PerWcfOperation()
.AsWcfService(serviceModelPipes)
);
//our service (IServiceContractA) has a dependancy on another service so needs a client to access it.
container.Register(Castle.MicroKernel.Registration.Component.For<IServiceDependancy>()
.AsWcfClient(WcfEndpoint.BoundTo(namedPipeBinding)
.At(@"net.pipe://localhost/IServiceDependancy")).LifeStyle.Transient);
}
}
public class ServiceDependancyCastleInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true, HttpHelpPageEnabled = true };
container.Register(Component.For<IServiceBehavior>().Instance(returnFaults));
//local in-proc service hosting
var namedPipeBinding = new NetNamedPipeBinding();
var serviceModel = new DefaultServiceModel().AddEndpoints(
WcfEndpoint.BoundTo(namedPipeBinding).At("net.pipe://localhost/IServiceDependancy")
).Discoverable();
container.Register(Component.For<IServiceDependancy>()
.ImplementedBy<ServiceDependancyImplementation>()
.LifeStyle.PerWcfOperation()
.AsWcfService(serviceModel)
);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void SomeOperation_With3Containers_NoException()
{
//setup the container that is going to host the service dependancy
using (var dependancyContainer = new WindsorContainer().Install(new ServiceDependancyCastleInstaller()))
{
//container that host the service that the client will call.
using (var serviceContainer = new WindsorContainer().Install(new ServiceCastleInstaller()))
{
//client container, nice and simple so doing it in the test here.
using (var clientContainer = new WindsorContainer())
{
clientContainer.AddFacility<WcfFacility>();
var endpoint = WcfEndpoint.BoundTo(new NetNamedPipeBinding())
.At("net.pipe://localhost/IServiceContractA");
clientContainer.Register(Castle.MicroKernel.Registration.Component.For<IServiceContractA>()
.AsWcfClient(endpoint).LifeStyle.Transient);
var proxy = clientContainer.Resolve<IServiceContractA>();
proxy.SomeOperation();
clientContainer.Release(proxy);
}
}
}
}
[TestMethod]
public void SomeOperation_With2Containers_NoException()
{
//this one fails.
// this test omits the dependancy that the IServiceContractA has
//Note that all seems to work, the only hint you have that it doesnt
//is the .Release call throws and exception.
//container that host the service that the client will call.
using (var serviceContainer = new WindsorContainer().Install(new ServiceCastleInstaller()))
{
//client container, nice and simple so doing it in the test here.
using (var clientContainer = new WindsorContainer())
{
clientContainer.AddFacility<WcfFacility>();
var endpoint = WcfEndpoint.BoundTo(new NetNamedPipeBinding())
.At("net.pipe://localhost/IServiceContractA");
clientContainer.Register(Castle.MicroKernel.Registration.Component.For<IServiceContractA>()
.AsWcfClient(endpoint).LifeStyle.Transient);
var proxy = clientContainer.Resolve<IServiceContractA>();
//this call seems like it works but any break points
//in code don't get hit.
proxy.SomeOperation();
//this throws and exception
clientContainer.Release(proxy);
}
}
}
}
}
Спасибо за ответ. Во-первых, вызовы One way, я не верю, что ваше утверждение будет правильным, или предполагаемое использование One Way вызывает или их дизайн в WCF. Я предлагаю этот пост для более подробной информации: http://stackoverflow.com/questions/5318192/how-to-enable-reliability-for-one-way-methods – thorphin
Вы правы, клиент не получает исключения до тех пор, пока я попробуйте освободить разрешенный клиентский прокси WCF, что является единственным признаком того, что есть проблема. Основной вопрос здесь в том, почему нет, или где это сделать, или как включить ведение журнала замка в отношении недоступности службы A? Он никогда не попадает в мой код, поэтому я могу зарегистрировать проблему. Без этого мои вызовы будут полностью потеряны, а мой код никогда не будет выполнен. Огромный вопрос, чтобы быть уверенным! – thorphin
Это связано с использованием вами привязки net.pipe вместо http, однако оно не меняет основные моменты, которые мы обсуждали ранее. Что происходит, так это: 1. клиент отправляет односторонний запрос, не заботясь вообще о ответе на обслуживание, хорошо или плохо. 2. on service Сторона, замок пытается создать экземпляр реализации, для которого требуется служебный прокси B, но поскольку служба B не работает, кажется, что прокси-сервер net.pipe не может быть создан, и поэтому вы не можете сервис Код. 3. Затем релиз прокси на стороне клиента вызывает ошибку, так как работает net.pipe. – Roman