2013-07-19 4 views
6

मैं डब्ल्यूसीएफ रूटिंग सेवा के साथ क्या किया जा सकता है, इसके बारे में सीख रहा हूं। अभी भी 'इसके साथ घूमना' यह देखने के लिए कि यह क्या कर सकता है 'चरण।डब्ल्यूसीएफ रूटिंग सेवा - डायनेमिक एरर हैंडलिंग

रूटिंग सेवा की मेरी समझ यह है कि जब कोई संदेश आता है, तो सेवा बैकअप सूची में पहले जो भी अंतराल दिखाई देती है उसे पास करने का प्रयास करेगी। यदि यह विफल हो जाता है, तो यह अगली कोशिश करने के लिए आगे बढ़ेगा, और फिर अगला, जब तक कि कुछ काम न करे या कोशिश करने के लिए कुछ भी नहीं बचा है।

  1. विफलता
  2. ईमेल के माध्यम से सूचना भेजें कि endpoint
  3. विफल हो रहा है वैकल्पिक रूप से हटाने लॉग इन करें:

    मैं करना चाहते हैं क्या है कि विफलता घटना तक पहुँच प्राप्त ताकि मैं है बैकअप सूची से एंडपॉइंट ताकि यह भविष्य के संदेशों को सिस्टम

इस पैरा पर प्राप्त करने के लिए डब्ल्यूसीएफ ढांचे को विस्तारित करने में परेशानी हो रही है टिकाऊ घटना।

क्या यह एक बात है जो डब्ल्यूसीएफ रूटिंग सेवा कर सकती है? सही दिशा में किसी भी झुकाव की सराहना की जाएगी।


फिलहाल मैं 30-ish गतिशील रूप से उत्पन्न मार्ग आईआईएस के तहत सेवाओं की मेजबानी की है (या अधिक सटीक होना करने के लिए, दृश्य स्टूडियो 2010 के लिए ASP.NET विकास सर्वर)। मैं नीचे ग्लोबल.एक्सएक्स में सेवाओं के लिए मार्ग स्थापित कर रहा हूं।

protected void Application_Start(object sender, EventArgs e) 
    { 
     List<Type> serviceTypes = ServiceUtility.GetServiceTypes(); 
     foreach (Type st in serviceTypes) 
     { 
      string route = String.Format("Services/{0}.svc", ServiceUtility.GetServiceName(st)); 
      RouteTable.Routes.Add(new ServiceRoute(route, new RoutingServiceHostFactory(st), typeof(System.ServiceModel.Routing.RoutingService))); 
     } 
    } 

सेवा उपयोगिता और रूटिंग सेवाहोस्ट फैक्ट्री कस्टम कक्षाएं हैं। ध्यान दें कि IPolicyService विधानसभा कि मैं में दिलचस्पी रखता हूँ में एक WCF सेवा अनुबंध इंटरफेस है।

public static class ServiceUtility 
{ 
    public static List<Type> GetServiceTypes() 
    { 
     Type policyInterfaceType = typeof(IPolicyService); 
     Assembly serviceContractsAssembly = Assembly.GetAssembly(policyInterfaceType); 
     Type[] serviceContractsAssemblyTypes = serviceContractsAssembly.GetTypes(); 

     List<Type> serviceTypes = new List<Type>(); 
     foreach (Type t in serviceContractsAssemblyTypes) 
     { 
      if (!t.IsInterface) 
       continue; 

      object[] attrib = t.GetCustomAttributes(typeof(ServiceContractAttribute), false); 
      if (attrib == null || attrib.Length <= 0) 
       continue; 

      serviceTypes.Add(t); 
     } 

     return serviceTypes; 
    } 

    // Other stuff 
} 

मैं अपने ServiceHosts पैदा कर रहा हूँ इस प्रकार है। मैंने ब्रेवटी के लिए अपने कुछ सहायक तरीकों को छोड़ दिया है।

public class RoutingServiceHostFactory : ServiceHostFactory 
{ 
    private Type BackendServiceType { get; set; } 
    private Binding BackendServiceBinding { get; set; } 

    public RoutingServiceHostFactory(Type backendServiceType) 
    { 
     this.BackendServiceType = backendServiceType; 
     this.BackendServiceBinding = ServiceUtility.GetBinding(this.BackendServiceType); 
    } 

    private const string DOMAIN_LIVE = "http://localhost:2521/"; 
    private const string DOMAIN_DEAD_1 = "http://localhost:2522/"; 
    private const string DOMAIN_DEAD_2 = "http://localhost:2524/"; 
    private const string DOMAIN_DEAD_3 = "http://localhost:2525/"; 
    private const string DOMAIN_DEAD_4 = "http://localhost:2526/"; 
    private const string DOMAIN_DEAD_5 = "http://localhost:2527/"; 

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
    { 
     ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses); 

     this.BindEndpoints(host, baseAddresses); 
     this.ConfigureRoutingBehavior(host); 
     this.ConfigureServiceMetadataBehavior(host); 
     this.ConfigureDebugBehavior(host); 

     host.Description.Behaviors.Add(new RoutingServiceErrorHandlerInjector()); 

     return host; 
    } 

    // Other Stuff 

    private void ConfigureRoutingBehavior(ServiceHost host) 
    { 
     string deadAddress1 = ServiceUtility.GetServiceUrl(DOMAIN_DEAD_1, this.BackendServiceType); 
     string deadAddress2 = ServiceUtility.GetServiceUrl(DOMAIN_DEAD_2, this.BackendServiceType); 
     string deadAddress3 = ServiceUtility.GetServiceUrl(DOMAIN_DEAD_3, this.BackendServiceType); 
     string deadAddress4 = ServiceUtility.GetServiceUrl(DOMAIN_DEAD_4, this.BackendServiceType); 
     string deadAddress5 = ServiceUtility.GetServiceUrl(DOMAIN_DEAD_5, this.BackendServiceType); 
     string realAddress = ServiceUtility.GetServiceUrl(DOMAIN_LIVE, this.BackendServiceType); 

     RoutingConfiguration rc = new RoutingConfiguration(); 

     ContractDescription contract = new ContractDescription("IRequestReplyRouter"); 
     ServiceEndpoint deadDestination1 = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(deadAddress1)); 
     ServiceEndpoint deadDestination2 = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(deadAddress2)); 
     ServiceEndpoint deadDestination3 = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(deadAddress3)); 
     ServiceEndpoint deadDestination4 = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(deadAddress4)); 
     ServiceEndpoint deadDestination5 = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(deadAddress5)); 
     ServiceEndpoint realDestination = new ServiceEndpoint(contract, this.BackendServiceBinding, new EndpointAddress(realAddress)); 

     List<ServiceEndpoint> backupList = new List<ServiceEndpoint>(); 
     backupList.Add(deadDestination1); 
     backupList.Add(deadDestination2); 
     backupList.Add(deadDestination3); 
     backupList.Add(deadDestination4); 
     backupList.Add(deadDestination5); 
     backupList.Add(realDestination); 

     rc.FilterTable.Add(new MatchAllMessageFilter(), backupList); 

     RoutingBehavior rb = new RoutingBehavior(rc); 

     host.Description.Behaviors.Add(rb);    
    } 

    // Other Stuff 
} 

पोर्ट 2521 में दूसरी तरफ एक वास्तविक वेबसाइट है जो कुछ डब्ल्यूसीएफ सेवाओं की मेजबानी कर रही है। उपरोक्त संदर्भित अन्य बंदरगाहों में कुछ भी नहीं सुन रहा है।

संदर्भ के लिए, यहां रूटिंग साइट के लिए मेरा web.config है। ध्यान दें कि टाइम-आउट और ऐसे ही मेरे आसपास घूमने का नतीजा है, उन्हें बहुत गंभीरता से न लें।

<?xml version="1.0"?> 
<configuration> 
    <system.web> 
    <compilation debug="true" targetFramework="4.0" /> 
    </system.web> 

    <system.serviceModel> 
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />  
    <bindings> 
     <wsHttpBinding> 
     <binding 
      name="TestBinding" 
      allowCookies="True" 
      closeTimeout="00:04:00" 
      openTimeout="00:00:10" 
      receiveTimeout="00:05:00" 
      sendTimeout="00:05:00" 
      maxReceivedMessageSize="15728640"> 
      <security> 
      <message establishSecurityContext="true" /> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    </system.serviceModel> 
</configuration> 

संपादित

नीचे TheDoctor के जवाब के जवाब में, मैंने सोचा कि मैं मैं इस प्रयास किया समाधान के साथ क्या करते रहे हैं के बाद से मैं मूल रूप से तैनात पर विस्तार करना चाहिए। मैंने आईरर हैंडलर इंटरफ़ेस को कार्यान्वित करने का प्रयास किया है। हालांकि, मुझे इसके साथ बहुत भाग्य नहीं मिला है।

ध्यान दें कि ऊपर दिए गए उदाहरण में, मेरी रूटिंग सेवाहोस्ट फैक्ट्री थोड़ा बदल गई है। अब मैं सेवा विवरण में RoutingServiceErrorHandlerInjector व्यवहार को जोड़ रहा हूं। ध्यान दें कि मैंने चित्रण के उद्देश्य के लिए अपनी बैकअप सूची में अतिरिक्त मृत अंतराल भी जोड़े हैं।

public class RoutingServiceErrorHandlerInjector : IServiceBehavior 
{ 
    #region IServiceBehavior Members 

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 

    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) 
    { 
     foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers) 
     { 
      chanDisp.ErrorHandlers.Add(new RoutingServiceErrorHandler()); 
     } 
    } 

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) 
    { 

    } 

    #endregion 
} 

public class RoutingServiceErrorHandler : IErrorHandler 
{ 
    #region IErrorHandler Members 

    public bool HandleError(Exception error) 
    { 
     throw new NotImplementedException(error.Message, error); 

    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     throw new NotImplementedException(error.Message, error); 
    } 

    #endregion 
} 

मेरे उम्मीद थी कि मैं एक ProvideFault या deadDestination5 के माध्यम से deadDestination1 के लिए एक HandleError घटना सक्रिय होना चाहिए। मेरे डीबगर में उपरोक्त NotImplementedExceptions पर मेरे पास ब्रेकपॉइंट्स हैं। लेकिन वह कोड कभी भी सक्रिय नहीं किया गया है। कॉल अंततः इसे बैकअप सूची के अंत में वास्तविक पते के माध्यम से बनाते हैं, और क्लाइंट/सर्वर एप्लिकेशन जिसका उपयोग मैं इस रूटिंग सेवा का परीक्षण करने के लिए कर रहा हूं ठीक है। संचार धीमा है लेकिन अभी भी समय सीमा के भीतर अच्छी तरह से है।

हालांकि, अगर मैं उपरोक्त कॉन्फ़िगररआउटिंग व्यवहार विधि से backupList.Add(realDestination); लाइन को टिप्पणी करता हूं, तो रूटिंग सेवा सर्विसर। एंड्रॉइड.प्रोवाइडफॉल्ट विधि का अभ्यास किया जाता है ... लेकिन इसमें केवल DeadDestination5 से संबंधित जानकारी शामिल है। DeadDestination4 के माध्यम से deadDestination1 के लिए जेनरेट किए गए किसी भी अपवाद या त्रुटियां बस मुझ पर गायब हो जाती हैं।

इसके अलावा, मुझे RoutingService के लिए परावर्तित कोड के माध्यम से RedGate डीबगर चरणबद्ध करने के साथ जाना पड़ा है। यह मेरे लिए मुश्किल था क्योंकि मुझे अनुकूलित कोड डीबग करने के लिए उपयोग नहीं किया जाता है, इसलिए वास्तव में पढ़ने के लिए मेरे लिए कोई भी चर उपलब्ध नहीं था। लेकिन नीचे तर्क के stepthrough eyeballing से: System.ServiceModel.Routing.ProcessRequestAsyncResult से

// This has been taken from System.ServiceModel.Routing.RoutingService 
// via the RedGate decompiler - unsure about it's ultimate accuracy. 
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed), ServiceBehavior(AddressFilterMode=AddressFilterMode.Any, InstanceContextMode=InstanceContextMode.PerSession, UseSynchronizationContext=false, ValidateMustUnderstand=false)] 
public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter, IDisposable 
{ 
    [OperationBehavior(Impersonation=ImpersonationOption.Allowed), TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 
    IAsyncResult IRequestReplyRouter.BeginProcessRequest(Message message, AsyncCallback callback, object state) 
    { 
     return this.BeginProcessRequest<IRequestReplyRouter>(message, callback, state); 
    } 

    private IAsyncResult BeginProcessRequest<TContract>(Message message, AsyncCallback callback, object state) 
    { 
     IAsyncResult result; 
     try 
     { 
      System.ServiceModel.Routing.FxTrace.Trace.SetAndTraceTransfer(this.ChannelExtension.ActivityID, true); 
      result = new ProcessRequestAsyncResult<TContract>(this, message, callback, state); 
     } 
     catch (Exception exception) 
     { 
      if (TD.RoutingServiceProcessingFailureIsEnabled()) 
      { 
       TD.RoutingServiceProcessingFailure(this.eventTraceActivity, OperationContext.Current.Channel.LocalAddress.ToString(), exception); 
      } 
      throw; 
     } 
     return result; 
    } 
} 

प्रासंगिक वर्गों में नीचे दिखाया गया। ये RedGate के माध्यम से डीबगिंग से भी हैं, इसलिए संशोधित नहीं कर सकते हैं। मुझे विश्वास है कि रेडगेट और माइक्रोसॉफ्ट से जारी स्रोत सटीक हैं। #hesaiddubiously

internal class ProcessRequestAsyncResult<TContract> : TransactedAsyncResult 
{   
    public ProcessRequestAsyncResult(RoutingService service, Message message, AsyncCallback callback, object state) : base(callback, state) 
    { 
     this.allCompletedSync = true; 
     this.service = service; 
     this.messageRpc = new System.ServiceModel.Routing.MessageRpc(message, OperationContext.Current, service.ChannelExtension.ImpersonationRequired); 
     if (TD.RoutingServiceProcessingMessageIsEnabled()) 
     { 
      TD.RoutingServiceProcessingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, message.Headers.Action, this.messageRpc.OperationContext.EndpointDispatcher.EndpointAddress.Uri.ToString(), (this.messageRpc.Transaction != null) ? "True" : "False"); 
     } 
     try 
     { 
      EndpointNameMessageFilter.Set(this.messageRpc.Message.Properties, service.ChannelExtension.EndpointName); 
      this.messageRpc.RouteToSingleEndpoint<TContract>(this.service.RoutingConfig); 
     } 
     catch (MultipleFilterMatchesException exception) 
     { 
      throw System.ServiceModel.Routing.FxTrace.Exception.AsError(new ConfigurationErrorsException(System.ServiceModel.Routing.SR.ReqReplyMulticastNotSupported(this.messageRpc.OperationContext.Channel.LocalAddress), exception)); 
     } 
     while (this.StartProcessing()) 
     { 
     } 
    } 

    private bool StartProcessing() 
    { 
     bool flag = false; 
     SendOperation operation = this.messageRpc.Operations[0]; 
     this.currentClient = this.service.GetOrCreateClient<TContract>(operation.CurrentEndpoint, this.messageRpc.Impersonating); 
     if (TD.RoutingServiceTransmittingMessageIsEnabled()) 
     { 
      TD.RoutingServiceTransmittingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, "0", this.currentClient.Key.ToString()); 
     } 
     try 
     { 
      Message message; 
      if ((this.messageRpc.Transaction != null) && operation.HasAlternate) 
      { 
       throw System.ServiceModel.Routing.FxTrace.Exception.AsError(new ConfigurationErrorsException(System.ServiceModel.Routing.SR.ErrorHandlingNotSupportedReqReplyTxn(this.messageRpc.OperationContext.Channel.LocalAddress))); 
      } 
      if (operation.AlternateEndpointCount > 0) 
      { 
       message = this.messageRpc.CreateBuffer().CreateMessage(); 
      } 
      else 
      { 
       message = this.messageRpc.Message; 
      } 
      operation.PrepareMessage(message); 
      IAsyncResult result = null; 
      using (base.PrepareTransactionalCall(this.messageRpc.Transaction)) 
      { 
       using (IDisposable disposable = null) 
       { 
        try 
        { 
        } 
        finally 
        { 
         disposable = this.messageRpc.PrepareCall(); 
        } 
        result = this.currentClient.BeginOperation(message, this.messageRpc.Transaction, base.PrepareAsyncCompletion(ProcessRequestAsyncResult<TContract>.operationCallback), this); 
       } 
      } 
      if (!base.CheckSyncContinue(result)) 
      { 
       return flag; 
      } 
      if (this.OperationComplete(result)) 
      { 
       base.Complete(this.allCompletedSync); 
       return flag; 
      } 
      return true; 
     } 
     catch (Exception exception) 
     { 
      if (Fx.IsFatal(exception)) 
      { 
       throw; 
      } 
      if (!this.HandleClientOperationFailure(exception)) 
      { 
       throw; 
      } 
      return true; 
     } 
    } 
} 

मेरी सतही पढ़ने के लिए, पर मुझे ऐसा लगता है कि ProcessRequestAsyncResult ProcessRequestAsyncResult.StartProcessing विधि के माध्यम से बैकअप सूची के माध्यम से कदम का काम कर रही है। हालांकि, StartProcess() प्रत्येक अपवाद को फेंकने वाला प्रतीत नहीं होता है, बल्कि यह चुनिंदा चुनता है कि अपवाद फेंकना है या नहीं।

ऐसा लगता है कि अंतिम मृत पते के लिए केवल अपवाद को वास्तव में StartProcess() द्वारा फेंक दिया जा रहा है, फिर RoutingService.BeginProcessRequest कैच क्लॉज द्वारा पारित किया गया है, केवल अंततः इसे मेरे आईरर हैंडलर में सक्रियण के लिए सभी तरह से बनाते हैं कार्यान्वयन।

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

लेकिन फिर, ध्यान दें कि यह सतही पढ़ने है। मैं आसानी से गलत हो सकता था। वास्तव में, मैं बहुत अधिक गलत साबित करना चाहता हूं। मैं रूटिंग सेवा को ऐसा करने के लिए एक तरीका ढूंढना पसंद करूंगा जो मैं खुद को रोल करने के बजाय करना चाहता हूं।

उत्तर

0

डब्ल्यूसीएफ त्रुटि प्रबंधन (http://msdn.microsoft.com/en-us/library/ee517422.aspx) प्रदान करता है, ताकि आप एक ऐसा फ़ंक्शन बना सकें जो CommunicationException (http://msdn.microsoft.com/en-us/library/system.servicemodel.communicationexception.aspx) पर सक्रिय हो और फ़ंक्शन में पास किए गए डेटा से त्रुटि कोड लॉग कर सके। आप वहां से मेल रूटिंग सेवा और जो कुछ भी आपको चाहिए, वहां जा सकते हैं।

+0

बैकअप सूची में प्रत्येक एंडपॉइंट के लिए प्रत्येक अपवाद को कैसे पहुंचाया जा सकता है? –

+0

इस अपवाद को पकड़ने के लिए अब तक मेरे प्रयासों को दिखाने के लिए प्रश्न के लिए कुछ अतिरिक्त जानकारी में जोड़ा गया है। –

+0

@ डैनियल, ऐसा लगता है कि कोड का अंतिम भाग केवल अपवादों को संभालता है जो घातक हो सकते हैं या जो अनचाहे हो सकते हैं। – TheDoctor

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