繁体   English   中英

通用服务工厂 <T> 用于带有MVC 3的WCF通道工厂和StructureMap

[英]Generic ServiceFactory<T> for WCF Channel Factory and StructureMap with MVC 3

所以这将是一个有趣的帖子,因为我必须包括所有代码,并会尝试清楚地解释如何设置体系结构。

我已将所有Service和DataContracts放在一个中央程序集中(DMT.WCF.Contracts)。 这样做是为了使我的应用程序的分布式部分都可以引用相同类型的服务接口和协定,这非常好。

我已经通过指定ServiceContext设置了StructureMap容器​​,以通过以下方式注入我的依赖项,该上下文将容纳所有Service Interface属性,以便以后可以在应用程序中引用它们。

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类,该类在配置IoC容器时处理向StructureMap提供代理:

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>();

        });
    }

尽管我最初可以通过以下方式使用它:

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

我不确定为什么会这样。 就像我说的那样,我最初能够启动并运行它,但是不确定发生了什么变化。

我查看了数百篇有关此错误消息的参考,但是它们都是特定于似乎与我的问题不符的问题,除非我忽略了我的问题。

救命!!!

此操作是否不使用ChannelFactory来创建频道安全客户端?

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

好吧,这里有两个问题。 正如Sixto Saez提到的那样,有WCF问题需要考虑。 在StructureMap方面,我的猜测是您的工厂方法可能正在返回接口的默认实例。

两个建议...

  1. 在容器配置之后,立即添加对ObjectFactory.AssertConfigurationIsValid()的调用...确保在找出问题出处之后再次将其删除:-)它应该引发非常类似的错误,但实际上它将尝试解析每个实例每个已配置类型的 通常,您会因所有错误而收到非常冗长的错误。 然后,您可以开始查找配置错误所在的位置。

  2. 它可能与您的可插拔类型的工厂方法有关。 您可以尝试动态创建这些实例。 使用IContext语法执行此操作-context => //在此处创建Foo。

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语法可能有助于修复配置错误。 如果没有,您可以使用断言从那里去。 我认为其他评论涵盖了WCF问题,但是在StructureMap配置错误的情况下很难评估这些问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM