2009-11-03 14 views
12

J'ai eu de vrais problèmes avec automapper. Je pense avoir trouvé la solution mais je ne sais pas comment l'implémenter.Utilisation de la version d'instance de CreateMap et de Map avec un service WCF?

Fondamentalement, j'utilise un mappage personnalisé avec ResolveUsing et ConstructedBy pour passer des params au constructeur, je comprends que la plupart des gens le définissent une fois dans le global.asax et l'oublient.

Mais le problème est que ma méthode (sur un WCF) passe dans différents params au constructeur d'un ResolveUsing ......

Avant que j'utilisais le Mapper.CreateMap et Mapper.Map qui sont méthodes statiques et il apparaît que lorsque différentes pétitions entrent dans le service wcf via des méthodes (multi-utilisateurs), elles sont en conflit les unes avec les autres. Après avoir lu quelque chose, il semble que je puisse utiliser la version d'instance de CreateMap et Map pour que chaque pétition obtienne sa propre carte et puisse transmettre ses propres paramètres.

Mais je n'arrive pas à trouver comment le faire. Quelqu'un peut-il expliquer s'il vous plaît? Je suis vraiment coincé ...

Avant et encore j'obtiendrais des erreurs de clé en double et aussi j'ai mis dans une trace de journal sur le constructeur et il apparaît que 1 pétition remplace l'autre - d'où les versions statiques de Mapper.

Eh bien, j'espère que je ne me trompe pas, mais je ne trouve rien d'autre ...

ÉDITÉE - UN EXEMPLE DE CE QUE JE DOIS

Fondamentalement, tout ce mapping fonctionne comme il se doit, comme J'utilise MapFrom dans la plupart des cas.

Ensuite, je crée une instance de mon résolveur que je passe dans une URL. J'ai vérifié l'URL avant de la transmettre et c'est correct. Mais une fois qu'il retourne, il renvoie la mauvaise URL.

La raison pour laquelle je dois passer dans l'URL est qu'elle contient des variables, donc j'ai besoin de remplacer les variables ... Fondamentalement, il y a 2 urls selon le bureau et j'ai des journaux partout et je vois ce que je suis passant mais une fois que je le passe - ce n'est pas celui que j'ai passé, si cela a du sens, c'est bizarre !!

C'est un service WCF et un client a appelé la méthode deux fois en passant dans 2 bureaux différents donc 2 URL différentes. Mais ils retournent toujours la même URL. C'est comme si une session écrasait l'autre ...

J'espère que cela a du sens.

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)) 
      ; 

TROUVE où ne parvient pas - en ligne avec le code MAIS POURQUOI UNKNOWN

Voir mes commentaires. Dans le constructeur, l'urlTemplate arrive, je l'enregistre dans un var privé puis dans le ResolveCore surchargé c'est autre chose :-)

J'ai placé quelques logs log4net là-bas, donc je peux voir ce qui se passe.

[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 

SOLUTION TEMPORAIRE

je l'ai fait une solution temporaire, mais il est vraiment mauvais. Je suis sûr que automapper peut faire ce que j'essaie, mais je fais évidemment quelque chose de mal. Fondamentalement, je retourne par LINQ une collection d'enregistrements (c'est ma source) donc j'ai entré un nouveau champ sur chaque enregistrement qui a le bon modèle d'URL là-bas. Et puis, au lieu de passer (via le constructeur) le template de l'url, je l'ai disponible comme propriété sur TOUT enregistrement sur la collection (LA SOURCE) ... et ça marche parfaitement.

Bien sûr, c'est vraiment patch et pas idéal mais ça me fait courir.

Où est-ce que je me trompe?

+0

Dans votre exemple, est-ce que vous ne connaissez pas la source jusqu'à l'exécution mais savez-vous à quelle cible vous correspondez au moment de la compilation? –

+0

Non, je connais la source ... mais je passe des variables à ResolveUsing en utilisant le constructeur, donc la map doit être créée à chaque fois et ne doit pas être partagée par une autre session –

+0

S'il s'agit d'un service WCF, il fonctionne propre domaine de l'application pour que les cartes ne soient partagées avec aucun autre processus. Il semble que les arguments de ResolveUsing varient, mais ResolveUsing prend typiquement le type source. Quel est le raisonnement pour que vous passiez des arguments dans le constructeur de votre Value Resolver personnalisé qui sont en dehors de votre type source? –

Répondre

2

Eh bien, il semble que ma question est abandonnée, mais après un certain temps en jouant autour j'ai finalement trouvé une solution BON ..

i était essentiellement dans un Resolve et j'ai eu une autre carte que l'une des propriétés a appelé un autre ResolveUsing ...

Il semble qu'il semble y avoir un problème avec cela. Une autre chose étrange est qu'il a échoué à chaque fois que le pool d'applications a été démarré ou recyclé. Par conséquent, il a échoué la première fois et s'est bien passé jusqu'à ce que le recyclage se produise (j'utilise une application wcf).

donc j'ai remplacé le deuxième mappage avec un foreach et a fait ma cartographie comme ça dans ma Resolve originale ...

J'ai mis la réponse ici dans le cas où il peut aider quelqu'un d'autre dans l'avenir ..

j'utilisais les Mapper méthodes statiques pour faire mes applications, celles-ci ne sont pas en global.asax que je dois passer des choses différentes en fonction de certains facteurs ..

Je me suis toujours demandé s'il serait possible de le faire avec les versions Instance de mappper, je pensais que ça existait ..... mais jamais découvert ..

Mais de toute façon tout fonctionne 100% maintenant ...

+0

Pourriez-vous s'il vous plaît répondre http://stackoverflow.com/questions/9498962/contract-first-soa-designing-business-domain-wcf? – Lijo

1

Avez-vous regardé l'utilisation de l'appel de carte qui prend dans l'objet de destination?

var bar = new Barre ("Personnaliser chaque appel");

Mapper.Map (foo, bar);

+0

Merci jimmy, je ne suis pas certain Je comprends très bien. Si je change la carte alors je n'aurai pas accès à mon objet src standard dont j'ai besoin car je fais normalement des mappings seulement sur quelques propriétés qui nécessitent d'appeler le ResolveUsing spécial et de passer un paramètre car il y a pas mal de choses de la logique ici ... Donc dans resolveusing j'utilise toujours mon objet src standard mais en appliquant une logique supplémentaire avant le retour (dans ce cas un stringg) - est-ce que je me méprends? –

+0

si vous pourriez élaborer je l'apprécierais beaucoup. –

+0

Je pense que j'ai mal compris - avez-vous un petit extrait qui montre comment vous utilisez les appels CreateMap et Map? –

1

Si vous souhaitez utiliser une version instanciée du mappeur Automapper, alors je pense que vous pouvez utiliser la classe MappingEngine. Je crois que la classe Mapper statique instancie et configure un objet MappingEngine pour effectuer tout le travail de mappage de Nitty Gritty.

Voici un exemple d'application à IoC Automapper (qui exige instanciation du MappingEngine)

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

34

Oui, il est un moyen d'utiliser une version d'instance de AutoMapper.

Au lieu de ...

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

vous pouvez utiliser:

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

Je ne connais pas les anciennes versions d'AutoMapper, mais dans la version actuelle, la classe 'Configuration' s'appelle' ConfigurationStore'. –

+2

Et la méthode 'AllMappers()' est maintenant une propriété appelée 'Mappers'. – bugged87

13

En réponse à l » commentLuke Woodwards sur la nouvelle syntaxe:

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>();