kullanarak WCF hata sözleşmesini enjekte etme Şu anda WCF arka ucuna sahip WPF uygulaması üzerinde çalışıyorum. İstisna yönetimi için bir istemci günlüğü çözümü ve bir sunucu günlüğü çözümü uyguladık ve harika çalışıyorlar, ancak bu bilgileri tel üzerinden bir araya getirmek çoğu zaman zordur. Sunucuda bir özel durum ortaya çıkarsa, istisnai bir durumla istemcide oturum açabilmem için bir istisna belirtecini telin üzerinden geçirmenin bir yolunu istedim. Bu şekilde, bir istemci hatası çekerken sorun yaşadığımda, sunucu istisnasıyla kolayca ilişkilendirebilirim.Castle Dynamic Proxy Generation
Mimarimiz hakkında biraz daha fazla bilgi vermek istiyorum ve sonra sorunumu bildireceğim.
WCF uygulamamız, servis referansı belirleme için kullanıma hazır bir yöntemdir. İstemcide dinamik proxy üretimi gerçekleştirdik. Bunu, istemci ve sunucu tarafından paylaşılan web hizmeti arabirimleri oluşturarak gerçekleştirdik ve proxy'yi oluşturmak için Castle.DynamicProxy.ProxyGenerator sınıfını ve CreateInterfaceProxyWithoutTarget yöntemini kullandık. Ek olarak CreateInterfaceProxyWithoutTarget yöntemini çağırdığımızda, bir II denetçisinin uygulanmasını belirtiriz.
FaultOperationInvoker (uygular IOperationInvoker): Bizim iz ve hata davranışı için kullanılan üç ana sınıfları vardır sunucuda olan IOperationInvoker.Invoke kullanarak hizmet yöntemi çağırmak çalışır. Eğer bir hata istisnası tipiyse, bir istisna ise, belirli bir detay türüne sahip bir arıza sözleşmesi olup olmadığını belirlemeye çalışır ve eğer öyleyse, o zaman sarın ve ardından detay bilgisi ile yeni bir hata istisnası getirin.
internal class FaultOperationInvoker : IOperationInvoker
{
IOperationInvoker innerOperationInvoker;
FaultDescription[] faults;
public FaultOperationInvoker(IOperationInvoker invoker, FaultDescription[] faults)
{
this.innerOperationInvoker = invoker;
this.faults = faults;
}
#region IOperationInvoker Members
object[] IOperationInvoker.AllocateInputs()
{
return this.innerOperationInvoker.AllocateInputs();
}
object IOperationInvoker.Invoke(object instance, object[] inputs, out object[] outputs)
{
try
{
return this.innerOperationInvoker.Invoke(instance, inputs, out outputs);
}
catch (FaultException e)
{
ServerLogger.GetLogger(instance.GetType().FullName).LogException(e, "Unhandled exception in service operation.");
//allow fault exceptions to bubble out
throw;
}
catch (Exception e)
{
Type exceptionType = e.GetType();
ServerLogger.GetLogger(instance.GetType().FullName).LogException(e, "Unhandled exception in service operation.");
//if the excpetion is serializable and there operation is tagged to support fault contracts of type WcfSerivceFaultDetail
if (faults != null && (faults.OfType<WcfServiceFaultDetail>().Any() || faults.Count(x => x.DetailType == typeof(WcfServiceFaultDetail)) > 0))
{
throw new FaultException<WcfServiceFaultDetail>(new WcfServiceFaultDetail(true, e), "Unhandled exception during web service call.", WcfFaultCustomExceptionFactory.GetFaultCodeForExceptionType(exceptionType));
}
else
{
throw new FaultException("Unhandled exception during web service call.", WcfFaultCustomExceptionFactory.GetFaultCodeForExceptionType(exceptionType));
}
}
}
FaultOperationBehavior (uygular IOperationBehavior), yukarıda tarif edilen hata işlemi invoker için gönderme işlemi invoker işaret eder.
[AttributeUsage(AttributeTargets.Method)]
public class FaultOperationBehavior : System.Attribute, IOperationBehavior
{
#region IOperationBehavior Members
void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { }
void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription,
System.ServiceModel.Dispatcher.ClientOperation clientOperation) { }
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription,
System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.Invoker = new FaultOperationInvoker(dispatchOperation.Invoker, operationDescription.Faults.ToArray());
}
void IOperationBehavior.Validate(OperationDescription operationDescription) { }
#endregion
}
ExceptionTraceBehavior IServiceBehavior uygulayan özel durumları işlemek için (ınherits Özellik, Uygular IServiceBehavior). Biz de bir sınıf (FaultOperationBehavior)
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, Inherited = true)]
public class ExceptionTraceBehavior : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var ep in serviceDescription.Endpoints)
{
foreach (var operation in ep.Contract.Operations)
{
if (operation.Behaviors.Contains(typeof(FaultOperationBehavior)))
continue;
operation.Behaviors.Add(new FaultOperationBehavior());
//Check to see if this operation description contains a wcf service fault detail operation. If it doesn't, add one.
if (operation.Faults != null && (operation.Faults.Count == 0 || operation.Faults.Count > 0 && operation.Faults.Count(x => x.DetailType == typeof(WcfServiceFaultDetail)) == 0))
{
FaultDescription faultDescription = new FaultDescription(operation.Name);
//faultDescription.Name = "WcfServiceFaultDetail";
//faultDescription.Namespace = "";
faultDescription.DetailType = typeof(WcfServiceFaultDetail);
operation.Faults.Add(faultDescription);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
hizmet arayüzleri her biri somut bir uygulama vardır vardır. Tüm hizmetlerimiz, ExceptionTrace özelliğiyle dekore edilen temel hizmet sınıfımızı da devralır.
Şimdi, arka plan bilgisi ile, işte problem. Her hizmet işleminin, WCFServiceFaultDetail ayrıntı türünde bir hata sözleşmesi olmasını istiyorum, ancak her hizmet işleminde bir FaultContract özniteliği koymak istemiyorum. ExceptionTraceBehavior uygulamasında gördüğünüz gibi, hata sözleşmesini programsal olarak nasıl ekleyeceğimi anladım ve hatayı işleme eklemek için harika çalışıyor. Operasyonda normal bir istisna tutulduğunda, uygun bir arıza sözleşmesi olduğunu ve yeni bir Hata Tasarrufu attığını görür. Ancak, istisna müşteriye geri döndüğünde, catch (FaultException fe) kodu yerine catch (FaultExcection fe) koduna girer. programlı arıza sözleşmede eklemek için kod kaldırırsanız
Ancak, ben beklendiği gibi [FaultContract (typeof (WcfServiceFaultDetail))], istemci durum yakalar her hizmet işlemi süsleyin.
Anlayabileceğim tek şey, proxy'nin bir WSDL veya başka bir meta verisinden değil, arabirimden dinamik olarak üretilmesinden ve arabirimde bir hata sözleşmesi düzenlemesinin yapılmadığından, programatik hata sözleşmemimin onurlandırılmak.Bunu göz önüne aldığımızda düşünceyle
, ben IInterceptor uygulanmasında arıza sözleşme eklemek anlamaya çalıştım ama hiçbir başarı oldu. Yani birileri bu yapmış ve bazı ayrıntılar sağlayabilir umuyorum. Herhangi bir yardım takdir edilir.
İstemci/sunucu hatası korelasyonu için, Etkinlik Kimliği Yayılımı'na baktınız mı? – Paciv
Ben yapmadım, ona bir bakacağım. Bahşiş için teşekkürler. – BernicusMaximus