質問:
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
};
}