2009-09-30 5 views
1

Question:
Est-il possible de (automatiquement) changer la classe de base des objets de domaine générés automatiquement créés par Visual Studio « Ajouter une référence Web » fonctionnalité, sans manuellement modifier References.cs?Spécifiez Web Service de référence AUTOGÉNÉRÉ classe de base Entité

Contexte:
Lorsque l'on ajoute une référence à un service Web (via Visual Studio 'Ajouter une référence Web' fonctionnalité), un certain nombre de classes sont générées automatiquement. Les thèses représentent un objet proxy (par exemple un MyServiceSoapClient) et un certain nombre d'objets de domaine générés automatiquement (par exemple, un CustomerInfo).

Donc, si je fais quelque chose le long des lignes de ce qui suit:

MyServiceSoapClient client = new MyServiceSoapClient(); 
CustomerInfo cust = client.GetCustomer("John Smith"); 

Je vais revenir un objet CustomerInfo avec diverses propriétés etc, joliment désérialisée de tout le serveur XML retourné.

Le problème est ...
Disons que je change la valeur de la propriété Nom de l'objet Cust à « Bob Dylan ».
Idéalement, je voudrais avoir une classe de base appelée ServiceEntity qui suivra si des changements ont été faits (en piégeant l'événement INotifyPropertyChanged.PropertyChanged fourni de façon continue dans la classe de base), pour fournir une propriété 'Dirty' indiquant que le l'objet a changé depuis qu'il a été récupéré du service.

La solution
Bien que la réponse ci-dessous est un bon, nous avons pris une approche légèrement différente ...
Comme l'état de synchronisation ne doit être enregistré dans quelques situations, il était plus logique d'ajouter synchroniser le suivi à travers une classe générique, afin que nous puissions l'utiliser au fur et à mesure des besoins.
Voici un exemple de classe générique et de l'interface:

Interface:

public interface ISyncEntity 
{ 
    /// <summary> 
    /// Gets or Sets the Entity Sync State 
    /// </summary> 
    [XmlIgnore] 
    [SoapIgnore] 
    EntitySyncState SyncState { get; set; } 

    /// <summary> 
    /// Flag for deletion 
    /// </summary> 
    void DeleteOnSync(); 

    /// <summary> 
    /// Flag for Creation 
    /// </summary> 
    void CreateOnSync(); 
} 

Classe:

public class SyncEntity<TEntity> : ISyncEntity 
{ 
    /// <summary> 
    /// Backing Field for Entity Property 
    /// </summary> 
    private TEntity _entity; 

    /// <summary> 
    /// Gets or Sets the Entity in question 
    /// </summary> 
    public TEntity Entity 
    { 
     get { return _entity; } 
     set { OnEntityChange(value); } 
    } 

    /// <summary> 
    /// Invoked when a Property on the Entity is changing 
    /// </summary> 
    /// <param name="entity"></param> 
    protected void OnEntityChange(TEntity entity) 
    { 
     // Detach the property change event handler from the previous entity? 
     if (_entity is INotifyPropertyChanged) 
      (entity as INotifyPropertyChanged).PropertyChanged -= OnPropertyChange; 

     // Set backing field 
     _entity = entity; 

     // Implements INotifyPropertyChanged? 
     if (entity is INotifyPropertyChanged) 
      (entity as INotifyPropertyChanged).PropertyChanged += OnPropertyChange; 

     // Set the Sync State 
     SyncState = EntitySyncState.Unchanged; 
    } 



    /// <summary> 
    /// Fired when a property in the entity changes 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    protected void OnPropertyChange(object sender, PropertyChangedEventArgs e) 
    { 
     // If a delete or create is already pending, don't worry about the update! 
     if (SyncState == EntitySyncState.Unchanged) 
      SyncState = EntitySyncState.UpdatePending; 
    } 

    #region Sync Framework Members 

    [XmlIgnore] 
    [SoapIgnore] 
    public EntitySyncState SyncState 
    { 
     get; 
     set; 
    } 

    public void DeleteOnSync() 
    { 
     SyncState = EntitySyncState.DeletePending; 
    } 

    public void CreateOnSync() 
    { 
     SyncState = EntitySyncState.CreatePending; 
    } 

    #endregion 
} 

Méthode d'extension:

public static SyncEntity<TEntity> ToSyncEntity<TEntity>(this TEntity source) 
{ 
    if (source == null) 
     throw new ArgumentException("Source cannot be null"); 

    return new SyncEntity<TEntity>() 
    { 
     Entity = source 
    }; 
} 
+0

Dan vous n'avez pas à éditer votre titre pour dire qu'il est résolu, la sélection d'une réponse est suffisante et facilite la recherche de personnes – blowdart

Répondre

1

Les classes de proxy client générés par Visual Studio de Les fonctions de références Web sont construites wi le wsdl.exe utility du .Net Framework. Une fois générée, la sortie produit des classes partielles publiques. Au lieu de tenter de modifier la sortie générée automatiquement, vous pouvez fournir un code de classe supplémentaire dans un autre fichier qui ajoute le code d'événement que vous essayez d'implémenter.

Bien sûr, cela laisse avec implémentation du code similaire pour chaque objet. En fonction de votre service source, vous pouvez envisager d'étendre SoapHttpClientProtocol (ou n'importe quelle classe de base de protocole représente vos objets) pour fournir une implémentation unique pour tous vos objets hérités. Cela peut ne pas être possible sans l'utilisation de AOP. En tant que tel, votre kilométrage peut varier.

+0

C'est en fait une très bonne idée. Nous avons cependant résolu le problème en implémentant une classe basée sur Generics qui réagit à l'événement PropertyChanged (à partir de l'interface INotifyPropertyChanged) et une méthode Generic Extension pour créer un objet SyncObject . Cela a l'avantage supplémentaire de nous permettre de garder notre code propre et agréable et de ne faire que surveiller les données de synchronisation lorsque nous en avons besoin explicitement. Merci pour votre aide! – Dan

+0

Génériques à la rescousse! J'aime cette stratégie encore mieux. Envelopper efficacement les classes EF peut être un défi. – jro

+0

J'ai tout essayé mais cela ne marche pas car les classes générées * explicitement * héritent de l'objet, donc si vous pouvez étendre la classe, vous ne pouvez pas fournir une classe de base différente, ce qui est la question d'origine demandé (et ce que je dois faire). –

Questions connexes