Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

public class CultureContext : IDisposable

{

private readonly CultureInfo originalCulture;

public CultureContext(string culture)

{

originalCulture = CultureInfo.CurrentCulture; Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);

}

public void Dispose()

{

Thread.CurrentThread.CurrentCulture = originalCulture;

}

}

You can then use use this class to define blocks of code that execute in a specific culture.

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

using (new CultureContext("nl-NL"))

{

// Code in this block uses the "nl-NL" culture

Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 25-12-2016 00:00:00

}

using (new CultureContext("es-ES"))

{

// Code in this block uses the "es-ES" culture

Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 25/12/2016 0:00:00

}

// Reverted back to the original culture

Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 12/25/2016 12:00:00 AM

Note: as we don't use the CultureContext instance we create, we don't assign a variable for it.

This technique is used by the BeginForm helper in ASP.NET MVC.

Section 60.7: Using Statements and Database Connections

The using keyword ensures that the resource defined within the statement only exists within the scope of the statement itself. Any resources defined within the statement must implement the IDisposable interface.

These are incredibly important when dealing with any connections that implement the IDisposable interface as it can ensure the connections are not only properly closed but that their resources are freed after the using statement is out of scope.

Common IDisposable Data Classes

Many of the following are data-related classes that implement the IDisposable interface and are perfect candidates for a using statement :

SqlConnection,SqlCommand,SqlDataReader, etc.

OleDbConnection,OleDbCommand,OleDbDataReader, etc.

MySqlConnection, MySqlCommand, MySqlDbDataReader, etc.

DbContext

GoalKicker.com – C# Notes for Professionals

323

All of these are commonly used to access data through C# and will be commonly encountered throughout building data-centric applications. Many other classes that are not mentioned that implement the same FooConnection,FooCommand,FooDataReader classes can be expected to behave the same way.

Common Access Pattern for ADO.NET Connections

A common pattern that can be used when accessing your data through an ADO.NET connection might look as follows :

// This scopes the connection (your specific class may vary) using(var connection = new SqlConnection("{your-connection-string}")

{

// Build your query

var query = "SELECT * FROM YourTable WHERE Property = @property");

// Scope your command to execute

using(var command = new SqlCommand(query, connection))

{

//Open your connection connection.Open();

//Add your parameters here if necessary

//Execute your query as a reader (again scoped with a using statement) using(var reader = command.ExecuteReader())

{

//Iterate through your results here

}

}

}

Or if you were just performing a simple update and didn't require a reader, the same basic concept would apply :

using(var connection = new SqlConnection("{your-connection-string}"))

{

var query = "UPDATE YourTable SET Property = Value WHERE Foo = @foo"; using(var command = new SqlCommand(query,connection))

{

connection.Open();

//Add parameters here

//Perform your update command.ExecuteNonQuery();

}

}

Using Statements with DataContexts

Many ORMs such as Entity Framework expose abstraction classes that are used to interact with underlying databases in the form of classes like DbContext. These contexts generally implement the IDisposable interface as well and should take advantage of this through using statements when possible :

using(var context = new YourDbContext())

{

// Access your context and perform your query var data = context.Widgets.ToList();

}

GoalKicker.com – C# Notes for Professionals

324

Section 60.8: Executing code in constraint context

If you have code (a routine) you want to execute under a specific (constraint) context, you can use dependency injection.

The following example shows the constraint of executing under an open SSL connection. This first part would be in your library or framework, which you won't expose to the client code.

public static class SSLContext

{

// define the delegate to inject

public delegate void TunnelRoutine(BinaryReader sslReader, BinaryWriter sslWriter);

// this allows the routine to be executed under SSL

public static void ClientTunnel(TcpClient tcpClient, TunnelRoutine routine)

{

using (SslStream sslStream = new SslStream(tcpClient.GetStream(), true, _validate))

{

sslStream.AuthenticateAsClient(HOSTNAME, null, SslProtocols.Tls, false);

if (!sslStream.IsAuthenticated)

{

throw new SecurityException("SSL tunnel not authenticated");

}

if (!sslStream.IsEncrypted)

{

throw new SecurityException("SSL tunnel not encrypted");

}

using (BinaryReader sslReader = new BinaryReader(sslStream)) using (BinaryWriter sslWriter = new BinaryWriter(sslStream))

{

routine(sslReader, sslWriter);

}

}

}

}

Now the client code which wants to do something under SSL but does not want to handle all the SSL details. You can now do whatever you want inside the SSL tunnel, for example exchange a symmetric key:

public void ExchangeSymmetricKey(BinaryReader sslReader, BinaryWriter sslWriter)

{

byte[] bytes = new byte[8];

(new RNGCryptoServiceProvider()).GetNonZeroBytes(bytes); sslWriter.Write(BitConverter.ToUInt64(bytes, 0));

}

You execute this routine as follows:

SSLContext.ClientTunnel(tcpClient, this.ExchangeSymmetricKey);

To do this, you need the using() clause because it is the only way (apart from a try..finally block) you can guarantee the client code (ExchangeSymmetricKey) never exits without properly disposing of the disposable resources. Without using() clause, you would never know if a routine could break the context's constraint to dispose of those resources.

GoalKicker.com – C# Notes for Professionals

325