Last active
July 19, 2018 16:04
-
-
Save ArseniySavin/3328f9d20202860ce5c349481c5217f0 to your computer and use it in GitHub Desktop.
WCFHelper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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