【问题标题】:How to use Autofac with WCF fileless activation and a custom ServiceHostFactory?如何将 Autofac 与 WCF 无文件激活和自定义 ServiceHostFactory 一起使用?
【发布时间】:2015-05-11 17:53:58
【问题描述】:

我需要在我的 CusotmServiceHostFactory 中添加绑定/配置。但是,我想使用 Autofac。我的 CustomServiceHostFactry 如何实现 AutofacServiceHostFactory?我正在使用无文件激活,所以我的配置部分如下所示:

<serviceActivations>                
  <add service="Project.Business.Services.AccountService" 
        relativeAddress="Account/AccountService.svc" 
        factory="Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>

这是我当前的自定义工厂:

public class CustomServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
        builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();

        builder.RegisterGeneric(typeof (Repository<>)).As(typeof (IRepositoryAsync<>));

        builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .As(t => t.GetInterfaces().FirstOrDefault(
                i => i.Name == "I" + t.Name));

        var container = builder.Build();
        var host = new CustomServiceHost(serviceType, baseAddresses);
        Type contractType = GetContractType(serviceType);
        host.AddDependencyInjectionBehavior(contractType, container);

        return host;
    }
    private static Type GetContractType(Type serviceType)
    {
        return serviceType.GetInterfaces()
            .FirstOrDefault(i => Attribute.IsDefined(i, typeof(ServiceContractAttribute), false));
    }
}

如您所见,我没有设置 AutfoacServiceHostFactory.Container 属性。我试过改变我的 CustomServiceHostFactory 来实现 AutofacServiceHostFactory 像这样:

public class CustomServiceHostFactory : AutofacServiceHostFactory

..但无论我做什么,当我发布到 IIS 并浏览服务时,我都会收到此错误:

AutofacServiceHost.Container 静态属性必须在之前设置 服务可以被实例化。


编辑 1:我也试过这个。

public class CustomServiceHostFactory : AutofacServiceHostFactory

然后分配给容器。我的原始代码在这里略有变化:

AutofacServiceHostFactory.Container = builder.Build();
var host = new CustomServiceHost(serviceType, baseAddresses);
Type contractType = GetContractType(serviceType);
host.AddDependencyInjectionBehavior(contractType, AutofacServiceHostFactory.Container);

这给出了同样的错误。事实上,当我在 localhost 上运行时,调试时我什至不再进入 CreateServiceHost 方法。浏览器只是呈现错误。那不再是正确的入口点/组合根了吗?


编辑 2: 事实证明这会起作用,但相当烦人。我必须用字符串 constructorString 作为参数来覆盖这个 CreateServiceHost 方法。如果我尝试覆盖其他方法签名(采用 Type serviceType 参数),我永远不会在该方法中达到我的断点......不知道为什么。这似乎是一个黑客。为什么我从来不进入 CreateServiceHost(Type serviceType... 覆盖?

public class CustomServiceHostFactory : AutofacServiceHostFactory
{
    public CustomServiceHostFactory()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
        builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();
        builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>));

        builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .As(t => t.GetInterfaces().FirstOrDefault(
                i => i.Name == "I" + t.Name));

        Container = builder.Build();
    }

    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        Type serviceType = GetType(constructorString);
        Type contractType = GetContractType(serviceType);
        var host = new CustomServiceHost(serviceType, baseAddresses);
        host.AddDependencyInjectionBehavior(contractType, Container);

        return host;
    }

    private static Type GetContractType(Type serviceType)
    {
        return serviceType.GetInterfaces()
            .FirstOrDefault(i => Attribute.IsDefined(i, typeof(ServiceContractAttribute), false));
    }

    private static Type GetType(string typeName)
    {
        var type = Type.GetType(typeName);
        if (type != null) return type;

        foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
        {
            type = a.GetType(typeName);
            if (type != null)
                return type;
        }

        return null;
    }
}

【问题讨论】:

  • 您是否尝试分配 ServiceHost.Container 属性? host.Container = builder.Build(); ?
  • 是的,我已经更新了问题以显示我尝试过的内容。
  • 所以你也将它设置在host.Container 或只是AutoServiceHostFactory
  • 没有host.Container。当我实现 AutofacServiceHostFactory 并尝试分配给它的容器时,我只有一个容器。我在这里错过了什么吗?
  • 不抱歉.. 是我的错。你见过autofac documentation sample 吗?

标签: wcf dependency-injection autofac


【解决方案1】:

好的,终于搞定了。我希望这可以帮助别人。这是 CustomServiceHostFactory:

public class CustomServiceHostFactory : ServiceHostFactory
{
    public CustomServiceHostFactory()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyDbContext>().As<IDataContextAsync>().InstancePerLifetimeScope();
        builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>().InstancePerLifetimeScope();
        builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>)).InstancePerLifetimeScope();

        builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .As(t => t.GetInterfaces().FirstOrDefault(
                i => i.Name == "I" + t.Name)).InstancePerLifetimeScope();

        AutofacHostFactory.Container = builder.Build();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        Type contractType = GetContractType(serviceType);
        var host = new CustomServiceHost(serviceType, baseAddresses);
        host.AddDependencyInjectionBehavior(contractType, AutofacHostFactory.Container);

        return host;
    }

    private static Type GetContractType(Type serviceType)
    {
        return serviceType.GetInterfaces()
            .FirstOrDefault(i => Attribute.IsDefined(i, typeof(ServiceContractAttribute), false));
    }
}

这是 CustomServiceHost 代码(为简洁起见省略了实现):

public class CustomServiceHost : ServiceHost
{        
    public CustomServiceHost(Type serviceType, Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
    }

    protected override void ApplyConfiguration()
    {
        base.ApplyConfiguration();
        AddServiceDebugBehavior();
        AddWcfMessageLoggingBehavior();
        AddGlobalErrorHandlingBehavior();
        AddServiceCredentialBehavior();
        AddEndpoints();
        ConfigureThrottling();
    }

     //implement above methods here...
}

这是配置(重要的部分):

<serviceHostingEnvironment>
  <!-- where virtual .svc files are defined -->
  <serviceActivations>                
    <add service="Project.Business.Services.AccountClassService" 
          relativeAddress="Account/AccountClassService.svc" 
          factory="Project.WebHost.CustomServiceHostFactory"/>

    <add service="Project.Business.Services.UserService"
          relativeAddress="User/UserService.svc"
          factory="Project.WebHost.CustomServiceHostFactory"/>
  </serviceActivations>
</serviceHostingEnvironment>

我的每个 WCF 服务都有这个行为属性,使它们在每次调用时都起作用(而不是默认的 PerSession):

InstanceContextMode = InstanceContextMode.PerCall

【讨论】:

    猜你喜欢
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    相关资源
    最近更新 更多