2009-09-24 9 views
5

मेरे वर्तमान अनुप्रयोगों में से एक में, मुझे वेबसाइट सेवा/एसओएपी के माध्यम से रिमोट सेवा (सीआरएम) से ग्राहक डेटा प्राप्त करने की आवश्यकता है। लेकिन मैं mysql डेटाबेस में डेटा को कैश करना चाहता हूं, ताकि मुझे अगली बार webservice से कनेक्ट करने की आवश्यकता न हो (डेटा अक्सर बदलता नहीं है, दूरस्थ सेवा धीमी है और बैंडविड्थ सीमा है - इसलिए कैशिंग ठीक है/जरूरी है)।डेटाबेस में कैश नहीं होने पर दूरस्थ सेवा से डेटा प्राप्त करना - सुझाव की आवश्यकता

मुझे इस कार्य के तकनीकी भाग के बारे में काफी यकीन है, लेकिन मुझे इस वेब ऐप में इस स्वच्छ और पारदर्शी को कार्यान्वित करने के बारे में इतना यकीन नहीं है।

मेरा अन्य डेटा एक ही MySQL डेटाबेस से आता है, इसलिए मैं रिपॉजिटरीज़ जो एनएचबीर्नेट के साथ डेटाबेस से पूछे गए सूचियों या एकल इकाइयों को वापस लौटाता हूं।

मेरे विचारों अब तक:


1 सब एक प्रयोग में

एक CustomerRepository, जो ईद द्वारा ग्राहक के लिए लग रहा है, यदि सफल, तो यह वापसी, और वेब सेवा कॉल और पुनर्प्राप्त डेटा को डेटाबेस में सहेजें।

नियंत्रक इस तरह दिखता है:

class Controller 
{ 
    private CustomerRepository Rep; 

    public ActionResult SomeAction(int id) 
    { 
     return Json(Rep.GetCustomerById(id)); 
    } 
} 

छद्म में भंडार/इस तरह सरल कोड:

class CustomerRepository 
{ 
    public Customer GetCustomerById(int id) 
    { 
     var cached = Database.FindByPK(id); 
     if(cached != null) return cached; 

     var webserviceData = Webservice.GetData(id); 
     var customer = ConvertDataToCustomer(webserviceData); 

     SaveCustomer(customer); 

     return customer; 
    } 
} 

हालांकि उपरोक्त कुछ हद तक सरल लग रहा है, मुझे लगता है कि CustomerRepository वर्ग काफी बड़ी और बदसूरत बढ़ेगा । तो मुझे उस दृष्टिकोण को बिल्कुल पसंद नहीं है।

एक संग्रह को केवल डेटाबेस से डेटा लोड करना चाहिए, जो कम से कम मेरे ऐप में "अनुबंध" होना चाहिए।


2 sepereate और भंडार (db पहुँच) और वेब सेवा (दूरदराज के उपयोग) के लिए

उपयोग अलग कक्षाओं नियंत्रक में एक साथ स्टिक किया और जाने नियंत्रक काम करते हैं:

नियंत्रक ऐसा लगता है:

class Controller 
{ 
    private CustomerRepository Rep; 
    private Webservice Service; 

    public ActionResult SomeAction(int id) 
    { 
     var customer = Rep.GetCustomerById(id); 
     if(customer != null) return Json(customer); 

     var remote = Service.GetCustomerById(id); 
     Rep.SaveCustomer(remote); 

     return Json(remote); 
    } 
} 

हालांकि यह थोड़ा बेहतर दिखता है, मैं अभी भी उन सभी लोगो को रखना पसंद नहीं करता नियंत्रक में सी, क्योंकि अगर सेवा वापस नहीं लौटाती है तो त्रुटि प्रबंधन को छोड़ दिया जाता है और शायद कुछ और चीजों को अव्यवस्थित कर सकता है।

शायद मैं नियंत्रक द्वारा उपयोग की जाने वाली एक और सेवा परत बना सकता हूं, लेकिन कोड काफी समान होगा, लेकिन किसी अन्य वर्ग में।

दरअसल मैं अपने नियंत्रक को एक इंटरफ़ेस/कक्षा का उपयोग करना चाहता हूं, जो उस सामान को समाहित करता है, लेकिन मुझे एक वर्ग नहीं चाहिए जो "यह सब करता है": भंडार तक पहुंच, webservice तक पहुंच, डेटा को सहेजना .. । यह कुछ हद तक मेरे लिए गलत लगता है ...



सभी विचारों अब तक कर रहे हैं/शायद कैशिंग कोड, त्रुटि हैंडलिंग, आदि मुझे लगता है कि के साथ काफी फूला हुआ हो जाएगा।

शायद मैं एओपी का उपयोग करके कुछ चीजें साफ़ कर सकता हूं?

आप उपरोक्त की तरह सामान लागू करेंगे?

तकनीकी ढांचे का उपयोग किया गया: एएसपी.नेट एमवीसी, डीआई के लिए स्प्रिंग.NET, ओआरएम के रूप में एनएचबीरनेट, डेटाबेस के रूप में mysql, दूरस्थ सेवा SOAP के माध्यम से उपयोग की जाती है।

उत्तर

5

आप Decorator पैटर्न के साथ अपने आर्किटेक्चर को स्पष्ट रूप से कार्यान्वित कर सकते हैं।

आइए कल्पना करें कि आपके पास ICustomerRepository नामक एक इंटरफ़ेस है।

आप पहली बार वेब सेवा के आधार पर आईसी कस्टमर रिपोजिटरी (चलिए इसे WsCustomerRepository कहते हैं) लागू करते हैं, और इस कार्यान्वयन में डेटाबेस के बारे में चिंता न करें।

फिर आप एक और आईसी कस्टमर रिपोजिटरी (MySQLRepository) लागू करते हैं जो केवल आपके डेटाबेस से बात करता है।

अंत में, आप एक तीसरा आईसी कस्टमर रिपोजिटरी (कैशिंग रिपोजिटरी) बनाते हैं जो आपके द्वारा वर्णित कैशिंग तर्क लागू करता है। यह 'स्थानीय' रिपोजिटरी से पूछताछ से शुरू होता है, लेकिन यदि इसका कोई परिणाम नहीं मिलता है, तो यह 'रिमोट' रिपोजिटरी से पूछताछ करता है और परिणाम को वापस करने से पहले 'स्थानीय' रिपोजिटरी में परिणाम डालता है।

आपका CachingRepository ऐसा दिखाई दे सकता:

public class CachingRepository : ICustomerRepository 
{ 
    private readonly ICustomerRepository remoteRep; 
    private readonly ICustomerRepository localRep; 

    public CachingRepository(ICustomerRepository remoteRep, ICustomerRepository localRep) 
    { 
     this.remoteRep = remoteRep; 
     this.localRep = localRep; 
    } 

    // implement ICustomerRepository... 
} 

आप देख सकते हैं, CachingRepository भी ठोस वेब सेवा और डेटाबेस के बारे में पता नहीं है, लेकिन इसके एकल जिम्मेदारी पर ध्यान केंद्रित कर सकते हैं: कैशिंग

यह आपको ज़िम्मेदारी का एक साफ अलगाव देता है, और जहां तक ​​आपके नियंत्रक चिंतित हैं, वे केवल आईसी कस्टमर रिपोजिटरी इंस्टेंस से बात करते हैं।

+1

ओह, मुझे आपके उत्तर से भी ज्यादा पसंद है! अच्छा लगा। –

+0

अब यह वास्तव में एक दिलचस्प दृष्टिकोण है – Max

+0

@ मैक्स: सजावट एक ऐसा पैटर्न है जो DI में बहुत से उपयोग को देखता है - अन्य चीजों के साथ परिदृश्य में बिल्कुल इस तरह की :) :) –

0

यह मेरी राय में, एक सेवा परत के लिए एक आदर्श उम्मीदवार है।

आपके पास दो डेटा स्रोत (डीबी रेपो और वेब सेवा) हैं, और आपको सुझाए गए अनुसार नियंत्रक के लिए उन्हें encapsulate करने की आवश्यकता है।

सेवा परत एक विधि ऐसी है कि अपने नियंत्रक इस तरह, कॉल कर सकते हैं तो:

public class Controller 
{ 
    private CustomerService _customerService; // Perhaps injected by an IoC container? 

    public ActionResult SomeAction(int id) 
    { 
     return Json(_customerService.GetCustomerById(id)); 
    } 
} 

फिर सेवा परत इतनी तरह व्यापार तर्क/कैशिंग संभाल कर सकते हैं (आप भंडार इंजेक्षन सकता है):

public class CustomerService 
{ 
    private readonly ICustomerRepository _customerRepository; 

    public CustomerService(ICustomerRepository customerRepository) 
    { 
     _customerRepository = customerRepository; 
    } 

    public Customer GetCustomerById(int id) 
    { 
     var cached = _customerRepository.FindByPK(id); 
     if(cached != null) return cached; 

     var webserviceData = Webservice.GetData(id); // You could inject the web service as well... 
     var customer = ConvertDataToCustomer(webserviceData); 

     _customerRepository.SaveCustomer(customer); 

     return customer; 
    } 
} 

फिर, आप अलग-अलग वर्गों में, या (बेहतर अभी तक) अलग असेंबली में भंडार और वेब सेवा तर्क रख सकते हैं।

आशा है कि मदद करता है!

+0

मैंने उस दृष्टिकोण के बारे में भी सोचा, हालांकि: सभी चीजों को नियंत्रक/क्रिया विधि में रखने के बजाय सेवा परत का उपयोग करने का क्या फायदा होगा? जो कुछ मैं इतना निश्चित नहीं हूँ। – Max

+1

लाभ यह है कि यह नियंत्रक से व्यवसाय तर्क को बाहर रखता है, और यदि आवश्यक हो तो आपको सेवा परत विधि को किसी अन्य नियंत्रक में पुन: उपयोग करने की अनुमति देता है। –

0

व्यक्तिगत रूप से इस परिदृश्य में मैं आपके डिजाइन पर पुनर्विचार करता हूं। मैं एक अलग प्रक्रिया (शायद एक विंडोज सेवा) होने के बारे में सोचूंगा जो रिमोट सेवा से आपके MySQL डीबी को अपडेट करता है।

इस तरह से ग्राहक हमेशा आपके स्थानीय डीबी से डेटा प्राप्त कर सकते हैं बिना किसी महत्वपूर्ण समय के लिए ब्लॉक करना। यदि आवश्यक हो तो आप MySQL डीबी से डेटा प्राप्त करते समय भी कैशिंग का उपयोग कर सकते हैं।

मुझे लगता है कि यह दृष्टिकोण संभव है कि आपके पास कितने ग्राहक हैं। दृष्टिकोण कुछ साल पहले मेरे लिए अच्छा काम करता था जब एक वेब सेवा से विनिमय दर प्राप्त करना जो विशेष रूप से विश्वसनीय नहीं था।

0

आम तौर पर मुझे मार्क का जवाब पसंद है, लेकिन मैं दो महत्वपूर्ण नोट्स जोड़ूंगा।

  1. तुम भी अपने डीबी में इस कैशिंग किया जाना चाहिए? मेरे लिए यह एप्लिकेशन कैश का सही उपयोग है। मेरे पास आमतौर पर एक कैशिंग इंटरफ़ेस होता है जो HTTP अनुप्रयोग कैश को समाहित करता है और उन विधियों का उपयोग करना आसान होता है जो स्वचालित रूप से किसी कुंजी के अस्तित्व की जांच करते हैं, जिसे वे आपकी विधि कहते हैं और कैश में डालते हैं .. इसके अलावा आप इसके बारे में एक समाप्ति भी कर सकते हैं ताकि यह ऑटो समाप्त हो जाए एक निश्चित मात्रा में समय।

    var परिणाम = कैशमेनगर। जोड़ें (() => YourMethodCall(), "कैशस्टफकेकी", नया टाइम्सपैन (0,1,0));

मुझे पता है कि यह जटिल लगता है लेकिन इसे कैश में संग्रहीत करना प्रदर्शन के संदर्भ में तेज़ होगा और एक नई तालिका बनाने से छुटकारा पा जाएगा।

  1. मैं मानता हूं कि इस प्रकार का तर्क वास्तव में नियंत्रक में नहीं है, आपका नियंत्रक बहुत बेवकूफ होना चाहिए और अधिकतर आपके यूआई और आपकी निचली परतों के बीच गोंद होना चाहिए। हालांकि, यह इस बात पर निर्भर करता है कि आप किस प्रकार का ऐप बना रहे हैं। सभी ऐप्स को 3 टायर सुपर स्ट्रक्चर होने की आवश्यकता नहीं है।
संबंधित मुद्दे

 संबंधित मुद्दे