12 Stimmen

Verwendung der Instanzversion von CreateMap und Map mit einem WCF-Dienst?

Ich hatte einige echte Probleme mit automapper. Ich denke, ich habe die Lösung gefunden, aber unsicher, wie es zu implementieren.

Grundsätzlich verwende ich eine benutzerdefinierte Zuordnung mit ResolveUsing und ConstructedBy, um Parameter an den Konstruktor zu übergeben. Ich verstehe, dass die meisten Leute dies einmal in der global.asax einrichten und dann vergessen.

Aber das Problem ist, dass meine Methode (auf einem wcf) in verschiedenen Parametern an den Konstruktor eines ResolveUsing ...... übergibt

Vorher habe ich Mapper.CreateMap und Mapper.Map verwendet, die statische Methoden sind, und es scheint, dass sie miteinander in Konflikt geraten, wenn verschiedene Petitionen über Methoden (Multi-User) in den wcf-Dienst kommen.

Nachdem ich etwas gelesen habe, scheint es, dass ich die Instanzversion von CreateMap und Map verwenden kann, so dass jede einzelne Petition ihre eigene Karte erhält und ihre eigenen Parameter übergeben kann.

Aber ich kann nicht herausfinden, wie man das macht. Kann mir das bitte jemand erklären? Ich stecke wirklich fest...

Früher habe ich hin und wieder Fehler bei doppelten Schlüsseln bekommen, und ich habe auch einen Log-Trace auf den Konstruktor gelegt, und es scheint, dass eine Petition die andere überschreibt - daher die statischen Versionen von Mapper.

Ich hoffe, dass ich richtig liege, aber ich kann nichts anderes finden...

BEARBEITET - EIN BEISPIEL FÜR DAS, WAS ICH HABE

Grundsätzlich funktionieren alle Zuordnungen wie sie sollten, da ich in den meisten Fällen MapFrom verwende.

Dann erstelle ich eine Instanz meines Resolvers, die ich mit einer URL übergebe. Ich habe die URL überprüft, bevor ich sie übergebe, und sie ist korrekt. Aber sobald er zurückkehrt, gibt er die falsche URL zurück.

Der Grund, warum ich in der URL übergeben müssen ist, dass es Variablen in dort hat, so dass ich die Variablen ersetzt werden müssen ... Grundsätzlich gibt es 2 URLs je nach Büro und ich habe Protokolle überall und ich kann sehen, was ich in übergeben, aber sobald ich es in übergeben - es ist nicht die, die ich in übergeben, wenn das Sinn macht, das ist seltsam!!!

Es handelt sich um einen WCF-Dienst, und ein Client hat die Methode zweimal aufgerufen und dabei 2 verschiedene Büros und damit 2 verschiedene URLs angegeben. Aber sie geben immer die gleiche URL zurück. Es ist wie eine Sitzung überschreibt die andere...

Ich hoffe, das ist sinnvoll.

  SalesPointResolver newSalesPointResolver = new SalesPointResolver(returnReservationUrl, reservationSite.ReservationUrl, startDate, endDate, officeCode);

        Mapper.CreateMap<Models.Custom.House, DTO.House>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.TaxIncluded,
                       opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxIncluded))
            .ForMember(dest => dest.TaxPercentage,
                       opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxPercentage))

            .ForMember(dest => dest.SalesPoints,
                       opt =>
                       opt.ResolveUsing(newSalesPointResolver))
            ;

HERAUSGEFUNDEN, WO ES SCHEITERT - ABER UNBEKANNT WARUM

Siehe meine Kommentare inline mit dem Code. Im Konstruktor kommt das urlTemplate an, ich speichere es in einer privaten Var und im überschriebenen ResolveCore ist es dann etwas anderes :-)

Ich habe einige log4net-Protokolle dort abgelegt, damit ich sehen kann, was passiert.

[Log]
public class SalesPointResolver : ValueResolver<Models.Custom.House, IList<DTO.SalesPoint>>
{
    private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    private string urlTemplate;

    public SalesPointResolver (bool returnReservationUrl, string urlTemplate, DateTime startDate, DateTime endDate, string officeCode)
    {
        this.urlTemplate = urlTemplate;

        log.Error("passed in " + urlTemplate); // THIS IS PERFECT
        log.Error("I am now " + this.urlTemplate); // THIS IS PERFECT
    }

    protected override IList<DTO.SalesPoint> ResolveCore(House source)
    {
        this.house = source;

        log.Error("in  resolveCore :" + this.urlTemplate); // THIS IS RETURNING THE WRONG VALUE

VORÜBERGEHENDE LÖSUNG

Ich habe eine vorläufige Lösung gefunden, aber sie ist wirklich schlecht. Ich bin sicher, automapper tun können, was ich versuche, aber ich bin offensichtlich etwas falsch machen.

Grundsätzlich gebe ich über LINQ eine Sammlung von Datensätzen zurück (DIES IST MEINE QUELLE), so dass ich ein neues Feld für jeden Datensatz eingegeben habe, der die richtige URL-Vorlage enthält. Und dann, anstatt in (über Konstruktor) die URL-Vorlage zu übergeben, habe ich es als eine Eigenschaft auf JEDEN Datensatz in der Sammlung (DIE QUELLE) verfügbar ... und es funktioniert perfekt.

Natürlich ist das wirklich ein Flickwerk und nicht ideal, aber es bringt mich zum Laufen.

Was mache ich falsch?

0 Stimmen

In Ihrem Beispiel ist es so, dass Sie die Quelle bis zur Laufzeit nicht kennen, aber Sie wissen, welches Ziel Sie zur Kompilierungszeit zuordnen?

0 Stimmen

Nein, ich kenne die Quelle ... aber ich bin in Variablen zu ResolveUsing mit Konstruktor daher die Karte muss jedes Mal erstellt werden und muss nicht von einer anderen Sitzung usw. geteilt werden übergeben

0 Stimmen

Wenn es sich um einen WCF-Dienst handelt, wird er in seiner eigenen Anwendungsdomäne ausgeführt, so dass die Maps nicht mit anderen Prozessen geteilt werden. Es klingt wie die Argumente zu ResolveUsing variieren, aber ResolveUsing nimmt den Quelltyp in der Regel. Was ist der Grund dafür, dass Sie Argumente in den Konstruktor Ihres benutzerdefinierten Value Resolver übergeben, die außerhalb Ihres Quelltyps sind?

34voto

root Punkte 2308

Ja, es gibt eine Möglichkeit, eine Instanzversion von AutoMapper zu verwenden.

Stattdessen...

Mapper.CreateMap<Dto.Ticket, Entities.Ticket>()

können Sie verwenden:

var configurationStore =
    new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
var mapper = new MappingEngine(configurationStore);
configurationStore.CreateMap<Dto.Ticket, Entities.Ticket>()

20 Stimmen

Ich weiß nicht, wie es bei älteren Versionen von AutoMapper ist, aber in der aktuellen Version ist die Configuration Klasse heißt ConfigurationStore .

2 Stimmen

Und die AllMappers() Methode ist jetzt eine Eigenschaft namens Mappers .

13voto

Jay Walker Punkte 4546

Als Antwort auf Luke Woodwards 's Kommentar auf die neuere Syntax:

ConfigurationStore store 
   = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
store.AssertConfigurationIsValid();
MappingEngine engine = new MappingEngine(store);

//add mappings via Profiles or CreateMap
store.AddProfile<MyAutoMapperProfile>();
store.CreateMap<Dto.Ticket, Entities.Ticket>();

2voto

mark smith Punkte 20145

Nun, es scheint, dass meine Frage aufgegeben wird, aber nach einer ganzen Weile herumspielen habe ich endlich eine GUTE Lösung gefunden.

im Grunde war ich in einem Resolve und ich hatte eine andere MAP, die eine der Eigenschaften rief eine andere ResolveUsing ...

Hier scheint es ein Problem zu geben. Eine weitere seltsame Sache ist, dass es jedes Mal, wenn der Anwendungspool gestartet oder recycelt wurde, fehlschlug. Daher ist es das erste Mal fehlgeschlagen und war dann in Ordnung, bis das Recyceln geschah (ich verwende eine wcf-App).

Also habe ich das zweite Mapping durch ein foreach ersetzt und mein Mapping so in meinem ursprünglichen Resolve gemacht ...

Ich habe die Antwort hier eingestellt, falls sie in Zukunft jemandem helfen kann.

Ich war mit dem Mapper statische Methoden, meine Zuordnungen zu tun, diese waren nicht in global.asax als ich verschiedene Dinge in Abhängigkeit von bestimmten Faktoren übergeben müssen.

Ich habe mich immer gefragt, ob es möglich wäre, dies mit Instanz-Versionen von mappper zu tun, ich dachte, es existierte..... aber nie herausgefunden.

Trotzdem funktioniert jetzt alles zu 100%...

0 Stimmen

Könnten Sie bitte antworten stackoverflow.com/questions/9498962/ ?

1voto

Jimmy Bogard Punkte 24802

Haben Sie die Verwendung des Map-Aufrufs, der das Zielobjekt aufnimmt, in Betracht gezogen?

var bar = new Bar("Custom each call");

Mapper.Map(foo, bar);

0 Stimmen

Danke, Jimmy, ich bin mir nicht sicher, ob ich das richtig verstehe. Wenn ich die Karte ändern, dann habe ich keinen Zugriff auf meine Standard-SRC-Objekt, die ich brauche, wie ich normalerweise Mappings seine nur auf ein paar Eigenschaften, die mich erfordern, rufen Sie die spezielle ResolveUsing und Übergabe eines Parameters, wie es ziemlich viel Logik hier ist... Also in ResolveUsing ich bin immer noch mit meinem Standard-SRC-Objekt, aber die Anwendung zusätzliche Logik vor der Rückkehr (in diesem Fall eine stringg) - verstehe ich Sie missverstehen?

0 Stimmen

Wenn Sie das näher erläutern könnten, wäre ich Ihnen sehr dankbar.

0 Stimmen

Ich glaube, ich missverstanden - haben Sie ein kleines Snippet, das zeigt, wie Sie die CreateMap und Map Aufrufe verwenden?

1voto

DuCKa Punkte 11

Wenn Sie eine instanzierte Version des Mappers in Automapper verwenden möchten, dann können Sie die Klasse MappingEngine verwenden. Ich glaube, dass die statische Mapper-Klasse ein MappingEngine-Objekt instanziiert und konfiguriert, um alle Feinheiten der Mapping-Arbeit zu erledigen.

Hier ein Beispiel für die Anwendung von IoC auf Automapper (was die Instanziierung der MappingEngine erfordert)

http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/05/11/automapper-and-ioc.aspx

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X