When I put my thrift client reference in a using block I get a TTransportException : "Cannot read, Remote side has closed exception."
//THRIFT IDL
namespace csharp ReferenceData.API
exception EntityDoesNotExistException {
1: string Key;
}
service ReferenceDataService {
bool HelloWorld() throws (1: EntityDoesNotExistException entityDoesNotExistException);
}
namespace Server
{
public class Service: ReferenceDataService.Iface
{
public bool HelloWorld()
{
throw new EntityDoesNotExistException(){Key = "TEST KEY"};
}
}
}
namespace Server
{
class Program
{
static void Main(string[] args)
{
try
{
var processor = new ReferenceData.API.ReferenceDataService.Processor(new Service());
TServerTransport serverTransport = new TServerSocket(9094);
TServer server = new TThreadedServer(processor, serverTransport);
Console.WriteLine("Running the Payroll Service on port {0}...", "9094");
server.Serve();
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace);
}
Console.ReadLine();
}
}
}
namespace Client
{
class Program
{
static void Main(string[] args)
{
var transport = new Thrift.Transport.TSocket("127.0.0.1", 9094);
transport.Open();
var service = new ReferenceDataService.Client(new Thrift.Protocol.TBinaryProtocol(transport));
using (service)
{
try
{
service.HelloWorld();
}
catch (EntityDoesNotExistException ex)
{
Console.WriteLine(ex.Key);
}
}
Console.ReadLine();
}
}
}
The remote method call actually succeeds but I have observed that the Processor.Process method is called twice and it is the second call that triggers the exception. Should the Process method be called twice? Should I be explicitly calling Dispose like this, I assumed that I should in order to close the socket as soon as possible.
The behaviour is by design.
The Process() method is called until the connection ends, typically because the client disconnects. In that case, ReadMessageBegin() fails with this exception which is expected and caught in TThreadedServer.cs, right below the Process() loop.
For the curious: The exception is thrown in TTransport.ReadAll()
Related
This question already has an answer here:
Why Dispose is not called even with using-statement?
(1 answer)
Closed 5 months ago.
Below my code example. Why tom.Dispose() method doesn't called (I don't see message in console) despite it is in using block?
class Program
{
static void Main()
{
using (Person tom = new Person("Tom"))
{
Console.WriteLine($"Name: {tom.Name}");
try
{
dynamic result = new ExpandoObject();
result.d = 1;
Console.WriteLine(result.a.b);
}
catch (Exception)
{
throw;
}
}
}
}
public class Person : IDisposable
{
public string Name { get; }
public Person(string name) => Name = name;
public void Dispose() => Console.WriteLine($"{Name} has been disposed");
}
upd: if I modify catch block to below, tom.Dispose() is called
catch (Exception)
{
if (tom != null)
tom.Dispose();
throw;
}
The object gets disposed properly. The way the code is written, the exception is rethrown and never handled and the application terminates before it has a chance to write to the console.
This snippet does print the message:
static void Main()
{
try
{
using (Person tom = new Person("Tom"))
{
Console.WriteLine($"Name: {tom.Name}");
dynamic result = new ExpandoObject();
result.d = 1;
Console.WriteLine(result.a.b);
}
}
catch(Exception){}
}
This produces :
Name: Tom
Tom has been disposed
For a few months now I have been using the ktor framework to create servers that expose rest calls and communication via webSockets. For now I have always used clients using kotlin as a programming language (or Android App, or App Desktop).
Specifically, I had a class that was injected with the HttpClient object (from the documentation = Asynchronous client to perform HTTP requests).
Within this class I have 4 methods:
start the session: instantiate the WebSocketSession object (Represents a web socket session between two peers)
send Frame
receives Frame
close the session
In Ktor my class is something that looks a lot like this:
class WebSocketServiceImpl(
private val client: HttpClient
){
private var socket: WebSocketSession? = null
//1)
suspend fun initSession(username: String): Resource<Unit>{
socket = client.webSocketSession {
url("ws://xxx.xxx.xxx.xxx:xxxx/myRoute?username=$username")
}
//2)
suspend fun send(myObj: MyObj) {
try {
val myObjSerialized = Json.encodeToString(myObj)
socket?.send(Frame.Text(myObjSerialized ))
} catch (e: Exception) {
e.printStackTrace()
}
}
//3)
fun observePrintableMessages(): Flow<MyObj> {
return try {
socket?.incoming
?.receiveAsFlow()
?.filter { it is Frame.Text }
?.map {
val myObjString = (it as? Frame.Text)?.readText() ?: ""
val printableMessageDto = Json.decodeFromString<MyObj>(myObjString)
} ?: flow { }
} catch (e: Exception) {
e.printStackTrace()
flow { }
}
}
//4)
suspend fun closeSession() {
socket?.close()
}
}
From the C # documentation instead, I found these examples on how to use Client-side WebSockets:
//1)
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", "protocolOne");
//2)
exampleSocket.send("Here's some text that the server is urgently awaiting!");
//3)
exampleSocket.onmessage = (event) => {
console.log(event.data);
}
//4)
exampleSocket.close();
Admitted and not granted that the methods I found in C # really work, to make the WebSocket object used in C # be equivalent to the WebSocketSession object in Kotlin is enough for me to do so? :
public void initSession(string username)
{
exampleSocket = new WebSocket($"wss://www.example.com/socketserver?username={username}", "");
}
Or is it some other type of object to use?
If for any reason you don't know the answer, you don't need to vote negative, you can just move on.
I used the Websocket.Client library (by Mariusz Kotas) found on NuGet
public class WebSocketService : IWebSocketService
{
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
private void FireMessageReceivedEvent(Message message) => MessageReceived?.Invoke(this, new MessageReceivedEventArgs(message));
public string Url { get => "ws://192.168.1.202:8082/chat-socket"; }
private WebsocketClient webSocketClient;
public async Task<SessionResoult> InitSession(string username)
{
string usernameSession = $"?username={username}";
string urlWithUsername = $"{Url}{usernameSession}";
try
{
webSocketClient = new WebsocketClient(new Uri(urlWithUsername));
await webSocketClient.Start();
if (webSocketClient.IsRunning)
{
SubscribeNewMessages();
return new SessionResoult.Success();
}
else
{
return new SessionResoult.Error("webSocketClient is not running");
}
}
catch(Exception ex)
{
return new SessionResoult.Error(ex.Message);
}
}
private void SubscribeNewMessages()
{
webSocketClient.MessageReceived.Subscribe(m =>
{
MessageDto message = JsonConvert.DeserializeObject<MessageDto>(m.Text);
FireMessageReceivedEvent(message.ToMessage());
});
}
public async Task SendMessageAsync(string message)
{
await Task.Run(() => webSocketClient.Send(message));
}
public void CloseSession()
{
webSocketClient.Dispose();
}
}
In the code, the interesting parts are:
1) initialization of the WebsocketClient object
2) the subscription of receiving messages ( Start() method immediately after initialization)
3) observation of message subscription -> webSocketClient.MessageReceived.Subscribe
4) the 'Fire' of the event linked to the observation of messages -> FireMessageReceivedEvent
5) those who use the class must subscribe to the event of the latter ->
webSocketService.MessageReceived + = (sender, e) => {OnMessageReceived (e.MessageReceived); };
MessageReceivedEventArgs -> Class describing the Arguments of the event
SessionResoult -> Class similar to an Enum but with the possibility of passing a string or not based on which subclass it is
I have a problem when trying to consume a server implementation of MessagePack RPC. I wrote one implementation for client and one for server based on a Python code provided by my company's client.
The server implementation should be consumed by Python, but as far as I see that won't be a problem.
Server implementation:
public class Program
{
static void Main(string[] args)
{
try
{
DefaultServiceTypeLocator def = new DefaultServiceTypeLocator();
ServiceTypeLocator ser = def;
def.AddService(new Methods().GetType());
var services = ser.FindServices();
var configuration = new RpcServerConfiguration();
IPAddress ipAddress = GetIp();
configuration.BindingEndPoint = new IPEndPoint(ipAddress, 8089);
Console.WriteLine(new IPEndPoint(ipAddress, 8089).ToString());
using (var server = new RpcServer(configuration))
{
server.Start();
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.Write(ex);
Console.ReadKey();
}
}
[MessagePackRpcServiceContractAttribute]
public class Methods
{
[MessagePackRpcMethodAttribute]
public int hello0()
{
Console.WriteLine("hello0");
return 0;
}
}
Client implementation:
public class Program
{
static void Main(string[] args)
{
try
{
var configuration = new RpcClientConfiguration();
IPAddress ipAddress = GetIp();
using (dynamic proxy = new DynamicRpcProxy(new IPEndPoint(ipAddress, 8089), configuration))
{
dynamic res = proxy.hello0();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
}
private static IPAddress GetIp()
{
string myHost = System.Net.Dns.GetHostName();
IPAddress myIP = null;
for (int i = 0; i <= System.Net.Dns.GetHostEntry(myHost).AddressList.Length - 1; i++)
{
if (System.Net.Dns.GetHostEntry(myHost).AddressList[i].IsIPv6LinkLocal == false)
{
if (System.Net.Dns.GetHostEntry(myHost).AddressList[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
myIP = System.Net.Dns.GetHostEntry(myHost).AddressList[i];
}
}
return myIP;
}
}
My client can't connect to my server, it can't see the methods over there. The error is: "operation does not exist".
Anyone has any clue?
Thank you!!
Well after many tries and many help from friends, I finally managed to fix the issue.
First of all you have to download the Message Pack RPC solution here and create your new project (server or client) inside this solution. In my case the server didn’t work when I created a new solution and referenced the dlls, only inside the whole project. The client worked only referencing the dlls.
Implementation for the Server Side:
internal class Program
{
public static void Main(string[] args1)
{
var config = new RpcServerConfiguration();
config.BindingEndPoint = new IPEndPoint(IPAddress.Loopback, 8089);
config.PreferIPv4 = true;
config.IsDebugMode = true;
//UseFullMethodName is a property that if it is false allows you in the CLIENT to call the methods only by it's name, check example further.
config.UseFullMethodName = false;
var defaultServiceTypeLocator = new DefaultServiceTypeLocator();
//Methods is the class I created with all the methods to be called.
defaultServiceTypeLocator.AddService(typeof(Methods));
config.ServiceTypeLocatorProvider = conf => defaultServiceTypeLocator;
using (var server = new RpcServer(config))
{
server.Start();
Console.ReadKey();
}
}
[MessagePackRpcServiceContract] //Define the contract to be used
public class Methods
{
[MessagePackRpcMethod] //Define the methods that are going to be exposed
public string Hello()
{
return "Hello";
}
[MessagePackRpcMethod]
public string HelloParam(string i)
{
return "Hello " + i;
}
}
Implementation for the Client Side:
static void Main(string[] args)
{
using (var target = CreateClient())
{
//var result1 = target.Call("Hello:Methods:0", null); /*if in the server the property UseFullMethodName is true, or not defined as false (default is true) you have to call the method on the server using *methodname:class:version**/
var result2 = target.Call("Hello", null); //Parameter is null
var result3 = target.Call("HelloParam", “Mariane”);//Method with parameter
}
}
public static RpcClient CreateClient()
{
return new RpcClient(new IPEndPoint(IPAddress.Loopback, 8089), new RpcClientConfiguration() { PreferIPv4 = true });
}
I hope this is clear and help you guys to fix it. Don’t forget to set the methods as public on the server. Thanks to https://github.com/yfakariya /msgpack-rpc-cli/issues/6 that answered my question. Really special thanks to #DanielGroh that spent some time with me trying to fix it and Gilmar Pereira which has no profile here but is a great developer and helped me a lot (https:// www. facebook .com/ gilmarps?fref=ts).
1.) From a .net client, how do I test if the client is connected to the server (i.e. can send and receive) Yes, I could send a message inside a try block and catch the ensuing exception but I'm hoping for a more elegant solution.
2) How do I open, close, and re-open connections? In my attempts to resolve question 1 above I discovered that if I open a connection then call connection.Close() I am not able to obtain another connection from the connection factory (see code fragment below). I receive error message XMSCC0008
I am using a very standard vanilla MQ configuration . Here is how my client connects:
ISession session = MQAccess.GetSession(MQAccess.Connection);
IDestination destination = session.CreateTopic(SubTopicName);
Consumer = MQAccess.GetConsumer(session, destination);
Consumer.MessageListener = new MessageListener(HandleMQSubEvent);
MQAccess.Connection.Start();
where MQAccess is a small utility class.
Edited the question to add MQAccess code:
public static class MQAccess
{
public static readonly MQConfigurationSectionHandler ConfigSettings;
public static readonly IConnectionFactory ConnectionFactory;
private static readonly IConnection connection;
public static IConnection Connection
{
get { return connection; }
}
static MQAccess()
{
ConfigSettings = (MQConfigurationSectionHandler)
ConfigurationManager.GetSection("mq-configuration");
XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
ConnectionFactory = factory.CreateConnectionFactory();
ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname);
ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port);
ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel);
if (ConfigSettings.QueueManager == string.Empty)
{
ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "");
}
else
{
ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager);
}
connection = GetConnection();
}
public static IConnection GetConnection()
{
return ConnectionFactory.CreateConnection();
}
public static ISession GetSession(IConnection connection)
{
return connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
}
public static IMessageProducer GetProducer(ISession session, IDestination destination)
{
return session.CreateProducer(destination);
}
public static IMessageConsumer GetConsumer(ISession session, IDestination destination)
{
return session.CreateConsumer(destination);
}
public static void MQPub(string TopicURI, string message)
{
using (var session = GetSession(Connection))
{
using (var destination = session.CreateTopic(TopicURI))
{
using (var producer = GetProducer(session, destination))
{
producer.Send(session.CreateTextMessage(message));
}
}
}
}
public static void MQPub(string TopicURI, IEnumerable<string> messages)
{
using (var session = GetSession(Connection))
{
using (var destination = session.CreateTopic(TopicURI))
{
using (var producer = GetProducer(session, destination))
{
foreach (var message in messages)
{
producer.Send(session.CreateTextMessage(message));
}
}
}
}
}
}
Edit: Renamed MQAccess class to MQClient. Made it an instance class per T Rob suggestion. Disconnect method still crashes with error msgs listed above
public class MQClient : IDisposable
{
public MQConfigurationSectionHandler ConfigSettings { get; private set; }
public IConnectionFactory ConnectionFactory { get; private set; }
public IConnection Connection { get; private set; }
public IMessageConsumer Consumer { get; private set; }
public IMessageProducer Producer { get; private set; }
// Save sessions as fields for disposing and future subscription functionality
private ISession ProducerSession;
private ISession ConsumerSession;
public string SubTopicName { get; private set; }
public string PubTopicName { get; private set; }
public bool IsConnected { get; private set; }
public event Action<Exception> ConnectionError;
private Action<IMessage> IncomingMessageHandler;
public MQClient(string subTopicName, string pubTopicName, Action<IMessage> incomingMessageHandler)
{
// Dont put connect logic in the constructor. If we lose the connection we may need to connect again.
SubTopicName = subTopicName;
PubTopicName = pubTopicName;
IncomingMessageHandler = incomingMessageHandler;
}
public string Connect()
{
IsConnected = false;
string errorMsg = string.Empty;
ConfigSettings = (MQConfigurationSectionHandler)
ConfigurationManager.GetSection("mq-configuration");
XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
ConnectionFactory = factory.CreateConnectionFactory();
ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname);
ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port);
ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel);
if (ConfigSettings.QueueManager == string.Empty)
ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "");
else
ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager);
Connection = ConnectionFactory.CreateConnection();
if (!string.IsNullOrEmpty(PubTopicName))
{
ProducerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
Producer = ProducerSession.CreateProducer(ProducerSession.CreateTopic(PubTopicName));
}
if (!string.IsNullOrEmpty(SubTopicName) && IncomingMessageHandler != null)
{
ConsumerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
Consumer = ConsumerSession.CreateConsumer(ConsumerSession.CreateTopic(SubTopicName));
Consumer.MessageListener = new MessageListener(IncomingMessageHandler);
}
try
{
Connection.Start();
Connection.ExceptionListener = new ExceptionListener(ConnectionExceptionHandler);
IsConnected = true;
}
catch (TypeInitializationException ex)
{
errorMsg = "A TypeInitializationException error occured while attempting to connect to MQ. Check the Queue configuration in App.config. The error message is: " + ex.Message;
}
catch (IllegalStateException ex)
{
errorMsg = "An IllegalStateException error occured while attempting to connect to MQ. Check the Queue configuration in App.config. The error message is: " + ex.Message;
}
return errorMsg;
}
public void Disconnect()
{
if (Producer != null)
{
Producer.Close();
Producer.Dispose();
Producer = null;
}
if (ProducerSession != null)
{
// Call Unsubscribe here if subscription is durable
ProducerSession.Close();
ProducerSession.Dispose();
ProducerSession = null;
}
if (Connection != null)
{
Connection.Stop();
//if (Connection.ExceptionListener != null)
// Connection.ExceptionListener = null;
// Per Shashi............
//if (Consumer.MessageListener != null)
// Consumer.MessageListener = null;
Connection.Close();
Connection.Dispose();
Connection = null;
}
if (Consumer != null)
{
if (Consumer.MessageListener != null)
Consumer.MessageListener = null;
Consumer.Close();
Consumer.Dispose();
Consumer = null;
}
if (ConsumerSession != null)
{
// Call Unsubscribe here if subscription is durable
ConsumerSession.Close();
ConsumerSession.Dispose();
ConsumerSession = null;
}
IsConnected = false;
}
public void Publish(string message)
{
Producer.Send(ProducerSession.CreateTextMessage(message));
}
public void Publish(string[] messages)
{
foreach (string msg in messages)
Publish(msg);
}
public void ConnectionExceptionHandler(Exception ex)
{
Disconnect(); // Clean up
if (ConnectionError != null)
ConnectionError(ex);
}
#region IDisposable Members
private bool disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
Disconnect();
disposed = true;
}
}
#endregion
}
The problem is here --> where MQAccess is a small utility class.
The first part of the question asks how to tell if the connection is active. The XMS classes for WebSphere MQ are an implementation of the JMS specification for non-Java platforms. They follow the JMS spec fairly closely and the JMS spec does not have a method on the connection or session equivalent to isConnected therefore neither does XMS. However, all GET and PUT activity should occur within a try/catch block in order to catch the JMS exceptions. (From which you always print the linkedException, right?) When a JMS exception is thrown the app either treats it as fatal and dies or else it closes all JMS objects except for the Connection Factory, waits a few seconds and then re-drives the connection sequence.
UPDATE based on new info in the question:
Thanks for posting the MQAccess class. This provides considerable insight into what's happening, although there still isn't any code showing where the connection is closed and reopened as per Part #2 of the question.
However, the code shows that the MQAccess class creates a private instance of ICONNECTION connection as the class instance is constructed, which is then exposed publicly as MQAccess.GetConnection. The MQAccess class as currently posted has no public or private class method that would ever replace the connection handle held by connection so if MQAccess.Connection.Close() is ever called, that IConnection object instance within the MQAccess class will forever after hold an invalid connection handle. Once the connection is closed, that instance of MQAccess is effectively dead. You'd have to delete and reinstantiate MQAccess to get a new connection.
The MQAccess class does expose the connection factory publicly so in theory it would be possible to call MQAccess.GetConnection from outside the class and obtain a valid new IConnection object, even after closing the original one. However, that instance would exist outside the scope of the MQAccess class and thus any subsequent calls to MQAccess would refer to its defunct instance variable connection rather than the new connection instance created outside the class.
If you need to close and recreate connections, you might consider managing that from inside of MQAccess. A low-tech approach might be to write an MQAccess.Close() method for the connection which would close the existing connection then immediately call connection = GetConnection(); so that the private connection variable always holds a valid connection handle.
If this doesn't resolve the problem, please post the code that is closing and recreating the connections.
By the way, the non-transacted session over a network connection opens the possibility to lose or duplicate messages for any JMS provider, including WMQ. Was this what you intended? I've explained why this is in an other SO post here.
Adding to comments from T.Rob.
Question 1:
I hope you have access to source code of MQAccess. If yes, you could expose a property in MQAccess that indicates whether a connection is active or not. If you do not have access then you may have to ask the author of that class to add this property. You can do the following to set/reset the property.
1) Set the property after createConnection method returns successfully.
2) Set an Exception listener for the connection.
3) Reset the property in Exception handler. Check the reason code and reset the property if it's a connection broken error (XMSWMQ1107 and the linked exception can have MQRC 2009).
Question 2
It would help if you can show us how you are closing and reopening connections. My recommendation to close connection is:
1) First do a connection.Stop().
2) Remove any message listeners, basically do a consumer.MessageListener = null.
3) Then do connection.Close().
4) Do a connection = null
Additional Information
Here is the sample I have used to test.
private void OnException(Exception ex)
{
XMSException xmsex = (XMSException)ex;
Console.WriteLine("Got exception");
// Check the error code.
if (xmsex.ErrorCode == "XMSWMQ1107")
{
Console.WriteLine("This is a connection broken error");
stopProcessing = true; // This is a class member variable
}
}
In your method where connection is created, set the exception listener.
// Create connection.
connectionWMQ = cf.CreateConnection();
connectionWMQ.ExceptionListener = new ExceptionListener(OnException);
Whenever there is a connection error, the exception listener will be invoked and flag is set to true.
It is good a practice to dispose the objects when they are no longer required. There is parent child relation, Consumer, Producer etc are children of Session which in turn is a child of Connection. So order of disposal can be child first and parent next. But if a parent is disposed, children are also disposed automatically.
I've written an extension method for use with WCF services that keeps all the disposal and exception handling logic in one place. The method is as follows:
public static TResult CallMethod<TChannel, TResult>(
this ClientBase<TChannel> proxy,
Func<TResult> func) where TChannel : class
{
proxy.ThrowIfNull("proxy");
func.ThrowIfNull("func");
try
{
// set client credentials
return func();
}
finally
{
if (proxy != null)
{
try
{
if (proxy.State != CommunicationState.Faulted)
{
proxy.Close();
}
else
{
proxy.Abort();
}
}
catch (CommunicationException)
{
proxy.Abort();
}
catch (TimeoutException)
{
proxy.Abort();
}
catch (Exception)
{
proxy.Abort();
throw;
}
}
}
}
The method will be used like this:
public int CreateBusinessObject(BusinessObject item)
{
MyServiceClient proxy = new MyServiceClient();
return proxy.CallMethod(() => proxy.CreateBusinessObject(item));
}
My question really is whether this would be better as a static method which creates the service proxy? I'm slightly worried about my current implementation. Should the construction of the proxy be inside the try/catch? My current understanding is that if the constructor fails, there is nothing to dispose of anyway.
If the constructor fails, the entire object is in an invalid state. You should not be worried about disposing in this case.
A nice test for this is what would happen when you execute the following:
class Program
{
static void Main(string[] args)
{
using (new TestClass())
{
Console.WriteLine("In using");
}
}
class TestClass : IDisposable
{
public TestClass()
{
throw new Exception();
}
public void Dispose()
{
Console.WriteLine("Disposed");
}
}
}
The result is that the Disposing never gets reached. This is what happens when the constructor fails.