WCF Channel Factory和带有MVC 3 </t>的StructureMap的通用ServiceFactory <t>

时间:2012-03-08 18:49:07

标签: c# asp.net-mvc wcf structuremap

所以这将是一篇有趣的帖子,因为我必须包含我的所有代码,并试图清楚地解释我如何设置我的架构。

我已将所有Service和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类,该类处理在配置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

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

我已经查看了有关此错误消息的数百个引用中的许多内容,但它们都是特定于我认为不匹配的问题,除非我忽略了我的问题。

HELP !!!

2 个答案:

答案 0 :(得分:0)

此操作是否使用ChannelFactory来修改频道安全客户端?

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

答案 1 :(得分:0)

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

两个建议......

  1. 在容器配置之后,添加对ObjectFactory.AssertConfigurationIsValid()的调用...确保在找出错误后再次删除它:-)它应该抛出一个非常类似的错误,但它会实际上尝试解决每个配置类型的每个实例。通常,你会得到一个非常详细的错误,包括错误的一切。然后,您可以开始查找配置错误的位置。

  2. 它可能与您的可插拔类型的工厂方法有关。您可以尝试动态创建这些实例。使用IContext语法来做到这一点 - context =&gt; //在这里做Foo。

  3. 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配置错误时,很难评估这些问题。