आप क्या मिल गया है भेस में एक आदेश का एक बढ़िया उदाहरण है। आप यहां क्या कर रहे हैं इसके बारे में अच्छा यह है कि आपकी सेवा विधि पहले से ही एक तर्क में ले जाती है DoSomethingData
। यह आपका कमांड संदेश है।
क्या तुम यहाँ से चूक रहे हैं आदेश संचालकों पर एक सामान्य अमूर्त है:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
पुनर्रचना का एक छोटा सा के साथ, अपने सेवा विधि इस प्रकार दिखाई देगा:
// Vanilla dependency.
ICommandHandler<DoSomethingData> doSomethingHandler;
public void DoSomething(DoSomethingData data)
{
this.doSomethingHandler.Handle(data);
}
और निश्चित रूप से आपको ICommandHandler<DoSomethingData>
के लिए कार्यान्वयन की आवश्यकता है। आपके मामले में यह इस तरह दिखेगा:
public class DoSomethingHandler : ICommandHandler<DoSomethingData>
{
public void Handle(DoSomethingData command)
{
// does the actual something
DoSomethingInternal(command);
}
}
अब आप उन पार काटने चिंताओं आप तर्क सत्यापन, कर सकते हैं आग, प्रकाशन चैनल स्थिति अद्यतन और त्रुटि हैंडलिंग की तरह कार्यान्वित के बारे में सोच रहा हो सकता है, क्या। खैर हाँ, वे सभी आपकी डब्ल्यूसीएफ सेवा कक्षा और आपके व्यापार तर्क (DoSomethingHandler
) दोनों के बारे में चिंतित नहीं होना चाहिए, वे सभी क्रॉस-कटिंग चिंताओं हैं।
पहलू-ओरिएंटेड प्रोग्रामिंग को लागू करने के कई तरीके हैं। कुछ पोस्टशर्प जैसे कोड बुनाई उपकरण का उपयोग करना पसंद करते हैं। इन उपकरणों के नकारात्मक पक्ष यह है कि वे यूनिट परीक्षण को बहुत कठिन बनाते हैं, क्योंकि आप अपनी सभी क्रॉस-कटिंग चिंताओं को बुनाई करते हैं।
दूसरा तरीका अवरोध का उपयोग करके होता है। गतिशील प्रॉक्सी पीढ़ी और कुछ प्रतिबिंब का उपयोग करना। हालांकि इसमें एक भिन्नता है कि मुझे और अधिक पसंद है, और यह सजावटी लगाने के द्वारा है। इसके बारे में अच्छी बात यह है कि यह मेरे अनुभव में क्रॉस कटिंग चिंताओं को लागू करने का सबसे साफ तरीका है।
के अपने सत्यापन के लिए एक डेकोरेटर पर एक नज़र डालें:
public class WcfValidationCommandHandlerDecorator<T> : ICommandHandler<T>
{
private IValidator<T> validator;
private ICommandHandler<T> wrapped;
public ValidationCommandHandlerDecorator(IValidator<T> validator,
ICommandHandler<T> wrapped)
{
this.validator = validator;
this.wrapped = wrapped;
}
public void Handle(T command)
{
if (!this.validator.ValidateArgument(command))
{
throw new FaultException(...);
}
// Command is valid. Let's call the real handler.
this.wrapped.Handle(command);
}
}
के बाद से इस WcfValidationCommandHandlerDecorator<T>
एक सामान्य प्रकार है, हम इसे चारों ओर हर आदेश हैंडलर लपेट कर सकते हैं।
public class WcfExceptionHandlerCommandHandlerDecorator<T> : ICommandHandler<T>
{
private ICommandHandler<T> wrapped;
public ValidationCommandHandlerDecorator(ICommandHandler<T> wrapped)
{
this.wrapped = wrapped;
}
public void Handle(T command)
{
try
{
// does the actual something
this.wrapped.Handle(command);
_publicationChannel.StatusUpdate(new Info
{
Status = transitionResult.NewState
});
}
catch (FaultException<MyError> faultException)
{
if (faultException.Detail.ErrorType == MyErrorTypes.EngineIsOffline)
{
TryFireEvent(MyServiceEvent.Error, faultException.Detail);
}
throw;
}
}
}
आप देखा है कि कैसे मैं सिर्फ इस डेकोरेटर में अपने कोड लिपटे:
var handler = new WcfValidationCommandHandlerDecorator<DoSomethingData>(
new DoSomethingHandler(),
new DoSomethingValidator());
और आप के रूप में आसानी से एक डेकोरेटर है कि किसी भी फेंका अपवाद हैंडल बना सकते हैं: उदाहरण के लिए? हम फिर से मूल रैप करने के लिए इस डेकोरेटर का उपयोग कर सकते हैं:
var handler =
new WcfValidationCommandHandlerDecorator<DoSomethingData>(
new WcfExceptionHandlerCommandHandlerDecorator<DoSomethingData>(
new DoSomethingHandler()),
new DoSomethingValidator());
बेशक
यह सब कोड का एक बहुत भयंकर की तरह लगता है और अगर सब कुछ आप हाँ एक से एक WCF सेवा विधि है, यह शायद overkill है। लेकिन यदि आपके पास दर्जन या उससे भी कम है तो यह वाकई दिलचस्प हो जाता है। यदि आपके पास सैकड़ों हैं? खैर .. अगर आप इस तरह की तकनीक का उपयोग नहीं कर रहे हैं तो मैं उस कोड बेस को बनाए रखने वाला डेवलपर बनना नहीं चाहता हूं।
तो कुछ मिनटों के रिफैक्टरिंग के बाद आप डब्ल्यूसीएफ सेवा कक्षाओं के साथ समाप्त हो जाते हैं जो सिर्फ ICommandHandler<TCommand>
इंटरफेस पर निर्भर करते हैं। सभी क्रॉस-कटिंग चिंताओं को सजावटी में रखा जाएगा और निश्चित रूप से सब कुछ आपके डीआई पुस्तकालय द्वारा तारित किया जाता है। मुझे लगता है कि आप जानते हैं कि कुछ ;-)
जब आप इस किया है, वहाँ शायद एक बात आप, बेहतर बना सकते हैं क्योंकि आपके सभी WCF सेवा कक्षाएं boringly ही देखने के लिए शुरू कर देंगे है:
// Vanilla dependency.
ICommandHandler<FooData> handler;
public void Foo(FooData data)
{
this.handler.Handle(data);
}
यह होगा नए आदेश और नए हैंडलर लिखने के लिए उबाऊ शुरू करें। आपके पास अभी भी बनाए रखने के लिए आपकी डब्ल्यूसीएफ सेवा होगी।
आप के बजाय क्या कर सकते हैं, इस तरह, एक भी विधि के साथ एकल वर्ग के साथ एक WCF सेवा बनाने है:
[ServiceKnownType("GetKnownTypes")]
public class CommandService
{
[OperationContract]
public void Execute(object command)
{
Type commandHandlerType = typeof(ICommandHandler<>)
.MakeGenericType(command.GetType());
dynamic commandHandler = Bootstrapper.GetInstance(commandHandlerType);
commandHandler.Handle((dynamic)command);
}
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
// create and return a list of all command types
// dynamically using reflection that this service
// must accept.
}
}
अब आपके पास एक भी विधि के साथ एक WCF सेवा है कि कभी नहीं होगा परिवर्तन । ServiceKnownTypeAttribute
GetKnownTypes
पर इंगित करता है। डब्ल्यूसीएफ इस विधि को स्टार्टअप पर कॉल करेगा यह देखने के लिए कि इसे किस प्रकार स्वीकार करना चाहिए। जब आप आवेदन मेटाडाटा के आधार पर सूची लौटने के लिए, यह आप अपने WCF सेवा में एक भी लाइन को बदलने के लिए बिना प्रणाली में जोड़ने के लिए और, आदेशों को दूर कर सकते हैं।
आप शायद एक समय में एक बार नए WCF विशिष्ट सज्जाकार जोड़ देगा और उन आम तौर पर WCF सेवा में रखा जाना चाहिए। अन्य सजावटी शायद अधिक सामान्य होंगे और व्यापार स्तर में ही रखा जा सकता है। उदाहरण के लिए उन्हें आपके एमवीसी एप्लिकेशन द्वारा पुन: उपयोग किया जा सकता है।
आपका प्रश्न CQRS के बारे में थोड़ा था, लेकिन मेरा उत्तर यह कोई लेना देना नहीं है। खैर ... कुछ भी नहीं है। सीक्यूआरएस इस पैटर्न का व्यापक रूप से उपयोग करता है, लेकिन सीक्यूआरएस एक कदम आगे जाता है। सीक्यूआरएस सहयोगी डोमेन के बारे में है जो आपको आदेशों को कतारबद्ध करने और उन्हें असीमित रूप से संसाधित करने के लिए मजबूर करता है। दूसरी ओर मेरा जवाब SOLID डिज़ाइन सिद्धांतों को लागू करने के बारे में है। सोलिड हर जगह अच्छा है। न केवल सहयोगी डोमेन में।
आप इस बारे में और अधिक पढ़ने के लिए चाहते हैं, कृपया command handlers लागू करने के बारे में मेरे लेख को पढ़ें। इसके बाद, my article about applying this principle to WCF services पर जाएं और पढ़ें। मेरा जवाब उन लेखों का सारांश है।
शुभकामनाएं।
वाह, आपके अविश्वसनीय रूप से विस्तृत उत्तर के लिए, स्टीवन, आपको बहुत बहुत धन्यवाद! मैंने 'आईसीओएमएंड/आईसीओएमएंड हैंडलर' पैटर्न को लागू करने के बारे में सोचा, मैं बस यह सुनिश्चित करना चाहता था कि यह इसे संभालने के लिए "मूर्खतापूर्ण" तरीका था। मुझे खुशी है कि आपने मुझे आश्वस्त किया था कि मैं सही था :) –
यह सिर्फ इस सवाल को छोड़ देता है कि मुझे किसी भी तरह राज्य मशीन पूछताछ को समाहित करना चाहिए या नहीं। लेकिन इस बिंदु पर, मैं इसे सेवा में ही छोड़ दूंगा। –
मैं वास्तव में उस पर टिप्पणी नहीं कर सकता। मुझे नहीं पता कि आपकी यह राज्य मशीन क्या है। लेकिन मुझे यकीन है कि आप इसे एक सजावटी में encapsulate कर सकते हैं। इससे भी बेहतर, जब आप इस पैटर्न के लटकते हैं, तो आप अपने कोड में किए जा सकने वाले सभी नए सुधारों को देखना शुरू कर देते हैं। आपके नए जीवन में आपका स्वागत है ;-) – Steven