Skip to content

Instantly share code, notes, and snippets.

@ArseniySavin
Last active July 19, 2018 16:04
Show Gist options
  • Save ArseniySavin/3328f9d20202860ce5c349481c5217f0 to your computer and use it in GitHub Desktop.
Save ArseniySavin/3328f9d20202860ce5c349481c5217f0 to your computer and use it in GitHub Desktop.
WCFHelper
// Get SOAP current request
OperationContext.Curent.RequestContext.RequestMessage.ToString();
public class WcfHelper : IDisposable
{
private static WcfHelper wcf = new WcfHelper();
private static Dictionary<Type, ChannelFactory> factories = new Dictionary<Type, ChannelFactory>();
private static readonly object syncObject = new object();
public static WcfHelper Wcf
{
get
{
return wcf;
}
}
public virtual T CreateChannel<T>() where T : class
{
return CreateChannel<T>("*", null);
}
public virtual T CreateChannel<T>(string endpointConfigurationName) where T : class
{
return CreateChannel<T>(endpointConfigurationName, null);
}
public virtual T CreateChannel<T>(string endpointConfigurationName, string endpointAddress) where T : class
{
T local = GetFactory<T>(endpointConfigurationName, endpointAddress).CreateChannel();
((IClientChannel)local).Faulted += ChannelFaulted;
return local;
}
protected virtual ChannelFactory<T> GetFactory<T>(string endpointConfigurationName, string endpointAddress) where T : class
{
lock (syncObject)
{
ChannelFactory factory;
if (!factories.TryGetValue(typeof(T), out factory))
{
factory = CreateFactoryInstance<T>(endpointConfigurationName, endpointAddress);
factories.Add(typeof(T), factory);
}
return (factory as ChannelFactory<T>);
}
}
private ChannelFactory CreateFactoryInstance<T>(string endpointConfigurationName, string endpointAddress)
{
ChannelFactory factory = null;
if (!string.IsNullOrEmpty(endpointAddress))
{
factory = new ChannelFactory<T>(endpointConfigurationName, new EndpointAddress(endpointAddress));
}
else
{
factory = new ChannelFactory<T>(endpointConfigurationName);
}
factory.Faulted += FactoryFaulted;
factory.Open();
return factory;
}
private void ChannelFaulted(object sender, EventArgs e)
{
IClientChannel channel = (IClientChannel)sender;
try
{
channel.Close();
}
catch
{
channel.Abort();
}
throw new ApplicationException("Exc_ChannelFailure");
}
private void FactoryFaulted(object sender, EventArgs args)
{
ChannelFactory factory = (ChannelFactory)sender;
try
{
factory.Close();
}
catch
{
factory.Abort();
}
Type[] genericArguments = factory.GetType().GetGenericArguments();
if ((genericArguments != null) && (genericArguments.Length == 1))
{
Type key = genericArguments[0];
if (factories.ContainsKey(key))
{
factories.Remove(key);
}
}
throw new ApplicationException("Exc_ChannelFactoryFailure");
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (syncObject)
{
foreach (Type type in factories.Keys)
{
ChannelFactory factory = factories[type];
try
{
factory.Close();
continue;
}
catch
{
factory.Abort();
continue;
}
}
factories.Clear();
}
}
}
public T Call<TClient, T>(Func<TClient, T> funcCallClient) where TClient : class
{
TClient client = Wcf.CreateChannel<TClient>();
ICommunicationObject communicationObject = (ICommunicationObject)client;
try
{
return funcCallClient(client);
}
finally
{
try
{
var state = communicationObject.State;
if (communicationObject.State != CommunicationState.Faulted)
{
communicationObject.Close();
}
}
catch
{
communicationObject.Abort();
}
}
}
public void Call<TClient>(Action<TClient> funcCallClient) where TClient : class
{
TClient client = Wcf.CreateChannel<TClient>();
ICommunicationObject communicationObject = (ICommunicationObject)client;
try
{
funcCallClient(client);
}
finally
{
try
{
if (communicationObject.State != CommunicationState.Faulted)
{
communicationObject.Close();
}
}
catch
{
communicationObject.Abort();
}
}
}
public static void WcfCall<TClient>(Action<TClient> funcCallClient, Action<Exception> funcException = null) where TClient : class
{
try
{
string endpointName = GetEndpointName<TClient>();
if (String.IsNullOrEmpty(endpointName))
throw new ArgumentException(String.Format("Cannot find any endpoint name for the provided interface {0}", typeof(TClient).FullName));
ChannelFactory<TClient> factory = new ChannelFactory<TClient>(endpointName);
using (var clientChannel = (IClientChannel)factory.CreateChannel())
{
try
{
funcCallClient((TClient)clientChannel);
}
catch
{
clientChannel.Abort();
throw;
}
}
}
catch (Exception ex)
{
if (funcException != null)
funcException(ex);
else
{
BisServiceEventSource.Log.InfoServiceFailure(ex.ToString());
throw;
}
}
}
public static T WcfCall<TClient, T>(Func<TClient, T> funcCallClient, Action<Exception> funcException = null) where TClient : class
{
try
{
string endpointName = GetEndpointName<TClient>();
//if (String.IsNullOrEmpty(endpointName))
// throw new ArgumentException(String.Format("Cannot find any endpoint name for the provided interface {0}", typeof(TClient).FullName));
ChannelFactory<TClient> factory = new ChannelFactory<TClient>(String.IsNullOrEmpty(endpointName) ? "*" : endpointName);
using (var clientChannel = (IClientChannel)factory.CreateChannel())
{
try
{
return funcCallClient((TClient)clientChannel);
}
catch
{
clientChannel.Abort();
throw;
}
}
}
catch (Exception ex)
{
if (funcException != null)
funcException(ex);
else
{
BisServiceEventSource.Log.InfoServiceFailure(ex.ToString());
}
}
return default(T);
}
public static T WcfProxyCall<T, TC>(Func<TC, T> funcCallClient, Action<Exception> funcException = null) where TC : class, ICommunicationObject, new()
{
return WcfProxyCall(funcCallClient, () => { return new TC(); }, funcException);
}
public static T WcfProxyCall<T, TClient>(Func<TClient, T> funcCallClient, Func<TClient> funcCreateClient, Action<Exception> funcException = null) where TClient : class, ICommunicationObject
{
TClient client = null;
try
{
client = funcCreateClient();
return funcCallClient(client);
}
catch (FaultException ex)
{
// Do some business logic for this SOAP Fault Exception
if (funcException != null)
funcException(ex);
}
catch (CommunicationException ex)
{
// Catch this expected exception so it is not propagated further.
// Perhaps write this exception out to log file for gathering statistics...
if (funcException != null)
funcException(ex);
}
catch (TimeoutException ex)
{
// Catch this expected exception so it is not propagated further.
// Perhaps write this exception out to log file for gathering statistics...
if (funcException != null)
funcException(ex);
}
catch (Exception ex)
{
// An unexpected exception that we don't know how to handle.
// Perhaps write this exception out to log file for support purposes...
if (funcException != null)
funcException(ex);
throw;
}
finally
{
// This will:
// - be executed if any exception was thrown above in the 'try' (including ThreadAbortException); and
// - ensure that CloseOrAbortServiceChannel() itself will not be interrupted by a ThreadAbortException
// (since it is executing from within a 'finally' block)
CloseOrAbortServiceChannel(client);
// Unreference the client
client = default(TClient);
}
return default(T);
}
private static void CloseOrAbortServiceChannel(ICommunicationObject communicationObject)
{
bool isClosed = false;
if (communicationObject == null || communicationObject.State == CommunicationState.Closed)
{
return;
}
try
{
if (communicationObject.State != CommunicationState.Faulted)
{
communicationObject.Close();
isClosed = true;
}
}
catch (CommunicationException)
{
// Catch this expected exception so it is not propagated further.
// Perhaps write this exception out to log file for gathering statistics...
}
catch (TimeoutException)
{
// Catch this expected exception so it is not propagated further.
// Perhaps write this exception out to log file for gathering statistics...
}
catch (Exception)
{
// An unexpected exception that we don't know how to handle.
// Perhaps write this exception out to log file for support purposes...
throw;
}
finally
{
// If State was Faulted or any exception occurred while doing the Close(), then do an Abort()
if (!isClosed)
{
AbortServiceChannel(communicationObject);
}
}
}
private static void AbortServiceChannel(ICommunicationObject communicationObject)
{
try
{
communicationObject.Abort();
}
catch (Exception)
{
// An unexpected exception that we don't know how to handle.
// If we are in this situation:
// - we should NOT retry the Abort() because it has already failed and there is nothing to suggest it could be successful next time
// - the abort may have partially succeeded
// - the actual service call may have been successful
//
// The only thing we can do is hope that the channel's resources have been released.
// Do not rethrow this exception because the actual service operation call might have succeeded
// and an exception closing the channel should not stop the client doing whatever it does next.
//
// Perhaps write this exception out to log file for gathering statistics and support purposes...
}
}
internal static string GetEndpointName<TClient>() where TClient : class
{
return null;
}
public object Call(Func<Info.Services.IClientService, RES.Services.AgentResult> func)
{
throw new NotImplementedException();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment