1

質問:
References.csを手動で変更せずに、Visual Studioの[Web参照の追加]機能を使用して作成された自動生成ドメインオブジェクトの基本クラスを(自動的に)変更することはできますか?

背景:
(Visual Studioの[Web参照の追加]機能を介して)Webサービスへの参照を追加すると、いくつかのクラスが自動生成されます。これらは、プロキシオブジェクト(たとえば、MyServiceSoapClient)といくつかの自動生成されたドメインオブジェクト(たとえば、CustomerInfo)を表します。

したがって、次のように何かを行うと、次のようになります。

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

サーバーが返したXMLからすべてうまく逆シリアル化された、さまざまなプロパティなどを含むCustomerInfoオブジェクトを取得します。

問題は...
custオブジェクトのNameプロパティの値を「BobDylan」に変更したとします。
理想的には、変更が行われたかどうかを追跡するServiceEntityという基本クラスが必要です(基本クラスで継続的に提供されるINotifyPropertyChanged.PropertyChangedイベントをトラップすることにより)、オブジェクトが持っていることを示す「Dirty」プロパティを提供しますサービスからフェッチされてから変更されました。

解決策
以下の答えは良い答えですが、少し異なるアプローチを取りました...
同期ステータスはいくつかの状況でのみ記録する必要があるため、Genericクラスを介して同期追跡を追加する方が理にかなっています。必要に応じて使用してください。
ジェネリッククラスとインターフェースの例を次に示します。

インターフェース:

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

クラス:

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
}

拡張方法:

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
    };
}
4

1 に答える 1

1

Visual Studio の Web 参照機能によって生成されたクライアント プロキシ クラスは、.Net Framework のwsdl.exe ユーティリティで構築されます。出力が生成されると、パブリック部分クラスが生成されます。自動生成された出力を変更しようとする代わりに、実装しようとしているイベント コードを追加する別のファイルに追加のクラス コードを提供できます。

もちろん、これは各オブジェクトに同様のコードを実装することになります。ソース サービスによっては、SoapHttpClientProtocol (またはオブジェクトを表すプロトコル基本クラス) を拡張して、すべての継承オブジェクトに単一の実装を提供することを検討できます。これは、 AOPを使用しないと不可能な場合があります。そのため、走行距離は異なる場合があります。

于 2009-09-30T16:38:41.200 に答える