无法 bootstrap 具有 ServiceBehavior 的服务(AutoMapper "Mapper not initialized")
Unable to bootstrap a service with ServiceBehavior (AutoMapper "Mapper not initialized")
我遇到了几个问题,但无法解决问题。
尝试使用 AutoMapper 7.0 时,我遇到了 Mapper not initialized
异常 - 虽然我认为我的问题与 AutoMapper 无关,但与我尝试向 WCF 注册服务的方式有关。
我关注了 this 文章并为我的 AutoMapper 创建了一个 ServiceBehavior:
public sealed class AutomapServiceBehavior : Attribute, IServiceBehavior
{
public AutomapServiceBehavior()
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
AutomapBootstrap.InitializeMap();
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
然后在AutomapBootstrap.InitializeMap()中添加断点(看起来像这样):
public class AutomapBootstrap
{
public static void InitializeMap()
{
//BREAKPOINT ADDED HERE
var config = new MapperConfiguration(cfg =>
cfg.CreateMap<ClassA, ClassB>()
);
var mapper = new Mapper(config);
}
}
我认为应用程序应该在启动期间在我的断点处停止,但它没有。我错过了什么?
首先,您需要确保将注释添加到您的服务中,以便首先调用该行为
[AutomapServiceBehavior] <-------
[ServiceErrorBehavior(typeof(ElmahErrorHandler))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DVDService : IDVDService
{
其次,初始化映射器的方式是将其分配给 var,然后初始化完成,因此 var 将超出范围并立即被垃圾收集,即使在那篇文章的示例中我怀疑他是否测试过这是因为他的初始化没有调用正确的方法来将映射器存储在任何地方。
在 9.0 之前你会像
一样初始化它
Mapper.Initialize(cfg =>
{
cfg.CreateMap<ClassA, ClassB>();
});
Mapper.AssertConfigurationIsValid();
这将在 运行 时间内存储映射器的静态副本,可以在系统中的任何地方静态访问,通常您会在启动时调用它,而不是在服务定义中调用它,因为它只需要成为 运行 一次。这样您根本不需要在服务定义中调用它。它在您的整个应用程序中都可用。你就这样称呼它
var result = Mapper.Map<ClassB>(classA);
在 9.0 之后他们删除了静态 API 并且你需要使用依赖注入,
或者你可以看看我的回答
看看如何解决这个问题。
我遇到了几个问题,但无法解决问题。
尝试使用 AutoMapper 7.0 时,我遇到了 Mapper not initialized
异常 - 虽然我认为我的问题与 AutoMapper 无关,但与我尝试向 WCF 注册服务的方式有关。
我关注了 this 文章并为我的 AutoMapper 创建了一个 ServiceBehavior:
public sealed class AutomapServiceBehavior : Attribute, IServiceBehavior
{
public AutomapServiceBehavior()
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
AutomapBootstrap.InitializeMap();
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
然后在AutomapBootstrap.InitializeMap()中添加断点(看起来像这样):
public class AutomapBootstrap
{
public static void InitializeMap()
{
//BREAKPOINT ADDED HERE
var config = new MapperConfiguration(cfg =>
cfg.CreateMap<ClassA, ClassB>()
);
var mapper = new Mapper(config);
}
}
我认为应用程序应该在启动期间在我的断点处停止,但它没有。我错过了什么?
首先,您需要确保将注释添加到您的服务中,以便首先调用该行为
[AutomapServiceBehavior] <-------
[ServiceErrorBehavior(typeof(ElmahErrorHandler))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DVDService : IDVDService
{
其次,初始化映射器的方式是将其分配给 var,然后初始化完成,因此 var 将超出范围并立即被垃圾收集,即使在那篇文章的示例中我怀疑他是否测试过这是因为他的初始化没有调用正确的方法来将映射器存储在任何地方。
在 9.0 之前你会像
一样初始化它 Mapper.Initialize(cfg =>
{
cfg.CreateMap<ClassA, ClassB>();
});
Mapper.AssertConfigurationIsValid();
这将在 运行 时间内存储映射器的静态副本,可以在系统中的任何地方静态访问,通常您会在启动时调用它,而不是在服务定义中调用它,因为它只需要成为 运行 一次。这样您根本不需要在服务定义中调用它。它在您的整个应用程序中都可用。你就这样称呼它
var result = Mapper.Map<ClassB>(classA);
在 9.0 之后他们删除了静态 API 并且你需要使用依赖注入,
或者你可以看看我的回答