Общий ServiceFactory <T>для WCF Channel Factory и StructureMap с MVC 3 - PullRequest
0 голосов
/ 08 марта 2012

Так что это будет интересный пост, потому что я должен включить весь свой код и постараюсь объяснить, как я настроил свою архитектуру.

Я разместил все свои Сервисы и DataContracts в центральной сборке (DMT.WCF.Contracts).Это сделано для того, чтобы распределенные части моего приложения могли ссылаться на один и тот же тип сервисных интерфейсов и контрактов, что очень хорошо.

Я настроил контейнер StructureMap для добавления моих зависимостей следующим образом, указав ServiceContext, в котором будут храниться все свойства интерфейса службы, чтобы на них можно было ссылаться в приложении позже.

public interface IServiceContext
{

}

public class ServiceContext: IServiceContext
{
    public IAuthenticationService AuthenticationService { get; set; }
    public ServiceContext(IAuthenticationService authenticationService)
    {
         AuthenticationService = authenticationService;
    }
}

Затем у меня есть свой StructureMapControllerFactory, который выглядит следующим образом:

public class StructureMapControllerFactory:DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null) return null;
        return ObjectFactory.GetInstance(controllerType) as IController;
    }
}

, и это настроено в моем global.asax следующим образом:

protected void Application_Start()
    {
        ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        Configure();

    }

Я хотелчтобы максимально отделить мои службы от моего приложения, поэтому я реализовал следующий класс ServiceFactory, который обрабатывает предоставление прокси для StructureMap при настройке контейнера IoC:

public  static class ServiceFactory
{
    private static readonly ClientSection _clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;

    public static T Create<T>()
    {
        T context = default(T);
        foreach(ChannelEndpointElement endpoint in _clientSection.Endpoints)
        {
            if(endpoint.Contract == typeof(T).FullName)
            {
                IEnumerable<Type> assignables = typeof (Binding).Assembly.GetTypes().Where(p => typeof(Binding).IsAssignableFrom(p));
                Type bindingType = assignables.Single(p => p.Name.ToLower().Equals(endpoint.Binding.ToLower()));
                context = ChannelFactory<T>.CreateChannel((Binding)Activator.CreateInstance(bindingType, false), new EndpointAddress(endpoint.Address));
            }
        }
        return context;
    }

}

Это позволяет мне извлекать данные непосредственно изФайл конфигурации при создании прокси, поэтому мне не нужно выбирать «Добавить ссылку на службу» (поскольку это технически добавляет зависимость).

В моем global.asax я теперь могу настроить свой контейнер StructureMap следующим образом:

protected void Configure()
    {
        ObjectFactory.Configure(x =>
        {
            x.Scan(scanner => scanner.AddAllTypesOf<IController>());
            x.For<IAuthenticationService>().Use(ServiceFactory.Create<IAuthenticationService>());
            x.For<IServiceContext>().Use<ServiceContext>();

        });
    }

Хотя я изначально мог использовать это яn следующим образом:

IAuthenticationService service = ServiceContext.AuthenticationService.Authenticat(...);

Теперь я не могу запустить свое приложение без исключений, таких как:

StructureMap configuration failures:
Error:  104
Source:  Registry:  StructureMap.Configuration.DSL.Registry, StructureMap,  Version=2.6.1.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
Type Instance '685e2e2a-f271-4163-a6fa-ba074e4082d1' (Object:   DMT.WCF.Contracts.Authentication.IAuthenticationService) cannot be plugged into type   DMT.WCF.Contracts.Authentication.IAuthenticationService, DMT.WCF.Contracts,  Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Я не уверен, почему это происходит.Как я уже сказал, я изначально смог запустить и запустить его, но не уверен, что изменилось.

Я просмотрел множество сотен ссылок, касающихся этого сообщения об ошибке, но все они относятся кпроблемы, которые, кажется, не соответствуют моим, если я не пропускаю свою проблему.

HELP !!!

Ответы [ 2 ]

0 голосов
/ 01 марта 2013

Ну, два вопроса здесь.Как отметил Сиксто Саез, есть вопросы WCF, которые следует рассмотреть.Что касается структуры StructureMap, я предполагаю, что ваш фабричный метод может возвращать экземпляр по умолчанию для интерфейса.

Два предложения ...

  1. Сразу после конфигурации вашего контейнера добавьте вызов ObjectFactory.AssertConfigurationIsValid () ... убедитесь, что вы удалили его снова после того, как вычислиличто не так :-) он должен выдать очень похожую ошибку, но он на самом деле попытается разрешить каждый экземпляр каждого настроенного типа.Обычно вы получаете очень подробную ошибку со всем, что не так.Затем вы можете начать поиск ошибки конфигурации.

  2. Это может быть связано с вашим заводским методом для подключаемого типа.Вы можете попробовать создать эти экземпляры на лету.Для этого используйте синтаксис IContext - context => // Make Foo Here.

protected void Configure()
{
    ObjectFactory.Configure(x =>
    {
        x.Scan(scanner => scanner.AddAllTypesOf<IController>());

        // Skip using this
        // x.For<IAuthenticationService>()
        //    .Use(ServiceFactory.Create<IAuthenticationService>());

        // Use the IContext syntax instead. Normally you'd grab the instance out of the
        // container, but you can use this to resolve an instance "live" from
        // somewhere other than the container
        x.For<IAuthenticationService>()
            .Use(context => ServiceFactory.Create<IAuthenticationService>());

        x.For<IServiceContext>().Use<ServiceContext>();
    });

    // Remove this from production code because it resolves the entire container...
    ObjectFactory.AssertConfigurationIsValid();
}

Я предполагаю, что использование синтаксиса IContext может помочь исправить ошибки конфигурации.Вы можете использовать Assert, если нет.Я думаю, что другие комментарии касаются проблем WCF, но их сложно оценить, хотя StructureMap настроен неправильно.

0 голосов
/ 31 августа 2012

Разве эта операция не использует ChannelFactory для создания нового безопасного клиента канала?

context = ChannelFactory<T>.CreateChannel(
    (Binding)Activator.CreateInstance(bindingType, false),
    new EndpointAddress(endpoint.Address));
...