如何将 Autofac 与 WCF 无文件激活和自定义 ServiceHostFactory 结合使用?
How to use Autofac with WCF fileless activation and a custom ServiceHostFactory?
我需要在我的 CusotmServiceHostFactory 中添加 binding/configuration。但是,我想使用 Autofac。我的 CustomServiceHostFacotry 如何实现 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 并浏览服务时,我都会收到此错误:
The AutofacServiceHost.Container static property must be set before
services can be instantiated.
编辑 1:我也试过了。
public class CustomServiceHostFactory : AutofacServiceHostFactory
然后分配给容器。我的原始代码在这里略有变化:
AutofacServiceHostFactory.Container = builder.Build();
var host = new CustomServiceHost(serviceType, baseAddresses);
Type contractType = GetContractType(serviceType);
host.AddDependencyInjectionBehavior(contractType, AutofacServiceHostFactory.Container);
这给出了同样的错误。事实上,当我在本地主机上 运行 调试时,我什至不再进入 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;
}
}
好的,终于成功了。我希望这可以帮助别人。这是 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
我需要在我的 CusotmServiceHostFactory 中添加 binding/configuration。但是,我想使用 Autofac。我的 CustomServiceHostFacotry 如何实现 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 并浏览服务时,我都会收到此错误:
The AutofacServiceHost.Container static property must be set before services can be instantiated.
编辑 1:我也试过了。
public class CustomServiceHostFactory : AutofacServiceHostFactory
然后分配给容器。我的原始代码在这里略有变化:
AutofacServiceHostFactory.Container = builder.Build();
var host = new CustomServiceHost(serviceType, baseAddresses);
Type contractType = GetContractType(serviceType);
host.AddDependencyInjectionBehavior(contractType, AutofacServiceHostFactory.Container);
这给出了同样的错误。事实上,当我在本地主机上 运行 调试时,我什至不再进入 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;
}
}
好的,终于成功了。我希望这可以帮助别人。这是 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