Pertanyaan Kontrak kesalahan WCF di dunia nyata


Asumsikan kita memiliki metode layanan yang melakukan beberapa pemeriksaan keamanan, mengambil data dari DB dan layanan web pihak ketiga, konstruksi MyDataDTO, menulis entri audit kembali ke DB. Dan kami ingin kode kesalahan granular yang terstruktur dengan baik, bukan? Kami anak laki-laki yang baik dan mengikuti pedoman penanganan kesalahan WCF standar:

[FaultContract(typeof(AccessDenied))]
[FaultContract(typeof(KeyNotFound))]
[FaultContract(typeof(WsFault))]
[FaultContract(typeof(DbFault))]
MyDataDTO GetData(string key);

Sekarang kami menambahkan metode baru yang memperbarui data. Metode panggilan GetData() internal (atau sebagian besar), melakukan validasi menambahkan memperbarui data. Jadi itu harus memiliki semua kesalahan GetData() digandakan ditambah menambahkan kesalahannya sendiri:

[FaultContract(typeof(InvalidState))]
[FaultContract(typeof(DataNotValid))]
[FaultContract(typeof(AccessDenied))]
[FaultContract(typeof(KeyNotFound))]
[FaultContract(typeof(WsFault))]
[FaultContract(typeof(DbFault))]
void UpdateData(MyDataDTO data);

Sejauh ini bagus. Hal ini memungkinkan kami bahkan untuk menghasilkan dokumentasi xml yang dapat kami sediakan untuk konsumen layanan kami sehingga mereka tahu kode kesalahan mana yang dapat mereka harapkan.

Sekarang bayangkan kita memiliki 10 layanan dengan 10 metode seperti di atas (atau bahkan lebih kompleks) masing-masing. Dan mendefinisikan semua kontrak kesalahan itu menjadi mimpi buruk karena ini adalah proses yang rawan kesalahan:

  1. Tidak ada cara untuk menentukan kesalahan umum (seperti DbFault) untuk seluruh layanan
  2. Anda tidak dapat menjamin bahwa kesalahan yang ditentukan pada kontrak operasi akan benar-benar dikembalikan (masalah salin-tempel)
  3. Anda tidak dapat menjamin bahwa Anda tidak melewatkan kesalahan untuk menambah kontrak operasi

Mari kita tidak mempertimbangkan versi antarmuka di sini :)

Jadi Anda mendapat gambar jika Anda mendukung layanan WCF dalam produksi. Haruskah kita meninggalkan kontrak kesalahan sama sekali dan menggunakan C-style lama yang baik (seperti memiliki basis DTOBase kelas dengan properti ErrorCode)? Kurangi perincian error? Bagaimana cara memastikan dokumentasi benar / terbaru? Saya tertarik dengan beberapa praktik terbaik.


14
2018-01-06 13:47


asal


Jawaban:


Satu masalah dengan pendekatan asli Anda adalah bahwa Anda mencoba mereplikasi banyak kesalahan sistem / pengecualian yang bisa terjadi. Karena kerumitan sistem meningkat dengan setiap fungsi baru, jumlah masalah yang mungkin Anda harus pertanggungjawabkan meningkat secara eksponensial (atau lebih besar!)

Saya akan menyarankan pendekatan berikut: Karena Anda membuat "sistem" layanan dan panggilan akses, hanya tentukan FaultContracts yang terkait dengan sistem itu. Klien seharusnya hanya tertarik pada pertanyaan-pertanyaan berikut:

  1. Apakah ini masalah dengan data yang saya inginkan, atau cara saya bertanya?
  2. Jika tidak, apakah ini masalah dengan saya, atau itu masalah yang berhubungan dengan IT (sistem crash, kesalahan jaringan, masalah basis data, apa pun)?

Dengan sedikit pengerjaan ulang, Anda dapat mengurangi jumlah kontrak kesalahan yang harus Anda sediakan. Misalnya (dan ini di luar kepala saya):

//Base class to define general problems
[DataContract]
public class SysFault
{
  //MyDataDTO-specific general error.
  [DataMember]
  public string SysMsg {get;set;}

  //boolean for "this is a problem with me or the hosting system?"
  [DataMember]
  public bool IsSystemic {get;set;}
}

//Subclass to expose synchronization issues--if that's one you want to define
[DataContract]
public class SyncFault : SysFault
{
  [DataMember]
  public string SyncMsg { get;set; }
}

//Subclass to expose validation issues
[DataContract]
public class ValFault : SysFault
{
  [DataMember]
  public string ValMsg { get;set; }
}

Sekarang, Anda dapat menggunakan jenis kesalahan untuk memisahkan apa yang terjadi dengan layanan Anda. Sebagai contoh:

[ServiceContract]
public interface IRecordSys
{
    [OperationContract]
    [FaultContract(typeof(SysFault))]  //Raised for underlying problem
    [FaultContract(typeof(ValFault))]  //Raised if there is an issue with the key value
    MyDataDTO getData(string key);

    [OperationContract]
    [FaultContract(typeof(SysFault))]  //Raised for underlying problem elsewhere
    //Raised for some issue, such as unable to get two subsystems to update properly
    //with the given data
    [FaultContract(typeof(SyncFault))]
    void update(MyDataDTO data); 
}

Implementasi khusus Anda akan berbeda, tetapi idenya adalah menyampaikan pesan yang memprihatinkan anda sistem, tidak setiap masalah sistemik kecil yang mungkin datang.


9
2018-05-13 14:31



Anda dapat menerapkan ini:

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)

Dalam hal ini Anda akan memiliki satu tempat, di mana Anda akan beralih oleh jenis / pesan pengecualian dan memberikan kesalahan sendiri.

http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.providefault.aspx

atau lebih baik lagi dengan sampel:

http://blogs.msdn.com/b/pedram/archive/2008/01/25/wcf-error-handling-and-some-best-practices.aspx


1
2018-01-06 13:54