मैं एक डब्लूसीएफ सेवा से अपने मौजूदा व्यावसायिक तर्क के एक हिस्से का उपभोग करने के लिए एक सिल्वरलाइट प्रोग्राम को दोबारा लिख रहा हूं। ऐसा करने में, मैंने सिल्वरलाइट 3 में प्रतिबंध में भाग लिया है जो केवल उन मामलों से बचने के लिए डब्ल्यूसीएफ सेवाओं को एसिंक्रोनस कॉल की अनुमति देता है जहां लंबे समय से चलने वाले या गैर-उत्तरदायी सेवा कॉल यूआई थ्रेड को अवरुद्ध करते हैं (एसएल के पास डब्ल्यूसीएफ सेवाओं का आह्वान करने के लिए एक दिलचस्प क्यूइंग मॉडल है यूआई थ्रेड पर)।कोरटाइन्स को लागू करने के लिए सी # इटरेटर्स का उपयोग करके (मिस) की समस्याएं
परिणामस्वरूप, जो एक बार सीधा था, लिखना तेजी से अधिक जटिल हो रहा है (मेरे प्रश्न के अंत में कोड उदाहरण देखें)।
आदर्श रूप में, मैं कार्यान्वयन को सरल बनाने के लिए coroutines का उपयोग करूंगा, लेकिन दुख की बात है कि, सी # वर्तमान में मूल भाषा सुविधा के रूप में कोरआउट को समर्थन नहीं देता है। हालांकि, सी # में yield return
वाक्यविन्यास का उपयोग कर जेनरेटर (इटरेटर) की अवधारणा है। मेरा विचार है कि उपज कीवर्ड का पुन: उद्देश्य करना मुझे एक ही तर्क के लिए एक सरल कोरआउट मॉडल बनाने की अनुमति देना है।
मैं ऐसा करने में अनिच्छुक हूं, हालांकि, मुझे चिंता है कि कुछ छुपे हुए (तकनीकी) नुकसान हो सकते हैं जिनकी मुझे उम्मीद नहीं है (सिल्वरलाइट और डब्ल्यूसीएफ के साथ मेरे सापेक्ष अनुभवहीनता को देखते हुए)। मैं भी चिंतित हूं कि कार्यान्वयन तंत्र भविष्य के डेवलपर्स के लिए स्पष्ट नहीं हो सकता है और भविष्य में कोड को बनाए रखने या बढ़ाने के उनके प्रयासों को सरल बनाने के बजाय बाधा डाल सकता है। मैंने इस सवाल को एसओ पर राज्य मशीनों का निर्माण करने के लिए पुन: प्रयोजन करने के बारे में सोचा है: implementing a state machine using the "yield" keyword, और यह वही नहीं है जो मैं कर रहा हूं, यह मुझे रोक देता है।
हालांकि, मुझे सेवा कॉल की जटिलता को छिपाने और इस प्रकार के परिवर्तन में दोषों के संभावित जोखिम को प्रबंधित करने के लिए कुछ करने की आवश्यकता है। मैं इस समस्या को हल करने के लिए उपयोग किए जा सकने वाले अन्य विचारों या दृष्टिकोणों के लिए खुला हूं।
कोड के मूल गैर WCF संस्करण इस तरह दिखता है:
void Button_Clicked(object sender, EventArgs e) {
using(var bizLogic = new BusinessLogicLayer()) {
try {
var resultFoo = bizLogic.Foo();
// ... do something with resultFoo and the UI
var resultBar = bizLogic.Bar(resultFoo);
// ... do something with resultBar and the UI
var resultBaz = bizLogic.Baz(resultBar);
// ... do something with resultFoo, resultBar, resultBaz
}
}
}
फिर से सकारात्मक असर WCF संस्करण हो जाता है काफ़ी अधिक शामिल (यहां तक कि अपवाद हैंडलिंग और पूर्व/पोस्ट हालत परीक्षण के बिना):
// fields needed to manage distributed/async state
private FooResponse m_ResultFoo;
private BarResponse m_ResultBar;
private BazResponse m_ResultBaz;
private SomeServiceClient m_Service;
void Button_Clicked(object sender, EventArgs e) {
this.IsEnabled = false; // disable the UI while processing async WECF call chain
m_Service = new SomeServiceClient();
m_Service.FooCompleted += OnFooCompleted;
m_Service.BeginFoo();
}
// called asynchronously by SL when service responds
void OnFooCompleted(FooResponse fr) {
m_ResultFoo = fr.Response;
// do some UI processing with resultFoo
m_Service.BarCompleted += OnBarCompleted;
m_Service.BeginBar();
}
void OnBarCompleted(BarResponse br) {
m_ResultBar = br.Response;
// do some processing with resultBar
m_Service.BazCompleted += OnBazCompleted;
m_Service.BeginBaz();
}
void OnBazCompleted(BazResponse bz) {
m_ResultBaz = bz.Response;
// ... do some processing with Foo/Bar/Baz results
m_Service.Dispose();
}
ऊपर कोड स्पष्ट रूप से एक सरलीकरण, जबकि इसमें अपवाद हैंडलिंग, तुच्छता चेक, या अन्य ऐसी प्रथाओं उत्पादन कोड में आवश्यक होगा छोड़ देता है। फिर भी, मुझे लगता है कि यह जटिलता में तेजी से वृद्धि दर्शाता है जो सिल्वरलाइट में एसिंक्रोनस डब्ल्यूसीएफ प्रोग्रामिंग मॉडल के साथ शुरू होता है। मूल कार्यान्वयन को पुन: फैक्टरिंग (जिसने सेवा परत का उपयोग नहीं किया था, बल्कि एसएल क्लाइंट में इसके तर्क को एम्बेड किया था) तेजी से एक कठिन काम की तलाश में है। और एक जो काफी त्रुटि प्रवण होने की संभावना है।
कोड के सह नियमित संस्करण इस कुछ ऐसा दिखाई देगा (मैं अभी तक इस परीक्षण नहीं किया):
void Button_Clicked(object sender, EventArgs e) {
PerformSteps(ButtonClickCoRoutine);
}
private IEnumerable<Action> ButtonClickCoRoutine() {
using(var service = new SomeServiceClient()) {
FooResponse resultFoo;
BarResponse resultBar;
BazResponse resultBaz;
yield return() => {
service.FooCompleted = r => NextStep(r, out resultFoo);
service.BeginFoo();
};
yield return() => {
// do some UI stuff with resultFoo
service.BarCompleted = r => NextStep(r, out resultBar);
service.BeginBar();
};
yield return() => {
// do some UI stuff with resultBar
service.BazCompleted = r => NextStep(r, out resultBaz);
service.BeginBaz();
};
yield return() => {
// do some processing with resultFoo, resultBar, resultBaz
}
}
}
private void NextStep<T>(T result, out T store) {
store = result;
PerformSteps(); // continues iterating steps
}
private IEnumerable<Action> m_StepsToPerform;
private void PerformSteps(IEnumerable<Action> steps) {
m_StepsToPerform = steps;
PerformSteps();
}
private void PerformSteps() {
if(m_StepsToPerform == null)
return; // nothing to do
m_StepsToPerform.MoveNext();
var nextStep = m_StepsToPerform.Current;
if(nextStep == null) {
m_StepsToPerform.Dispose();
m_StepsToPerform = null;
return; // end of steps
}
nextStep();
}
चीजों के सभी प्रकार उपरोक्त कोड में सुधार करने की जरूरत है कि कर रहे हैं। लेकिन मूल आधार निरंतर पैटर्न (अपवाद हैंडलिंग और विभिन्न जांचों के लिए एक अवरोध बिंदु बनाने) को कारक करना है, जबकि प्रत्येक चरण के दौरान डब्ल्यूसीएफ के इवेंट-आधारित एसिंक मॉडल को ड्राइव करने की इजाजत दी जाती है - मूल रूप से जब अंतिम एसिंक डब्ल्यूसीएफ कॉल पूरा हो जाता है। सतह पर रहते हुए यह अधिक कोड जैसा दिखता है, यह उल्लेखनीय है कि PerformSteps()
और NextStep()
पुन: प्रयोज्य हैं, केवल ButtonClickCoRoutine()
में कार्यान्वयन प्रत्येक अलग कार्यान्वयन साइट के साथ बदल जाएगा।
मुझे पूरा यकीन नहीं है कि मुझे यह मॉडल पसंद है, और अगर मैं इसे लागू करने के लिए एक आसान तरीका अस्तित्व में हूं तो मुझे आश्चर्य नहीं होगा।लेकिन मैं "इंटरवेब्स" या एमएसडीएन, या कहीं और किसी को खोजने में सक्षम नहीं हूं। मदद के लिए अग्रिम धन्यवाद।
कोई अच्छा जवाब है, सिवाय इसके कि हम अपने दर्द महसूस कहने के लिए। हम चांदी के प्रकाश और अन्य ढांचे में एसिंक्रोनि का उपयोग कैसे करते हैं, इस बारे में बहुत सारे शोध कर रहे हैं। इटरेटर्स को सस्ता कोरआउटिन की तरह दिखने के लिए किए गए परिवर्तनों के प्रकार एक शुरुआत हैं, लेकिन इस जगह की सभी समस्याओं को हल करने के लिए पर्याप्त सामान्यता नहीं है। मैं निश्चित रूप से इस तरह के पैटर्न को भाषा में स्पष्ट रूप से व्यक्त करना चाहूंगा, साथ ही साथ हम इसे पुनरावर्तक पैटर्न के पीढ़ी (उपज) और खपत (foreach) पक्षों को स्पष्ट रूप से व्यक्त करते हैं। –
मुझे लगता है कि यह प्रश्न एसिंक/सी # के लिए प्रतीक्षा करने के लिए प्रेरणा बताता है। –