Castle WCF Facility, Использование универсального интерфейса для неуниверсального договора

Я попытался свести к минимуму написание кода для WCF CRUD-части большого проекта с использованием обобщений и средства замка WCF.

У меня есть контракт на обслуживание WCF:

[ServiceContract]
public interface IResourceService : ICRUDService<DTOResource>
{
    [OperationContract]
    DTOResource Get(long id);
}

а также generic интерфейс

public interface ICRUDService<T> where T is IDTO
{
    T Get(long id);
}

также общий MVC контроллер (1 контроллер для всех основных CruD для Dtos и услуг)

public class CRUDController<T> : Controller where T is IDTO
{
    readonly ICRUDService<T> service;
    public CRUDController(ICRUDService<T> service)
    {
        this.service = service;
    }   
}

На стороне клиента я регистрирую клиента WCF в Windsor Контейнер

Component
  .For<IResourceService , ICRUDService<DTOResource>>()
  .AsWcfClient(... standard stuff... )

Everythig работает нормально, компоненты и сервисы зарегистрированы, контроллер создан правильно, сервис

readonly ICRUDService<T> service;

в контроллере типа

Castle.Proxies.IResourceService 

Но когда я пытаюсь использовать службу в контроллере, у меня появляется ошибка

Method Get is not supported on this proxy, this can happen if the method is
 not marked with OperationContractAttribute or if the interface type is not 
 marked with ServiceContractAttribute.

Когда в контроллере я наложил жесткий код

((IResourceService)service).Get(id);

все работает правильно, поэтому я считаю, что эта проблема разрешима.

Я также пытался использовать Forward (с тем же результатом):

Component
  .For<IActionTypeService>
  .Forward<ICRUDService<DTOResource>>().AsWcfClient(...

Как заставить это работать?

2 ответа

Решение

В конце концов мне пришлось использовать "Channel Factory" на стороне клиента. Я смог использовать Виндзор WCF Facility на стороне сервера зарегистрировать общий договор:

[ServiceContract]
public interface ICRUDService<I>
{
    [OperationContract]
    I Get(int id);
}

с общей реализацией

public class CRUDService<I, IEntity> : ServiceBase, ICRUDService<I>
{
    public I Get(int id)
    {            
        ...
    }

стандартным способом (для нескольких типов)

private void InstallExample<I, IEntity>(IWindsorContainer container)
{
container.Register(
    Component
        .For<ICRUDService<I>>()
        .ImplementedBy(CRUDService<I, IEntity>)
        .Named("somename")
        .AsWcfService(
            new DefaultServiceModel()
                .Hosted()
                .PublishMetadata(x => x.EnableHttpGet())
                .AddEndpoints(WcfEndpoint
                .BoundTo(new BasicHttpBinding())
                .At("someAddress")
            )
        )
        .LifeStyle.PerWcfOperation();
}

с активацией без файла в web.config

<add factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" service="ClientService" relativeAddress="./ClientService.svc" />

На стороне сервера это работает отлично. К сожалению, на стороне клиента я не нашел рабочего решения для WCFFacility, и мне пришлось использовать ChannelFactory (который работает отлично)

ChannelFactory<ICRUDService<I>> factory = new ChannelFactory<ICRUDService<I>>(someBinding, someEndpoint);

В остальном (стандартные неуниверсальные услуги я использую WCF Facility без проблем.

Я думаю, что вам нужно поместить атрибут ServiceContract в ICrudService<>, добавить туда OperationContract к методу и удалить дублирующее объявление Get() из IResourceService.

Другие вопросы по тегам