简体   繁体   English

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

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

So this will be an interesting post because I must include all my code and will attempt to explain clearly how I have setup my architecture. 所以这将是一个有趣的帖子,因为我必须包括所有代码,并会尝试清楚地解释如何设置体系结构。

I have placed all my Service and DataContracts in a central assembly (DMT.WCF.Contracts). 我已将所有Service和DataContracts放在一个中央程序集中(DMT.WCF.Contracts)。 This is done so that the distributed pieces of my application can all reference the same type of service interfaces and contracts which is very nice. 这样做是为了使我的应用程序的分布式部分都可以引用相同类型的服务接口和协定,这非常好。

I have setup a StructureMap container to inject my dependencies in the following manner, by specifying a ServiceContext, which will house all of the Service Interface properties so that they can be referenced int he application later. 我已经通过指定ServiceContext设置了StructureMap容器​​,以通过以下方式注入我的依赖项,该上下文将容纳所有Service Interface属性,以便以后可以在应用程序中引用它们。

public interface IServiceContext
{

}

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

Then, I have my StructureMapControllerFactory which looks like the following: 然后,我有一个如下所示的StructureMapControllerFactory:

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

and this is configured in my global.asax like the following: 并在我的global.asax中进行如下配置:

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

        Configure();

    }

I wanted to decouple my services as much as possible from my appliction, so I have implemented the following ServiceFactory class that handles providing proxies to StructureMap when the IoC container is configured: 我想尽可能地将服务与应用程序脱钩,因此我实现了以下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;
    }

}

This allows me to pull directly from the config file when creating proxies so I do not need to select "Add Service Reference" (as that is technically adding a dependency). 这样,在创建代理时,我可以直接从配置文件中提取数据,因此无需选择“添加服务引用”(从技术上讲,这是添加依赖项)。

In my global.asax, I can now configure my StructureMap Container like this: 现在,在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>();

        });
    }

Although I was initially able to use this in the following manner: 尽管我最初可以通过以下方式使用它:

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

I am now unable to start my application without exceptions being thrown such as the following: 我现在无法启动我的应用程序,而不会引发如下异常:

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

I am not sure why this is occuring. 我不确定为什么会这样。 Like I said, I was initially able to get this up and running, but am not sure what has changed. 就像我说的那样,我最初能够启动并运行它,但是不确定发生了什么变化。

I have looked at the many of hundreds of references regarding this error message, but they are all specific to problems that dont seem to match mine, unless I am overlooking my problem. 我查看了数百篇有关此错误消息的参考,但是它们都是特定于似乎与我的问题不符的问题,除非我忽略了我的问题。

HELP!!! 救命!!!

Doesn't this operation use the ChannelFactory to new up a channel safe client? 此操作是否不使用ChannelFactory来创建频道安全客户端?

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

Well, two issues here. 好吧,这里有两个问题。 As Sixto Saez mentioned, there's WCF issues to consider. 正如Sixto Saez提到的那样,有WCF问题需要考虑。 On the StructureMap front, my guess is that your factory method may be returning a default instance for an interface. 在StructureMap方面,我的猜测是您的工厂方法可能正在返回接口的默认实例。

Two suggestions... 两个建议...

  1. Right after your container configuration, add a call to ObjectFactory.AssertConfigurationIsValid()...make sure you remove it again after you figure out what's wrong :-) it should throw a very similar error, but it will actually try to resolve every instance of every configured type. 在容器配置之后,立即添加对ObjectFactory.AssertConfigurationIsValid()的调用...确保在找出问题出处之后再次将其删除:-)它应该引发非常类似的错误,但实际上它将尝试解析每个实例每个已配置类型的 Usually you'll get a very verbose error with everything that's wrong. 通常,您会因所有错误而收到非常冗长的错误。 You can then start finding where your configuration error is. 然后,您可以开始查找配置错误所在的位置。

  2. It may have something to do with your factory method for the pluggable type. 它可能与您的可插拔类型的工厂方法有关。 You might try having those instances created on the fly. 您可以尝试动态创建这些实例。 Use the IContext syntax to do that - context => // Make Foo Here. 使用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();
}

I'm guessing that using the IContext syntax may help fix the configuration errors. 我猜想使用IContext语法可能有助于修复配置错误。 You can use the Assert to go from there if not. 如果没有,您可以使用断言从那里去。 I think the other comments cover the WCF issues, but it's kind of hard to assess those while StructureMap is misconfigured. 我认为其他评论涵盖了WCF问题,但是在StructureMap配置错误的情况下很难评估这些问题。

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

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