Проблема с Automapper 8.0 в службе .NET WCF - PullRequest
0 голосов
/ 26 ноября 2018

Я только что обновил Automapper в своем проекте WCF Service до последней версии 8.0.0.Я получаю следующую ошибку при вызове службы через тестовый клиент WCF:

System.InvalidOperationException: 'Mapper уже инициализирован.Вы должны вызывать Initialize один раз для домена / процесса приложения. '

В старой версии Automapper 6.0.2 она работает и не выдает никаких исключений.Я инициализировал Mapper с отдельным классом поведения службы.

Класс обслуживания EdiPartners.cs :

[AutomapServiceBehavior]
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = 
InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class EdiPartners : IPartners
{
    [FaultContract(typeof(ExceptionObject))]
    public Supplier GetPartnerData(string SupplierNumber)
    {
       // Code
    }
}

Класс поведения службы AutomapServiceBehavior :

    public sealed class AutomapServiceBehavior : Attribute, IServiceBehavior
    {
    #region IServiceBehavior Members

    public void AddBindingParameters(ServiceDescription serviceDescription, 
    ServiceHostBase serviceHostBase,
    Collection<ServiceEndpoint> endpoints, BindingParameterCollection 
    bindingParameters)
    {
        AutomapBootstrap.InitializeMap();
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    #endregion
}

Статический класс инициализации Automapper AutomapBootstrap :

   public class AutomapBootstrap
{
    public static void InitializeMap()
    {
        Mapper.Initialize(config =>
        {
            config.CreateMap<Supplier, IEdiPartnerData>();
            config.CreateMap<IEdiPartnerData, Supplier>();
            config.CreateMap<IEdiPartner, EdiPartner>();

        });
    }
}

Может быть, вы, ребята, можете мне помочь.Я не понимаю, почему это работает со старой, но не с новой версией.Есть ли лучший способ инициализации Automapper в службе WCF?

Заранее спасибо, Сандро

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Решение заключается в реализации пользовательского класса фабрики хоста службы:

public class EdiPartnersFactory : ServiceHostFactory
{
   protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
   {
    // Initialize Automapper
    AutomapBootstrap.InitializeMap();

    var host = new ServiceHost(serviceType, baseAddresses);

    return host;
    }
}

И я изменил web.config для контракта на обслуживание и привязки:

    <system.serviceModel>
  <services>
    <service name="Company.Sap.EdiPartners"
             behaviorConfiguration="MEXServiceTypeBehavior">
      <endpoint address=""
                binding="basicHttpBinding"
                contract="Company.Sap.IPartners" />
      <endpoint address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="MEXServiceTypeBehavior">
        <serviceMetadata httpGetEnabled="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

ИзменитеФайл .svc:

<%@ ServiceHost Language="C#" Debug="true" Service="Company.Sap.EdiPartners" Factory="Company.Sap.EdiPartnersFactory" CodeBehind="EdiPartners.svc.cs" %>

Таким образом, не нужно использовать привязку службы в классе обслуживания (выглядит намного чище):

public class EdiPartners : IPartners
{
    [FaultContract(typeof(ExceptionObject))]
    public Supplier GetPartnerData(string SupplierNumber)
    {
       // Code
    }
}
0 голосов
/ 27 ноября 2018

Поскольку ваш сервис InstanceContextMode.PerCall, новый вызов будет создаваться для каждого вызова.Кроме того, поскольку вы украсили свой сервис [AutomapServiceBehavior], он будет инициализироваться не один раз для домена приложения (как говорится в ошибке), а для экземпляра .

Поэтому измените код на:

public sealed class AutomapServiceBehavior : Attribute, IServiceBehavior
{
    static bool _initialised;

#region IServiceBehavior Members
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        if (_initialised)  // already init'd per this AppDomain
            return;

        AutomapBootstrap.InitializeMap();
        _initialised = true;
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
#endregion
}

Полезное поведение службы или пользовательский узел службы?

Кстати, AutomapServiceBehavior, вероятно, не является хорошим примером написания поведения службы, потому что если вы намереваетесь украсить несколько служб ею(возможно, с разными сопоставлениями) в одной сборке он не будет работать.AutoMapper нравится, когда инициализируется * только 1014 * один раз при запуске приложения , поэтому, если оно будет где-либо инициализировано, я помещу его в пользовательский ServiceHost и отключус поведением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...