diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 2a691a993e904..fe68094ebf025 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1321,6 +1321,14 @@ { "source_path":"docs/fsharp/language-reference/signatures.md", "redirect_url":"/dotnet/fsharp/language-reference/signature-files" + }, + { + "source_path":"docs/csharp/programming-guide/concepts/threading/thread-timers.md", + "redirect_url":"/dotnet/standard/threading/timers" + }, + { + "source_path":"docs/visual-basic/programming-guide/concepts/threading/thread-timers.md", + "redirect_url":"/dotnet/standard/threading/timers" } ] } diff --git a/docs/core/versions/selection.md b/docs/core/versions/selection.md index c5b1434b89664..21031709da865 100644 --- a/docs/core/versions/selection.md +++ b/docs/core/versions/selection.md @@ -27,9 +27,9 @@ The rest of this document examines those four scenarios. SDK commands include `dotnet new`, `dotnet build` or `dotnet run`. The `dotnet` CLI must choose an SDK version for any command. The .NET Core CLI uses the latest SDK installed on the machine by default. You'll use the .NET Core SDK v2.1.301 when it's installed, even if the project you are working with targets the .NET Core Runtime 2.0. Note that this is true for preview versions as well as released versions. You can take advantage of the latest SDK features and improvements while targeting earlier .NET Core runtime versions. You can target multiple runtime versions of .NET Core on different projects, using the same SDK tools for all projects. -On rare occasions, you may need to use an earlier version of the SDK. You specify that version in a [*global.json* file](../tools/global-json.md). The "use latest" policy means you only use *global.json* to specify a .NET Core version earlier than the latest installed version. +On rare occasions, you may need to use an earlier version of the SDK. You specify that version in a [*global.json* file](../tools/global-json.md). The "use latest" policy means you only use *global.json* to specify a .NET Core SDK version earlier than the latest installed version. -*global.json* can be placed anywhere in the file hierarchy. The CLI searches upward from the project directory for the first *global.json* it finds. You control which projects a given *global.json* applies to by its place in the file system. The .NET CLI searches for a *global.json* file iteratively navigating the path upward from the current working directory. The first *global.json* file found specifies the version used. If that version is installed, that version is used. If the SDK specified in the *global.json* is not found, the .NET CLI rolls forward to the latest SDK installed. This is the same as the default behavior, when no *global.json** file is found. +*global.json* can be placed anywhere in the file hierarchy. The CLI searches upward from the project directory for the first *global.json* it finds. You control which projects a given *global.json* applies to by its place in the file system. The .NET CLI searches for a *global.json* file iteratively navigating the path upward from the current working directory. The first *global.json* file found specifies the version used. If that version is installed, that version is used. If the SDK specified in the *global.json* is not found, the .NET CLI rolls forward to the latest SDK installed. This is the same as the default behavior, when no *global.json* file is found. The following example shows the *global.json* syntax: @@ -45,7 +45,7 @@ The process for selecting an SDK version is: 1. `dotnet` searches for a *global.json* file iteratively reverse-navigating the path upward from the current working directory. 1. `dotnet` uses the SDK specified in the first *global.json* found. -1. `dotnet` binds to the latest installed SDK if no *global.json* is found. +1. `dotnet` uses the latest installed SDK if no *global.json* is found. You can learn more about selecting an SDK version in the [matching rules](../tools/global-json.md) section of the topic on *global.json*. @@ -79,21 +79,21 @@ A few usage examples demonstrate the behavior: - 2.0.4 is required. 2.0.5 is the highest patch version installed. 2.0.5 is used. - 2.0.4 is required. No 2.0.* versions are installed. 1.1.1 is the highest runtime installed. An error message is displayed. -- 2.04 is required. 2.0.0 is the latest version installed. An error message is displayed. +- 2.0.4 is required. 2.0.0 is the highest version installed. An error message is displayed. - 2.0.4 is required. No 2.0.* versions are installed. 2.2.2 is the highest 2.x runtime version installed. 2.2.2 is used. - 2.0.4 is required. No 2.x versions are installed. 3.0.0 (not a currently available version) is installed. An error message is displayed. Minor version roll-forward has one side-effect that may affect end users. Consider the following scenario: - 2.0.4 is required. No 2.0.* versions are installed. 2.2.2 is installed. 2.2.2 is used. -- 2.0.5 is later installed. 2.0.5 will be used for subsequent application launches, not 2.2.2. The latest patch is preferred over an updated minor version. -- It's possible that 2.0.5 and 2.2.2 might behave differently, particularly for scenarios like serializing binary data. +- 2.0.5 is later installed. 2.0.5 will be used for subsequent application launches, not 2.2.2. The latest patch of the required minor version is preferred over a higher minor version. +- It's possible that 2.0.5 and 2.2.2 behave differently, particularly for scenarios like serializing binary data. ## Self-contained deployments include the selected runtime You can publish an application as a [**self-contained distribution**](../deploying/index.md#self-contained-deployments-scd). This approach bundles the .NET Core runtime and libraries with your application. Self-contained deployments don't have a dependency on runtime environments. Runtime version selection occurs at publishing time, not run time. -The publishing process selects the latest patch version of the given runtime family. For example, `dotnet publish` will select .NET Core 2.0.4 if it is the latest patch version in the .NET Core 2.0 runtime family. The target framework (including the latest installed security patches) are packaged with the application. +The publishing process selects the latest patch version of the given runtime family. For example, `dotnet publish` will select .NET Core 2.0.4 if it is the latest patch version in the .NET Core 2.0 runtime family. The target framework (including the latest installed security patches) is packaged with the application. It's an error if the minimum version specified for an application isn't satisfied. `dotnet publish` binds to the latest runtime patch version (within a given major.minor version family). `dotnet publish` doesn't support the roll-forward semantics of `dotnet run`. For more information about patches and self-contained deployments, see the article on [runtime patch selection](../deploying/runtime-patch-selection.md) in deploying .NET Core applications. @@ -103,4 +103,4 @@ Self-contained deployments may require a specific patch version. You can overrid 2.0.4 ``` -The `RuntimeFrameworkVersion` element overrides the default version policy. For self-contained deployments, the `RuntimeFrameworkVersion` specifies the *exact* runtime framework version. For framework dependent applications, the `RuntimeFrameworkVersion` specifies the *minimum* patch level of the framework. +The `RuntimeFrameworkVersion` element overrides the default version policy. For self-contained deployments, the `RuntimeFrameworkVersion` specifies the *exact* runtime framework version. For framework dependent applications, the `RuntimeFrameworkVersion` specifies the *minimum* required runtime framework version. diff --git a/docs/core/whats-new/dotnet-core-2-1.md b/docs/core/whats-new/dotnet-core-2-1.md index e7322b096725e..87c53bbc89a10 100644 --- a/docs/core/whats-new/dotnet-core-2-1.md +++ b/docs/core/whats-new/dotnet-core-2-1.md @@ -212,11 +212,11 @@ The sockets implementation introduced in .NET Core 2.1 has a number of advantage is the default implementation in .NET Core 2.1. However, you can configure your application to use the older class by calling the method: ```csharp -AppContext.SetSwitch("System.Net.Http.useSocketsHttpHandler", false); +AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); ``` ```vb -AppContext.SetSwitch("System.Net.Http.useSocketsHttpHandler", False) +AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", False) ``` You can also use an environment variable to opt out of using sockets implementations based on . To do this, set the `DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER` to either `false` or 0. diff --git a/docs/csharp/language-reference/keywords/foreach-in.md b/docs/csharp/language-reference/keywords/foreach-in.md index 9b0799d538204..93064248ac698 100644 --- a/docs/csharp/language-reference/keywords/foreach-in.md +++ b/docs/csharp/language-reference/keywords/foreach-in.md @@ -29,11 +29,11 @@ The following example shows usage of the `foreach` statement with an instance of The next example uses the `foreach` statement with an instance of the type, which doesn't implement any interfaces: -[!code-csharp[span example](~/samples/snippets/csharp/keywords/IterationKeywordsExamples.cs#2)] +[!code-csharp-interactive[span example](~/samples/snippets/csharp/keywords/IterationKeywordsExamples.cs#2)] Beginning with C# 7.3, if the enumerator's `Current` property returns a [reference return value](../../programming-guide/classes-and-structs/ref-returns.md) (`ref T` where `T` is the type of the collection element), you can declare the iteration variable with the `ref` or `ref readonly` modifier. The following example uses a `ref` iteration variable to set the value of each item in a stackalloc array. The `ref readonly` version iterates the collection to print all the values. The `readonly` declaration uses an implicit local variable declaration. Implicit variable declarations can be used with either `ref` or `ref readonly` declarations, as can explicitly typed variable declarations. -[!code-csharp[ref span example](~/samples/snippets/csharp/keywords/IterationKeywordsExamples.cs#RefSpan)] +[!code-csharp-interactive[ref span example](~/samples/snippets/csharp/keywords/IterationKeywordsExamples.cs#RefSpan)] ## C# language specification diff --git a/docs/csharp/programming-guide/concepts/linq/linq-to-xml-overview.md b/docs/csharp/programming-guide/concepts/linq/linq-to-xml-overview.md index e4d9d0ac974f1..80e4b295a6474 100644 --- a/docs/csharp/programming-guide/concepts/linq/linq-to-xml-overview.md +++ b/docs/csharp/programming-guide/concepts/linq/linq-to-xml-overview.md @@ -22,7 +22,7 @@ XML has been widely adopted as a way to format data in many contexts. For exampl Another advantage of [!INCLUDE[sqltecxlinq](~/includes/sqltecxlinq-md.md)] is the ability to use query results as parameters to and object constructors enables a powerful approach to creating XML trees. This approach, called *functional construction*, enables developers to easily transform XML trees from one shape to another. - For example, you might have a typical XML purchase order as described in [Sample XML File: Typical Purchase Order (LINQ to XML)](http://msdn.microsoft.com/library/0606c09f-6e43-4f8d-95c8-e8e2e08d2348). By using [!INCLUDE[sqltecxlinq](~/includes/sqltecxlinq-md.md)], you could run the following query to obtain the part number attribute value for every item element in the purchase order: + For example, you might have a typical XML purchase order as described in [Sample XML File: Typical Purchase Order (LINQ to XML)](sample-xml-file-typical-purchase-order-linq-to-xml-1.md). By using [!INCLUDE[sqltecxlinq](~/includes/sqltecxlinq-md.md)], you could run the following query to obtain the part number attribute value for every item element in the purchase order: ```csharp IEnumerable partNos = diff --git a/docs/csharp/programming-guide/concepts/threading/index.md b/docs/csharp/programming-guide/concepts/threading/index.md index 25093904048a2..7f59944af68fe 100644 --- a/docs/csharp/programming-guide/concepts/threading/index.md +++ b/docs/csharp/programming-guide/concepts/threading/index.md @@ -35,7 +35,6 @@ Threading enables your C# program to perform concurrent processing so that you c |[Parameters and Return Values for Multithreaded Procedures (C#)](../../../../csharp/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md)|Describes how to pass and return parameters with multithreaded applications.| |[Walkthrough: Multithreading with the BackgroundWorker Component (C#)](../../../../csharp/programming-guide/concepts/threading/walkthrough-multithreading-with-the-backgroundworker-component.md)|Shows how to create a simple multithreaded application.| |[Thread Synchronization (C#)](../../../../csharp/programming-guide/concepts/threading/thread-synchronization.md)|Describes how to control the interactions of threads.| -|[Thread Timers (C#)](../../../../csharp/programming-guide/concepts/threading/thread-timers.md)|Describes how to run procedures on separate threads at fixed intervals.| |[Thread Pooling (C#)](../../../../csharp/programming-guide/concepts/threading/thread-pooling.md)|Describes how to use a pool of worker threads that are managed by the system.| |[How to: Use a Thread Pool (C#)](../../../../csharp/programming-guide/concepts/threading/how-to-use-a-thread-pool.md)|Demonstrates synchronized use of multiple threads in the thread pool.| |[Threading](../../../../../docs/standard/threading/index.md)|Describes how to implement threading in the .NET Framework.| diff --git a/docs/csharp/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md b/docs/csharp/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md index e00c557249a20..2597223ddf52f 100644 --- a/docs/csharp/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md +++ b/docs/csharp/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md @@ -109,7 +109,7 @@ private void BackgroundWorker1_RunWorkerCompleted( } ``` - You can provide parameters and return values to thread-pool threads by using the optional `ByVal` state-object variable of the method. Thread-timer threads also support a state object for this purpose. For information on thread pooling and thread timers, see [Thread Pooling (C#)](../../../../csharp/programming-guide/concepts/threading/thread-pooling.md) and [Thread Timers (C#)](../../../../csharp/programming-guide/concepts/threading/thread-timers.md). + You can provide parameters and return values to thread-pool threads by using the optional `ByVal` state-object variable of the method. Thread-timer threads also support a state object for this purpose. For information on thread pooling and thread timers, see [Thread Pooling (C#)](../../../../csharp/programming-guide/concepts/threading/thread-pooling.md) and [Timers](../../../../standard/threading/timers.md). ## See Also [Walkthrough: Multithreading with the BackgroundWorker Component (C#)](../../../../csharp/programming-guide/concepts/threading/walkthrough-multithreading-with-the-backgroundworker-component.md) diff --git a/docs/csharp/programming-guide/concepts/threading/thread-timers.md b/docs/csharp/programming-guide/concepts/threading/thread-timers.md deleted file mode 100644 index 0c43a0cac74f6..0000000000000 --- a/docs/csharp/programming-guide/concepts/threading/thread-timers.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: "Thread Timers (C#)" -ms.date: 07/20/2015 -ms.assetid: 52ed71e8-4fd9-43a4-ae40-04cce7cff23f ---- -# Thread Timers (C#) -The class is useful for periodically running a task on a separate thread. For example, you could use a thread timer to check the status and integrity of a database or to back up critical files. - -## Thread Timer Example - The following example starts a task every two seconds and uses a flag to initiate the method that stops the timer. This example posts status to the output window. - -```csharp -private class StateObjClass -{ - // Used to hold parameters for calls to TimerTask. - public int SomeValue; - public System.Threading.Timer TimerReference; - public bool TimerCanceled; -} - -public void RunTimer() -{ - StateObjClass StateObj = new StateObjClass(); - StateObj.TimerCanceled = false; - StateObj.SomeValue = 1; - System.Threading.TimerCallback TimerDelegate = - new System.Threading.TimerCallback(TimerTask); - - // Create a timer that calls a procedure every 2 seconds. - // Note: There is no Start method; the timer starts running as soon as - // the instance is created. - System.Threading.Timer TimerItem = - new System.Threading.Timer(TimerDelegate, StateObj, 2000, 2000); - - // Save a reference for Dispose. - StateObj.TimerReference = TimerItem; - - // Run for ten loops. - while (StateObj.SomeValue < 10) - { - // Wait one second. - System.Threading.Thread.Sleep(1000); - } - - // Request Dispose of the timer object. - StateObj.TimerCanceled = true; -} - -private void TimerTask(object StateObj) -{ - StateObjClass State = (StateObjClass)StateObj; - // Use the interlocked class to increment the counter variable. - System.Threading.Interlocked.Increment(ref State.SomeValue); - System.Diagnostics.Debug.WriteLine("Launched new thread " + DateTime.Now.ToString()); - if (State.TimerCanceled) - // Dispose Requested. - { - State.TimerReference.Dispose(); - System.Diagnostics.Debug.WriteLine("Done " + DateTime.Now.ToString()); - } -} -``` - - Thread timers are particularly useful when the object is unavailable, such as when you are developing console applications. - -## See Also - - [Multithreaded Applications (C#)](../../../../csharp/programming-guide/concepts/threading/multithreaded-applications.md) diff --git a/docs/csharp/programming-guide/concepts/threading/toc.md b/docs/csharp/programming-guide/concepts/threading/toc.md index 1e3af3afe5020..6c05a7373bff5 100644 --- a/docs/csharp/programming-guide/concepts/threading/toc.md +++ b/docs/csharp/programming-guide/concepts/threading/toc.md @@ -3,6 +3,5 @@ ## [Parameters and Return Values for Multithreaded Procedures](parameters-and-return-values-for-multithreaded-procedures.md) ## [Walkthrough: Multithreading with the BackgroundWorker Component](walkthrough-multithreading-with-the-backgroundworker-component.md) ## [Thread Synchronization](thread-synchronization.md) -## [Thread Timers](thread-timers.md) ## [Thread Pooling](thread-pooling.md) ### [How to: Use a Thread Pool](how-to-use-a-thread-pool.md) diff --git a/docs/csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs b/docs/csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs index d840dff02cc2b..f56cd26dbb513 100644 --- a/docs/csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs +++ b/docs/csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs @@ -1,3 +1,4 @@ +#region everything namespace WrapTwoInterfaceEvents { using System; @@ -29,6 +30,7 @@ public class Shape : IDrawingObject, IShape // Explicit interface implementation required. // Associate IDrawingObject's event with // PreDrawEvent + #region IDrawingObjectOnDraw event EventHandler IDrawingObject.OnDraw { add @@ -46,6 +48,8 @@ event EventHandler IDrawingObject.OnDraw } } } + #endregion + // Explicit interface implementation required. // Associate IShape's event with // PostDrawEvent @@ -133,3 +137,4 @@ Sub1 receives the IDrawingObject event. Drawing a shape. Sub2 receives the IShape event. */ +#endregion \ No newline at end of file diff --git a/docs/csharp/programming-guide/events/how-to-implement-custom-event-accessors.md b/docs/csharp/programming-guide/events/how-to-implement-custom-event-accessors.md index 492f26e11b446..17c30185555d1 100644 --- a/docs/csharp/programming-guide/events/how-to-implement-custom-event-accessors.md +++ b/docs/csharp/programming-guide/events/how-to-implement-custom-event-accessors.md @@ -15,25 +15,7 @@ An event is a special kind of multicast delegate that can only be invoked from w ## Example The following example shows how to implement custom add and remove event accessors. Although you can substitute any code inside the accessors, we recommend that you lock the event before you add or remove a new event handler method. -```csharp -event EventHandler IDrawingObject.OnDraw -{ - add - { - lock (PreDrawEvent) - { - PreDrawEvent += value; - } - } - remove - { - lock (PreDrawEvent) - { - PreDrawEvent -= value; - } - } -} -``` +[!code-csharp[IDrawingObject.OnDraw](codesnippet/CSharp/how-to-implement-interface-events_1.cs#IDrawingObjectOnDraw)] ## See Also [Events](../../../csharp/programming-guide/events/index.md) diff --git a/docs/csharp/programming-guide/events/how-to-implement-interface-events.md b/docs/csharp/programming-guide/events/how-to-implement-interface-events.md index be3b95fdc2b9c..bd851433a9ccb 100644 --- a/docs/csharp/programming-guide/events/how-to-implement-interface-events.md +++ b/docs/csharp/programming-guide/events/how-to-implement-interface-events.md @@ -9,47 +9,47 @@ ms.assetid: 63527447-9535-4880-8e95-35e2075827df # How to: Implement Interface Events (C# Programming Guide) An [interface](../../../csharp/language-reference/keywords/interface.md) can declare an [event](../../../csharp/language-reference/keywords/event.md). The following example shows how to implement interface events in a class. Basically the rules are the same as when you implement any interface method or property. -### To implement interface events in a class +## To implement interface events in a class -- Declare the event in your class and then invoke it in the appropriate areas. +Declare the event in your class and then invoke it in the appropriate areas. - ```csharp - namespace ImplementInterfaceEvents +```csharp +namespace ImplementInterfaceEvents +{ + public interface IDrawingObject { - public interface IDrawingObject - { - event EventHandler ShapeChanged; - } - public class MyEventArgs : EventArgs + event EventHandler ShapeChanged; + } + public class MyEventArgs : EventArgs + { + // class members + } + public class Shape : IDrawingObject + { + public event EventHandler ShapeChanged; + void ChangeShape() { - // class members + // Do something here before the event… + + OnShapeChanged(new MyEventArgs(/*arguments*/)); + + // or do something here after the event. } - public class Shape : IDrawingObject + protected virtual void OnShapeChanged(MyEventArgs e) { - public event EventHandler ShapeChanged; - void ChangeShape() - { - // Do something here before the event… - - OnShapeChanged(new MyEventArgs(/*arguments*/)); - - // or do something here after the event. - } - protected virtual void OnShapeChanged(MyEventArgs e) - { - ShapeChanged?.Invoke(this, e); - } + ShapeChanged?.Invoke(this, e); } - } - ``` + +} +``` ## Example The following example shows how to handle the less-common situation in which your class inherits from two or more interfaces and each interface has an event with the same name. In this situation, you must provide an explicit interface implementation for at least one of the events. When you write an explicit interface implementation for an event, you must also write the `add` and `remove` event accessors. Normally these are provided by the compiler, but in this case the compiler cannot provide them. By providing your own accessors, you can specify whether the two events are represented by the same event in your class, or by different events. For example, if the events should be raised at different times according to the interface specifications, you can associate each event with a separate implementation in your class. In the following example, subscribers determine which `OnDraw` event they will receive by casting the shape reference to either an `IShape` or an `IDrawingObject`. - [!code-csharp[csProgGuideEvents#10](../../../csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs)] + [!code-csharp[WrapTwoInterfaceEvents](../../../csharp/programming-guide/events/codesnippet/CSharp/how-to-implement-interface-events_1.cs#everything)] ## See Also [C# Programming Guide](../../../csharp/programming-guide/index.md) diff --git a/docs/csharp/tutorials/inheritance.md b/docs/csharp/tutorials/inheritance.md index 279098154113d..edd713799b69e 100644 --- a/docs/csharp/tutorials/inheritance.md +++ b/docs/csharp/tutorials/inheritance.md @@ -3,7 +3,7 @@ title: Inheritance in C# description: Learn to use inheritance in C# libraries and applications. author: rpetrusha ms.author: ronpet -ms.date: 08/16/2017 +ms.date: 07/05/2018 ms.assetid: aeb68c74-0ea0-406f-9fbe-2ce02d47ef31 --- # Inheritance in C# and .NET @@ -27,7 +27,6 @@ To create and run the examples in this tutorial, you use the [dotnet](../../core 1. Enter the [dotnet run](../../core/tools/dotnet-run.md) command to compile and execute the example. - ## Background: What is inheritance? *Inheritance* is one of the fundamental attributes of object-oriented programming. It allows you to define a child class that reuses (inherits), extends, or modifies the behavior of a parent class. The class whose members are inherited is called the *base class*. The class that inherits the members of the base class is called the *derived class*. @@ -52,7 +51,7 @@ While all other members of a base class are inherited by derived classes, whethe - [Internal](../language-reference/keywords/internal.md) members are visible only in derived classes that are located in the same assembly as the base class. They are not visible in derived classes located in a different assembly from the base class. -- [Public](../language-reference/keywords/public.md) members are visible in derived classes and are part of the derived class' public interface. Public inherited members can be called just as if they were defined in the derived class. In the following example, class `A` defines a method named `Method1`, and class `B` inherits from class `A`. The example then calls `Method1` as if it were an instance method on `B`. +- [Public](../language-reference/keywords/public.md) members are visible in derived classes and are part of the derived class' public interface. Public inherited members can be called just as if they are defined in the derived class. In the following example, class `A` defines a method named `Method1`, and class `B` inherits from class `A`. The example then calls `Method1` as if it were an instance method on `B`. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/basics.cs#1)] @@ -93,7 +92,7 @@ public class B : A // Generates CS0534. } ``` -Inheritance applies only to classes and interfaces. Other type categories (structs, delegates, and enums) do not support inheritance. Because of this, attempting to compile code like the following produces compiler error CS0527: "Type 'ValueType' in interface list is not an interface." The error message indicates that, although you can define the interfaces that a struct implements, inheritance is not supported. +Inheritance applies only to classes and interfaces. Other type categories (structs, delegates, and enums) do not support inheritance. Because of these rules, attempting to compile code like the following example produces compiler error CS0527: "Type 'ValueType' in interface list is not an interface." The error message indicates that, although you can define the interfaces that a struct implements, inheritance is not supported. ```csharp using System; @@ -105,13 +104,13 @@ public struct ValueStructure : ValueType // Generates CS0527. ## Implicit inheritance -Besides any types that they may inherit from through single inheritance, all types in the .NET type system implicitly inherit from or a type derived from it. This ensures that common functionality is available to any type. +Besides any types that they may inherit from through single inheritance, all types in the .NET type system implicitly inherit from or a type derived from it. The common functionality of is available to any type. To see what implicit inheritance means, let's define a new class, `SimpleClass`, that is simply an empty class definition: [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/simpleclass.cs#1)] -We can then use reflection (which lets us inspect a type's metadata to get information about that type) to get a list of the members that belong to the `SimpleClass` type. Although we haven't defined any members in our `SimpleClass` class, output from the example indicates that it actually has nine members. One of these is a parameterless (or default) constructor that is automatically supplied for the `SimpleClass` type by the C# compiler. The remaining eight are members of , the type from which all classes and interfaces in the .NET type system ultimately implicitly inherit. +You can then use reflection (which lets you inspect a type's metadata to get information about that type) to get a list of the members that belong to the `SimpleClass` type. Although you haven't defined any members in your `SimpleClass` class, output from the example indicates that it actually has nine members. One of these members is a parameterless (or default) constructor that is automatically supplied for the `SimpleClass` type by the C# compiler. The remaining eight are members of , the type from which all classes and interfaces in the .NET type system ultimately implicitly inherit. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/simpleclass.cs#2)] @@ -129,7 +128,7 @@ Implicit inheritance from the class makes these methods ava - The protected method, which creates a shallow clone of the current object. -Because of implicit inheritance, we can call any inherited member from a `SimpleClass` object just as if it was actually a member defined in the `SimpleClass` class. For instance, the following example calls the `SimpleClass.ToString` method, which `SimpleClass` inherits from . +Because of implicit inheritance, you can call any inherited member from a `SimpleClass` object just as if it was actually a member defined in the `SimpleClass` class. For instance, the following example calls the `SimpleClass.ToString` method, which `SimpleClass` inherits from . [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/simpleclass2.cs#1)] @@ -149,11 +148,11 @@ Ordinarily, inheritance is used to express an "is a" relationship between a base > [!NOTE] > A class or struct can implement one more interfaces. While interface implementation is often presented as a workaround for single inheritance or as a way of using inheritance with structs, it is intended to express a different relationship (a "can do" relationship) between an interface and its implementing type than inheritance. An interface defines a subset of functionality (such as the ability to test for equality, to compare or sort objects, or to support culture-sensitive parsing and formatting) that the interface makes available to its implementing types. -Note that "is a" also expresses the relationship between a type and a specific instantiation of that type. In the following example, `Automobile` is a class that has three unique read-only properties: `Make`, the manufacturer of the automobile; `Model`, the kind of automobile; and `Year`, its year of manufacture. Our `Automobile` class also has a constructor whose arguments are assigned to the property values, and it overrides the method to produce a string that uniquely identifies the `Automobile` instance rather than the `Automobile` class. +Note that "is a" also expresses the relationship between a type and a specific instantiation of that type. In the following example, `Automobile` is a class that has three unique read-only properties: `Make`, the manufacturer of the automobile; `Model`, the kind of automobile; and `Year`, its year of manufacture. Your `Automobile` class also has a constructor whose arguments are assigned to the property values, and it overrides the method to produce a string that uniquely identifies the `Automobile` instance rather than the `Automobile` class. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/is-a.cs#1)] -In this case, we should not rely on inheritance to represent specific car makes and models. For example, we do not need to define a `Packard` type to represent automobiles manufactured by the Packard Motor Car Company. Instead, we can represent them by creating an `Automobile` object with the appropriate values passed to its class constructor, as the following example does. +In this case, you shouldn't rely on inheritance to represent specific car makes and models. For example, you don't need to define a `Packard` type to represent automobiles manufactured by the Packard Motor Car Company. Instead, you can represent them by creating an `Automobile` object with the appropriate values passed to its class constructor, as the following example does. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/is-a.cs#2)] @@ -161,35 +160,37 @@ An is-a relationship based on inheritance is best applied to a base class and to ## Designing the base class and derived classes -Let's look at the process of designing a base class and its derived classes. In this section, we'll define a base class, `Publication`, which represents a publication of any kind, such as a book, a magazine, a newspaper, a journal, an article, etc. We'll also define a `Book` class that derives from `Publication`. We could easily extend the example to define other derived classes, such as `Magazine`, `Journal`, `Newspaper`, and `Article`. +Let's look at the process of designing a base class and its derived classes. In this section, you'll define a base class, `Publication`, which represents a publication of any kind, such as a book, a magazine, a newspaper, a journal, an article, etc. You'll also define a `Book` class that derives from `Publication`. You could easily extend the example to define other derived classes, such as `Magazine`, `Journal`, `Newspaper`, and `Article`. ### The base Publication class -In designing our `Publication` class, we need to make several design decisions: +In designing your `Publication` class, you need to make several design decisions: -- What members to include in our base `Publication` class, and whether the `Publication` members provide method implementations, or whether `Publication` is an abstract base class that serves as a template for its derived classes. +- What members to include in your base `Publication` class, and whether the `Publication` members provide method implementations or whether `Publication` is an abstract base class that serves as a template for its derived classes. In this case, the `Publication` class will provide method implementations. The [Designing abstract base classes and their derived classes](#abstract) section contains an example that uses an abstract base class to define the methods that derived classes must override. Derived classes are free to provide any implementation that is suitable for the derived type. - The ability to reuse code (that is, multiple derived classes share the declaration and implementation of base class methods and do not need to override them) is an advantage of non-abstract base classes. Therefore, we should add members to `Publication` if their code is likely to be shared by some or most specialized `Publication` types. If we fail to do this efficiently, we'll end up having to provide largely identical member implementations in derived classes rather a single implementation in the base class. The need to maintain duplicated code in multiple locations is a potential source of bugs. + The ability to reuse code (that is, multiple derived classes share the declaration and implementation of base class methods and do not need to override them) is an advantage of non-abstract base classes. Therefore, you should add members to `Publication` if their code is likely to be shared by some or most specialized `Publication` types. If you fail to provide base class implementations efficiently, you'll end up having to provide largely identical member implementations in derived classes rather a single implementation in the base class. The need to maintain duplicated code in multiple locations is a potential source of bugs. + + Both to maximize code reuse and to create a logical and intuitive inheritance hierarchy, you want to be sure that you include in the `Publication` class only the data and functionality that is common to all or to most publications. Derived classes then implement members that are unique to the particular kinds of publication that they represent. - Both to maximize code reuse and to create a logical and intuitive inheritance hierarchy, we want to be sure that we include in the `Publication` class only the data and functionality that is common to all or to most publications. Derived classes then implement members that are unique to the particular kinds of publication that they represent. +- How far to extend your class hierarchy. Do you want to develop a hierarchy of three or more classes, rather than simply a base class and one or more derived classes? For example, `Publication` could be a base class of `Periodical`, which in turn is a base class of `Magazine`, `Journal` and `Newspaper`. -- How far to extend our class hierarchy. Do we want to develop a hierarchy of three or more classes, rather than simply a base class and one or more derived classes? For example, `Publication` could be a base class of `Periodical`, which in turn is a base class of `Magazine`, `Journal` and `Newspaper`. + For your example, you'll use the small hierarchy of a `Publication` class and a single derived class, `Book`. You could easily extend the example to create a number of additional classes that derive from `Publication`, such as `Magazine` and `Article`. - For our example, we'll use the simple hierarchy of a `Publication` class and a single derived classes, `Book`. We could easily extend the example to create a number of additional classes that derive from `Publication`, such as `Magazine` and `Article`. +- Whether it makes sense to instantiate the base class. If it does not, you should apply the [abstract](../language-reference/keywords/abstract.md) keyword to the class. Otherwise, your `Publication` class can be instantiated by calling its class constructor. If an attempt is made to instantiate a class marked with the `abstract` keyword by a direct call to its class constructor, the C# compiler generates error CS0144, "Cannot create an instance of the abstract class or interface." If an attempt is made to instantiate the class by using reflection, the reflection method throws a . -- Whether it makes sense to instantiate the base class. If it does not, we should apply the [abstract](../language-reference/keywords/abstract.md) keyword to the class. If an attempt is made to instantiate a class marked with the `abstract` keyword by a direct call to its class constructor, the C# compiler generates error CS0144, "Cannot create an instance of the abstract class or interface." If an attempt is made to instantiate the class by using reflection, the reflection method throws a . Otherwise, our `Publication` class can be instantiated by calling its class constructor. + By default, a base class can be instantiated by calling its class constructor. You do not have to explicitly define a class constructor. If one is not present in the base class' source code, the C# compiler automatically provides a default (parameterless) constructor. - By default, a base class can be instantiated by calling its class constructor. Note that we do not have to explicitly define a class constructor. If one is not present in the base class' source code, the C# compiler automatically provides a default (parameterless) constructor. + For your example, you'll mark the `Publication` class as [abstract](../language-reference/keywords/abstract.md) so that it cannot be instantiated. An `abstract` class without any `abstract` methods indicates that this class represents an abstract concept that is shared among several concrete classes (like a `Book`, `Journal`). - For our example, we'll mark the `Publication` class as [abstract](../language-reference/keywords/abstract.md) so that it cannot be instantiated. +- Whether derived classes must inherit the base class implementation of particular members, whether they have the option to override the base class implementation, or whether they must provide an implementation. You use the [abstract](../language-reference/keywords/abstract.md) keyword to force derived classes to provide an implementation. You use the [virtual](../language-reference/keywords/virtual.md) keyword to allow derived classes to override a base class method. By default, methods defined in the base class are *not* overridable. -- Whether derived classes must inherit the base class implementation of a particular members, or whether they have the option to override the base class implementation. We have to use the [virtual](../language-reference/keywords/virtual.md) keyword to allow derived classes to override a base class method. By default, methods defined in the base class are *not* overridable. + The `Publication` class does not have any `abstract` methods, but the class itself is `abstract`. -- Whether a derived class represents the final class in the inheritance hierarchy and cannot itself be used as a base class for additional derived classes. By default, any class can serve as a base class. We can apply the [sealed](../language-reference/keywords/sealed.md) keyword to indicate that a class cannot serve as a base class for any additional classes. Attempting to derive from a sealed class generated compiler error CS0509, "cannot derive from sealed type ". +- Whether a derived class represents the final class in the inheritance hierarchy and cannot itself be used as a base class for additional derived classes. By default, any class can serve as a base class. You can apply the [sealed](../language-reference/keywords/sealed.md) keyword to indicate that a class cannot serve as a base class for any additional classes. Attempting to derive from a sealed class generated compiler error CS0509, "cannot derive from sealed type ". - For our example, we'll mark our derived class as `sealed`. + For your example, you'll mark your derived class as `sealed`. The following example shows the source code for the `Publication` class, as well as a `PublicationType` enumeration that is returned by the `Publication.PublicationType` property. In addition to the members that it inherits from , the `Publication` class defines the following unique members and member overrides: @@ -197,7 +198,7 @@ The following example shows the source code for the `Publication` class, as well - A constructor - Because the `Publication` class is `abstract`, it cannot be instantiated directly from code like the following: + Because the `Publication` class is `abstract`, it cannot be instantiated directly from code like the following example: ```csharp var publication = new Publication("Tiddlywinks for Experts", "Fun and Games", @@ -228,7 +229,7 @@ The following example shows the source code for the `Publication` class, as well If a type does not override the method, it returns the fully qualified name of the type, which is of little use in differentiating one instance from another. The `Publication` class overrides to return the value of the `Title` property. -The following figure illustrates the relationship between our base `Publication` class and its implicitly inherited class. +The following figure illustrates the relationship between your base `Publication` class and its implicitly inherited class. ![The Object and Publication classes](media/publication-class.jpg) @@ -244,7 +245,7 @@ In addition to the members that it inherits from `Publication`, the `Book` class The two `Book` constructors share three common parameters. Two, *title* and *publisher*, correspond to parameters of the `Publication` constructor. The third is *author*, which is stored to a private `authorName` field. One constructor includes an *isbn* parameter, which is stored in the `ISBN` auto-property. - The first constructor uses the [this](../language-reference/keywords/this.md) keyword to call the other constructor. This is a common pattern in defining constructors. Constructors with fewer parameters provide default values when calling the constructor with the greatest number of parameters. + The first constructor uses the [this](../language-reference/keywords/this.md) keyword to call the other constructor. Constructor chaining is a common pattern in defining constructors. Constructors with fewer parameters provide default values when calling the constructor with the greatest number of parameters. The second constructor uses the [base](../language-reference/keywords/base.md) keyword to pass the title and publisher name to the base class constructor. If you don't make an explicit call to a base class constructor in your source code, the C# compiler automatically supplies a call to the base class' default or parameterless constructor. @@ -254,38 +255,38 @@ In addition to the members that it inherits from `Publication`, the `Book` class - Two read-only price-related properties, `Price` and `Currency`. Their values are provided as arguments in a `SetPrice` method call. The price is stored in a private field, `bookPrice`. The `Currency` property is the three-digit ISO currency symbol (for example, USD for the U.S. dollar) and is stored in the private `ISOCurrencySymbol` field. ISO currency symbols can be retrieved from the property. -- A `SetPrice` method, which sets the values of the `bookPrice` and `ISOCurrencySymbol` fields. These are the values returned by the `Price` and `Currency` properties. +- A `SetPrice` method, which sets the values of the `bookPrice` and `ISOCurrencySymbol` fields. Those values are returned by the `Price` and `Currency` properties. - Overrides to the `ToString` method (inherited from `Publication`) and the and methods (inherited from ). - Unless it is overridden, the method tests for reference equality. That is, two object variables are considered to be equal if they refer to the same object. In the case of the `Book` class, on the other hand, two `Book` objects should be equal if they have the same ISBN. + Unless it is overridden, the method tests for reference equality. That is, two object variables are considered to be equal if they refer to the same object. In the `Book` class, on the other hand, two `Book` objects should be equal if they have the same ISBN. - When you override the method, you must also override the method, which returns a value that the runtime uses to store items in hashed collections for efficient retrieval. The hash code should return a value that's consistent with the test for equality. Since we've overridden to return `true` if the ISBN properties of two `Book` objects are equal, we return the hash code computed by calling the method of the string returned by the `ISBN` property. + When you override the method, you must also override the method, which returns a value that the runtime uses to store items in hashed collections for efficient retrieval. The hash code should return a value that's consistent with the test for equality. Since you've overridden to return `true` if the ISBN properties of two `Book` objects are equal, you return the hash code computed by calling the method of the string returned by the `ISBN` property. The following figure illustrates the relationship between the `Book` class and `Publication`, its base class. ![Publication and Book classes](media/book-class.jpg) -We can now instantiate a `Book` object, invoke both its unique and inherited members, and pass it as an argument to a method that expects a parameter of type `Publication` or of type `Book`, as the following example shows. +You can now instantiate a `Book` object, invoke both its unique and inherited members, and pass it as an argument to a method that expects a parameter of type `Publication` or of type `Book`, as the following example shows. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/use-publication.cs#1)] ## Designing abstract base classes and their derived classes -In the previous example, we defined a base class that provided an implementation for a number of methods to allow derived classes to share code. In many cases, however, the base class is not expected to provide an implementation. Instead, the base class is an *abstract class*; it serves as a template that defines the members that each derived class must implement. Typically in the case of an abstract base class, the implementation of each derived type is unique to that type. +In the previous example, you defined a base class that provided an implementation for a number of methods to allow derived classes to share code. In many cases, however, the base class is not expected to provide an implementation. Instead, the base class is an *abstract class* that declares *abstract methods*; it serves as a template that defines the members that each derived class must implement. Typically in an abstract base class, the implementation of each derived type is unique to that type. You marked the class with the abstract keyword because it made no sense to instantiate a `Publication` object, although the class did provide implementations of functionality common to publications. -For example, each closed two-dimensional geometric shape includes two properties: area, the inner extent of the shape; and perimeter, or the distance along the edges of the shape. The way in which these properties are calculated, however, depends completely on the specific shape. The formula for calculating the perimeter (or circumference) of a circle, for example, is very different from that of a triangle. +For example, each closed two-dimensional geometric shape includes two properties: area, the inner extent of the shape; and perimeter, or the distance along the edges of the shape. The way in which these properties are calculated, however, depends completely on the specific shape. The formula for calculating the perimeter (or circumference) of a circle, for example, is different from that of a triangle. The `Shape` class is an `abstract` class with `abstract` methods. That indicates derived classes share the same functionality, but those derived classes implement that functionality differently. -The following example defines an abstract base class named `Shape` that defines two properties: `Area` and `Perimeter`. Note that, in addition to marking the class with the [abstract](../language-reference/keywords/abstract.md) keyword, each instance member is also marked with the [abstract](../language-reference/keywords/abstract.md) keyword. In this case, `Shape` also overrides the method to return the name of the type, rather than its fully qualified name. And it defines two static members, `GetArea` and `GetPerimeter`, that allow callers to easily retrieve the area and perimeter of an instance of any derived class. When we pass an instance of a derived class to either of these methods, the runtime calls the method override of the derived class. +The following example defines an abstract base class named `Shape` that defines two properties: `Area` and `Perimeter`. In addition to marking the class with the [abstract](../language-reference/keywords/abstract.md) keyword, each instance member is also marked with the [abstract](../language-reference/keywords/abstract.md) keyword. In this case, `Shape` also overrides the method to return the name of the type, rather than its fully qualified name. And it defines two static members, `GetArea` and `GetPerimeter`, that allow callers to easily retrieve the area and perimeter of an instance of any derived class. When you pass an instance of a derived class to either of these methods, the runtime calls the method override of the derived class. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/shape.cs#1)] -We can then derive some classes from `Shape` that represent specific shapes. The following example defines three classes, `Triangle`, `Rectangle`, and `Circle`. Each uses a formula unique for that particular shape to compute the area and perimeter. Some of the derived classes also define properties, such as `Rectangle.Diagonal` and `Circle.Diameter`, that are unique to the shape that they represent. +You can then derive some classes from `Shape` that represent specific shapes. The following example defines three classes, `Triangle`, `Rectangle`, and `Circle`. Each uses a formula unique for that particular shape to compute the area and perimeter. Some of the derived classes also define properties, such as `Rectangle.Diagonal` and `Circle.Diameter`, that are unique to the shape that they represent. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/shape.cs#2)] -The following example uses objects derived from `Shape`. It instantiates an array of objects derived from `Shape` and calls the static methods of the `Shape` class, which wraps return `Shape` property values. Note that the runtime retrieves values from the overridden properties of the derived types. The example also casts each `Shape` object in the array to its derived type and, if the cast succeeds, retrieves properties of that particular subclass of `Shape`. +The following example uses objects derived from `Shape`. It instantiates an array of objects derived from `Shape` and calls the static methods of the `Shape` class, which wraps return `Shape` property values. The runtime retrieves values from the overridden properties of the derived types. The example also casts each `Shape` object in the array to its derived type and, if the cast succeeds, retrieves properties of that particular subclass of `Shape`. [!code-csharp[Inheritance](../../../samples/snippets/csharp/tutorials/inheritance/shape.cs#3)] diff --git a/docs/framework/configure-apps/file-schema/network/mailsettings-element-network-settings.md b/docs/framework/configure-apps/file-schema/network/mailsettings-element-network-settings.md index a4fa80bc0327a..ad5f1b928a384 100644 --- a/docs/framework/configure-apps/file-schema/network/mailsettings-element-network-settings.md +++ b/docs/framework/configure-apps/file-schema/network/mailsettings-element-network-settings.md @@ -52,7 +52,7 @@ Configures mail sending options. - + - + - + - + diff --git a/docs/framework/data/adonet/ef/language-reference/entity-sql-reference.md b/docs/framework/data/adonet/ef/language-reference/entity-sql-reference.md index 7c47b71316576..94976960bb890 100644 --- a/docs/framework/data/adonet/ef/language-reference/entity-sql-reference.md +++ b/docs/framework/data/adonet/ef/language-reference/entity-sql-reference.md @@ -44,12 +44,12 @@ Equality and inequality are defined for any object type that has identity, such |[= (Equals)](equals-entity-sql.md)|Compares the equality of two expressions.| |[> (Greater Than)](greater-than-entity-sql.md)|Compares two expressions to determine whether the left expression has a value greater than the right expression.| |[>= (Greater Than or Equal To)](greater-than-or-equal-to-entity-sql.md)|Compares two expressions to determine whether the left expression has a value greater than or equal to the right expression.| -|[IS [NOT] NULL](isnull-entity-sql.md)|Determines if a query expression is null.| +|[IS \[NOT\] NULL](isnull-entity-sql.md)|Determines if a query expression is null.| |[< (Less Than)](less-than-entity-sql.md)|Compares two expressions to determine whether the left expression has a value less than the right expression.| |[<= (Less Than or Equal To)](less-than-or-equal-to-entity-sql.md)|Compares two expressions to determine whether the left expression has a value less than or equal to the right expression.| -|[[NOT] BETWEEN](between-entity-sql.md)|Determines whether an expression results in a value in a specified range.| +|[\[NOT\] BETWEEN](between-entity-sql.md)|Determines whether an expression results in a value in a specified range.| |[!= (Not Equal To)](not-equal-to-entity-sql.md)|Compares two expressions to determine whether the left expression isn't equal to the right expression.| -|[[NOT] LIKE](like-entity-sql.md)|Determines whether a specific character string matches a specified pattern.| +|[\[NOT\] LIKE](like-entity-sql.md)|Determines whether a specific character string matches a specified pattern.| ## Logical and case expression operators @@ -100,9 +100,9 @@ Entity SQL provides various powerful set operations. This includes set operators |--------------|---------| |[ANYELEMENT](anyelement-entity-sql.md)|Extracts an element from a multivalued collection.| |[EXCEPT](except-entity-sql.md)|Returns a collection of any distinct values from the query expression to the left of the EXCEPT operand that aren't also returned from the query expression to the right of the EXCEPT operand.| -|[[NOT] EXISTS](exists-entity-sql.md)|Determines if a collection is empty.| +|[\[NOT\] EXISTS](exists-entity-sql.md)|Determines if a collection is empty.| |[FLATTEN](flatten-entity-sql.md)|Converts a collection of collections into a flattened collection.| -|[[NOT] IN](in-entity-sql.md)|Determines whether a value matches any value in a collection.| +|[\[NOT\] IN](in-entity-sql.md)|Determines whether a value matches any value in a collection.| |[INTERSECT](intersect-entity-sql.md)|Returns a collection of any distinct values that are returned by both the query expressions on the left and right sides of the INTERSECT operand.| |[OVERLAPS](overlaps-entity-sql.md)|Determines whether two collections have common elements.| |[SET](set-entity-sql.md)|Used to convert a collection of objects into a set by yielding a new collection with all duplicate elements removed.| @@ -116,7 +116,7 @@ Entity SQL provides operations that allow the type of an expression (value) to b |--------------|---------| |[CAST](cast-entity-sql.md)|Converts an expression of one data type to another.| |[COLLECTION](collection-entity-sql.md)|Used in a [FUNCTION](function-entity-sql.md) operation to declare a collection of entity types or complex types.| -|[IS [NOT] OF](isof-entity-sql.md)|Determines whether the type of an expression is of the specified type or one of its subtypes.| +|[IS \[NOT\] OF](isof-entity-sql.md)|Determines whether the type of an expression is of the specified type or one of its subtypes.| |[OFTYPE](oftype-entity-sql.md)|Returns a collection of objects from a query expression that is of a specific type.| |[Named Type Constructor](named-type-constructor-entity-sql.md)|Used to create instances of entity types or complex types.| |[MULTISET](multiset-entity-sql.md)|Creates an instance of a multiset from a list of values.| diff --git a/docs/framework/data/adonet/sql-server-connection-pooling.md b/docs/framework/data/adonet/sql-server-connection-pooling.md index 6e551a7833ead..9de286b57872b 100644 --- a/docs/framework/data/adonet/sql-server-connection-pooling.md +++ b/docs/framework/data/adonet/sql-server-connection-pooling.md @@ -66,8 +66,7 @@ using (SqlConnection connection = new SqlConnection( > [!NOTE] > Do not call `Close` or `Dispose` on a `Connection`, a `DataReader`, or any other managed object in the `Finalize` method of your class. In a finalizer, only release unmanaged resources that your class owns directly. If your class does not own any unmanaged resources, do not include a `Finalize` method in your class definition. For more information, see [Garbage Collection](../../../../docs/standard/garbage-collection/index.md). -> [!NOTE] -> Login and logout events will not be raised on the server when a connection is fetched from or returned to the connection pool. This is because the connection is not actually closed when it is returned to the connection pool. For more information, see [Audit Login Event Class](http://msdn2.microsoft.com/library/ms190260.aspx) and [Audit Logout Event Class](http://msdn2.microsoft.com/library/ms175827.aspx) in SQL Server Books Online. +For more info about the events associated with opening and closing connections, see [Audit Login Event Class](/sql/relational-databases/event-classes/audit-login-event-class) and [Audit Logout Event Class](/sql/relational-databases/event-classes/audit-logout-event-class) in the SQL Server documentation. ## Removing Connections The connection pooler removes a connection from the pool after it has been idle for approximately 4-8 minutes, or if the pooler detects that the connection with the server has been severed. Note that a severed connection can be detected only after attempting to communicate with the server. If a connection is found that is no longer connected to the server, it is marked as invalid. Invalid connections are removed from the connection pool only when they are closed or reclaimed. diff --git a/docs/framework/interop/how-to-generate-interop-assemblies-from-type-libraries.md b/docs/framework/interop/how-to-generate-interop-assemblies-from-type-libraries.md index 35abea6d41e57..1f53afe8168f3 100644 --- a/docs/framework/interop/how-to-generate-interop-assemblies-from-type-libraries.md +++ b/docs/framework/interop/how-to-generate-interop-assemblies-from-type-libraries.md @@ -26,13 +26,13 @@ The [Type Library Importer (Tlbimp.exe)](../../../docs/framework/tools/tlbimp-ex The following command produces the Loanlib.dll assembly in the `Loanlib` namespace. ``` -tlbimp Loanlib.dll +tlbimp Loanlib.tlb ``` The following command produces an interop assembly with an altered name (LOANLib.dll). ``` -tlbimp LoanLib.dll /out: LOANLib.dll +tlbimp LoanLib.tlb /out: LOANLib.dll ``` ## See Also diff --git a/docs/framework/net-native/migrating-your-windows-store-app-to-net-native.md b/docs/framework/net-native/migrating-your-windows-store-app-to-net-native.md index fb6f696f71e40..33233d690d054 100644 --- a/docs/framework/net-native/migrating-your-windows-store-app-to-net-native.md +++ b/docs/framework/net-native/migrating-your-windows-store-app-to-net-native.md @@ -6,7 +6,7 @@ author: "rpetrusha" ms.author: "ronpet" --- # Migrating Your Windows Store App to .NET Native -[!INCLUDE[net_native](../../../includes/net-native-md.md)] provides static compilation of apps in the Windows Store or on the developer’s computer. This differs from the dynamic compilation performed for Windows Store apps by the just-in-time (JIT) compiler or the [Native Image Generator (Ngen.exe)](../../../docs/framework/tools/ngen-exe-native-image-generator.md) on the device. Despite the differences, [!INCLUDE[net_native](../../../includes/net-native-md.md)] tries to maintain compatibility with the [.NET for Windows Store apps](http://msdn.microsoft.com/library/windows/apps/br230302.aspx). For the most part, things that work on the .NET for Windows Store apps also work with [!INCLUDE[net_native](../../../includes/net-native-md.md)]. However, in some cases, you may encounter behavioral changes. This document discusses these differences between the standard .NET for Windows Store apps and [!INCLUDE[net_native](../../../includes/net-native-md.md)] in the following areas: +.NET Native provides static compilation of apps in the Windows Store or on the developer’s computer. This differs from the dynamic compilation performed for Windows Store apps by the just-in-time (JIT) compiler or the [Native Image Generator (Ngen.exe)](../../../docs/framework/tools/ngen-exe-native-image-generator.md) on the device. Despite the differences, .NET Native tries to maintain compatibility with the [.NET for Windows Store apps](http://msdn.microsoft.com/library/windows/apps/br230302.aspx). For the most part, things that work on the .NET for Windows Store apps also work with .NET Native. However, in some cases, you may encounter behavioral changes. This document discusses these differences between the standard .NET for Windows Store apps and .NET Native in the following areas: - [General runtime differences](#Runtime) @@ -21,36 +21,36 @@ ms.author: "ronpet" ## General runtime differences -- Exceptions, such as , that are thrown by the JIT compiler when an app runs on the common language runtime (CLR) generally result in compile-time errors when processed by [!INCLUDE[net_native](../../../includes/net-native-md.md)]. +- Exceptions, such as , that are thrown by the JIT compiler when an app runs on the common language runtime (CLR) generally result in compile-time errors when processed by .NET Native. -- Don't call the method from an app's UI thread. This can result in a deadlock on [!INCLUDE[net_native](../../../includes/net-native-md.md)]. +- Don't call the method from an app's UI thread. This can result in a deadlock on .NET Native. -- Don't rely on static class constructor invocation ordering. In [!INCLUDE[net_native](../../../includes/net-native-md.md)], the invocation order is different from the order on the standard runtime. (Even with the standard runtime, you shouldn't rely on the order of execution of static class constructors.) +- Don't rely on static class constructor invocation ordering. In .NET Native, the invocation order is different from the order on the standard runtime. (Even with the standard runtime, you shouldn't rely on the order of execution of static class constructors.) - Infinite looping without making a call (for example, `while(true);`) on any thread may bring the app to a halt. Similarly, large or infinite waits may bring the app to a halt. -- Certain generic initialization cycles don't throw exceptions in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. For example, the following code throws a exception on the standard CLR. In [!INCLUDE[net_native](../../../includes/net-native-md.md)], it doesn't. +- Certain generic initialization cycles don't throw exceptions in .NET Native. For example, the following code throws a exception on the standard CLR. In .NET Native, it doesn't. [!code-csharp[ProjectN#8](../../../samples/snippets/csharp/VS_Snippets_CLR/projectn/cs/compat1.cs#8)] -- In some cases, [!INCLUDE[net_native](../../../includes/net-native-md.md)] provides different implementations of .NET Framework class libraries. An object returned from a method will always implement the members of the returned type. However, since its backing implementation is different, you may not be able to cast it to the same set of types as you could on other .NET Framework platforms. For example, in some cases, you may not be able to cast the interface object returned by methods such as or to `T[]`. +- In some cases, .NET Native provides different implementations of .NET Framework class libraries. An object returned from a method will always implement the members of the returned type. However, since its backing implementation is different, you may not be able to cast it to the same set of types as you could on other .NET Framework platforms. For example, in some cases, you may not be able to cast the interface object returned by methods such as or to `T[]`. -- The WinInet cache isn't enabled by default on .NET for Windows Store apps, but it is on [!INCLUDE[net_native](../../../includes/net-native-md.md)]. This improves performance but has working set implications. No developer action is necessary. +- The WinInet cache isn't enabled by default on .NET for Windows Store apps, but it is on .NET Native. This improves performance but has working set implications. No developer action is necessary. ## Dynamic programming differences - [!INCLUDE[net_native](../../../includes/net-native-md.md)] statically links in code from the .NET Framework to make the code app-local for maximum performance. However, binary sizes have to remain small, so the entire .NET Framework can't be brought in. The [!INCLUDE[net_native](../../../includes/net-native-md.md)] compiler resolves this limitation by using a dependency reducer that removes references to unused code. However, [!INCLUDE[net_native](../../../includes/net-native-md.md)] might not maintain or generate some type information and code when that information can't be inferred statically at compile time, but instead is retrieved dynamically at runtime. + .NET Native statically links in code from the .NET Framework to make the code app-local for maximum performance. However, binary sizes have to remain small, so the entire .NET Framework can't be brought in. The .NET Native compiler resolves this limitation by using a dependency reducer that removes references to unused code. However, .NET Native might not maintain or generate some type information and code when that information can't be inferred statically at compile time, but instead is retrieved dynamically at runtime. - [!INCLUDE[net_native](../../../includes/net-native-md.md)] does enable reflection and dynamic programming. However, not all types can be marked for reflection, because this would make the generated code size too large (especially because reflecting on public APIs in the .NET Framework is supported). The [!INCLUDE[net_native](../../../includes/net-native-md.md)] compiler makes smart choices about which types should support reflection, and it keeps the metadata and generates code only for those types. + .NET Native does enable reflection and dynamic programming. However, not all types can be marked for reflection, because this would make the generated code size too large (especially because reflecting on public APIs in the .NET Framework is supported). The .NET Native compiler makes smart choices about which types should support reflection, and it keeps the metadata and generates code only for those types. - For example, data binding requires an app to be able to map property names to functions. In .NET for Windows Store apps, the common language runtime automatically uses reflection to provide this capability for managed types and publicly available native types. In [!INCLUDE[net_native](../../../includes/net-native-md.md)], the compiler automatically includes metadata for types to which you bind data. + For example, data binding requires an app to be able to map property names to functions. In .NET for Windows Store apps, the common language runtime automatically uses reflection to provide this capability for managed types and publicly available native types. In .NET Native, the compiler automatically includes metadata for types to which you bind data. - The [!INCLUDE[net_native](../../../includes/net-native-md.md)] compiler can also handle commonly used generic types such as and , which work without requiring any hints or directives. The [dynamic](~/docs/csharp/language-reference/keywords/dynamic.md) keyword is also supported within certain limits. + The .NET Native compiler can also handle commonly used generic types such as and , which work without requiring any hints or directives. The [dynamic](~/docs/csharp/language-reference/keywords/dynamic.md) keyword is also supported within certain limits. > [!NOTE] -> You should test all dynamic code paths thoroughly when porting your app to [!INCLUDE[net_native](../../../includes/net-native-md.md)]. +> You should test all dynamic code paths thoroughly when porting your app to .NET Native. - The default configuration for [!INCLUDE[net_native](../../../includes/net-native-md.md)] is sufficient for most developers, but some developers might want to fine- tune their configurations by using a runtime directives (.rd.xml) file. In addition, in some cases, the [!INCLUDE[net_native](../../../includes/net-native-md.md)] compiler is unable to determine which metadata must be available for reflection and relies on hints, particularly in the following cases: + The default configuration for .NET Native is sufficient for most developers, but some developers might want to fine- tune their configurations by using a runtime directives (.rd.xml) file. In addition, in some cases, the .NET Native compiler is unable to determine which metadata must be available for reflection and relies on hints, particularly in the following cases: - Some constructs like and can't be determined statically. @@ -59,13 +59,13 @@ ms.author: "ronpet" > [!NOTE] > Runtime directives are defined in a runtime directives (.rd.xml) file. For general information about using this file, see [Getting Started](../../../docs/framework/net-native/getting-started-with-net-native.md). For information about the runtime directives, see [Runtime Directives (rd.xml) Configuration File Reference](../../../docs/framework/net-native/runtime-directives-rd-xml-configuration-file-reference.md). - [!INCLUDE[net_native](../../../includes/net-native-md.md)] also includes profiling tools that help the developer determine which types outside the default set should support reflection. + .NET Native also includes profiling tools that help the developer determine which types outside the default set should support reflection. ## Other reflection-related differences - There are a number of other individual reflection-related differences in behavior between the .NET for Windows Store apps and [!INCLUDE[net_native](../../../includes/net-native-md.md)]. + There are a number of other individual reflection-related differences in behavior between the .NET for Windows Store apps and .NET Native. - In [!INCLUDE[net_native](../../../includes/net-native-md.md)]: + In .NET Native: - Private reflection over types and members in the .NET Framework class library is not supported. You can, however, reflect over your own private types and members, as well as types and members in third-party libraries. @@ -81,7 +81,7 @@ ms.author: "ronpet" - You can't use reflection to get or set a pointer field. -- When the argument count is wrong and the type of one of the arguments is incorrect, [!INCLUDE[net_native](../../../includes/net-native-md.md)] throws an instead of a . +- When the argument count is wrong and the type of one of the arguments is incorrect, .NET Native throws an instead of a . - Binary serialization of exceptions is generally not supported. As a result, non-serializable objects can be added to the dictionary. @@ -101,11 +101,11 @@ ms.author: "ronpet" ### General development differences **Value types** -- If you override the and methods for a value type, don't call the base class implementations. In .NET for Windows Store apps, these methods rely on reflection. At compile time, [!INCLUDE[net_native](../../../includes/net-native-md.md)] generates an implementation that doesn't rely on runtime reflection. This means that if you don't override these two methods, they will work as expected, because [!INCLUDE[net_native](../../../includes/net-native-md.md)] generates the implementation at compile time. However, overriding these methods but calling the base class implementation results in an exception. +- If you override the and methods for a value type, don't call the base class implementations. In .NET for Windows Store apps, these methods rely on reflection. At compile time, .NET Native generates an implementation that doesn't rely on runtime reflection. This means that if you don't override these two methods, they will work as expected, because .NET Native generates the implementation at compile time. However, overriding these methods but calling the base class implementation results in an exception. - Value types larger than one megabyte aren't supported. -- Value types can't have a default constructor in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. (C# and Visual Basic prohibit default constructors on value types. However, these can be created in IL.) +- Value types can't have a default constructor in .NET Native. (C# and Visual Basic prohibit default constructors on value types. However, these can be created in IL.) **Arrays** @@ -141,39 +141,35 @@ ms.author: "ronpet" `Delegate.BeginInvoke` and `Delegate.EndInvoke` aren't supported. - **Async** - - Threading logic in overloads of Task IAsync isn't supported. - **Miscellaneous APIs** - The property throws a exception if a attribute isn't applied to the type. The GUID is used primarily for COM support. -- The method correctly parses strings that contain short dates in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. However, it doesn't maintain compatibility with the changes in date and time parsing described in the Microsoft Knowledge Base articles [KB2803771](http://support.microsoft.com/kb/2803771) and [KB2803755](http://support.microsoft.com/kb/2803755). +- The method correctly parses strings that contain short dates in .NET Native. However, it doesn't maintain compatibility with the changes in date and time parsing described in the Microsoft Knowledge Base articles [KB2803771](http://support.microsoft.com/kb/2803771) and [KB2803755](http://support.microsoft.com/kb/2803755). -- `("E")` is correctly rounded in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. In some versions of the CLR, the result string is truncated instead of rounded. +- `("E")` is correctly rounded in .NET Native. In some versions of the CLR, the result string is truncated instead of rounded. ### HttpClient differences - In [!INCLUDE[net_native](../../../includes/net-native-md.md)], the class internally uses WinINet (through the [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class) instead of the and classes used in the standard .NET for Windows Store apps. WinINet doesn't support all the configuration options that the class supports. As a result: + In .NET Native, the class internally uses WinINet (through the [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class) instead of the and classes used in the standard .NET for Windows Store apps. WinINet doesn't support all the configuration options that the class supports. As a result: -- Some of the capability properties on return `false` on [!INCLUDE[net_native](../../../includes/net-native-md.md)], whereas they return `true` in the standard .NET for Windows Store apps. +- Some of the capability properties on return `false` on .NET Native, whereas they return `true` in the standard .NET for Windows Store apps. -- Some of the configuration property `get` accessors always return a fixed value on [!INCLUDE[net_native](../../../includes/net-native-md.md)] that is different than the default configurable value in .NET for Windows Store apps. +- Some of the configuration property `get` accessors always return a fixed value on .NET Native that is different than the default configurable value in .NET for Windows Store apps. Some additional behavior differences are covered in the following subsections. **Proxy** - The [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class doesn’t support configuring or overriding the proxy on a per-request basis. This means that all requests on [!INCLUDE[net_native](../../../includes/net-native-md.md)] use the system-configured proxy server or no proxy server, depending on the value of the property. In .NET for Windows Store apps, the proxy server is defined by the property. On [!INCLUDE[net_native](../../../includes/net-native-md.md)], setting the to a value other than `null` throws a exception. The property returns `false` on [!INCLUDE[net_native](../../../includes/net-native-md.md)], whereas it returns `true` in the standard .NET Framework for Windows Store apps. + The [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class doesn’t support configuring or overriding the proxy on a per-request basis. This means that all requests on .NET Native use the system-configured proxy server or no proxy server, depending on the value of the property. In .NET for Windows Store apps, the proxy server is defined by the property. On .NET Native, setting the to a value other than `null` throws a exception. The property returns `false` on .NET Native, whereas it returns `true` in the standard .NET Framework for Windows Store apps. **Automatic redirection** - The [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class doesn't allow the maximum number of automatic redirections to be configured. The value of the property is 50 by default in the standard .NET for Windows Store apps and can be modified. On [!INCLUDE[net_native](../../../includes/net-native-md.md)], the value of this property is 10, and trying to modify it throws a exception. The property returns `false` on [!INCLUDE[net_native](../../../includes/net-native-md.md)], whereas it returns `true` in .NET for Windows Store apps. + The [HttpBaseProtocolFilter](http://msdn.microsoft.com/library/windows/apps/windows.web.http.filters.httpbaseprotocolfilter.aspx) class doesn't allow the maximum number of automatic redirections to be configured. The value of the property is 50 by default in the standard .NET for Windows Store apps and can be modified. On .NET Native, the value of this property is 10, and trying to modify it throws a exception. The property returns `false` on .NET Native, whereas it returns `true` in .NET for Windows Store apps. **Automatic decompression** - .NET for Windows Store apps allows you to set the property to , , both and , or . [!INCLUDE[net_native](../../../includes/net-native-md.md)] only supports together with , or . Trying to set the property to either or alone silently sets it to both and . + .NET for Windows Store apps allows you to set the property to , , both and , or . .NET Native only supports together with , or . Trying to set the property to either or alone silently sets it to both and . **Cookies** @@ -181,11 +177,11 @@ ms.author: "ronpet" **Credentials** - In .NET for Windows Store apps, the and properties work independently. Additionally, the property accepts any object that implements the interface. In [!INCLUDE[net_native](../../../includes/net-native-md.md)], setting the property to `true` causes the property to become `null`. In addition, the property can be set only to `null`, , or an object of type . Assigning any other object, the most popular of which is , to the property throws a . + In .NET for Windows Store apps, the and properties work independently. Additionally, the property accepts any object that implements the interface. In .NET Native, setting the property to `true` causes the property to become `null`. In addition, the property can be set only to `null`, , or an object of type . Assigning any other object, the most popular of which is , to the property throws a . **Other unsupported or unconfigurable features** - In [!INCLUDE[net_native](../../../includes/net-native-md.md)]: + In .NET Native: - The value of the property is always . In .NET for Windows Store apps, the default is . @@ -199,7 +195,7 @@ ms.author: "ronpet" ### Interop differences **Deprecated APIs** - A number of infrequently used APIs for interoperability with managed code have been deprecated. When used with [!INCLUDE[net_native](../../../includes/net-native-md.md)], these APIs may throw a or exception, or result in a compiler error. In .NET for Windows Store apps, these APIs are marked as obsolete, although calling them generates a compiler warning rather than a compiler error. + A number of infrequently used APIs for interoperability with managed code have been deprecated. When used with .NET Native, these APIs may throw a or exception, or result in a compiler error. In .NET for Windows Store apps, these APIs are marked as obsolete, although calling them generates a compiler warning rather than a compiler error. Deprecated APIs for `VARIANT` marshaling: @@ -232,7 +228,7 @@ ms.author: "ronpet" || || - Deprecated APIs in the interface, which isn't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]: + Deprecated APIs in the interface, which isn't supported in .NET Native: |Type|Member| |----------|------------| @@ -270,7 +266,7 @@ ms.author: "ronpet" **Platform invoke and COM interop compatibility** - Most platform invoke and COM interop scenarios are still supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. In particular, all interoperability with Windows Runtime (WinRT) APIs and all marshaling required for the Windows Runtime is supported. This includes marshaling support for: + Most platform invoke and COM interop scenarios are still supported in .NET Native. In particular, all interoperability with Windows Runtime (WinRT) APIs and all marshaling required for the Windows Runtime is supported. This includes marshaling support for: - Arrays (including ) @@ -318,7 +314,7 @@ ms.author: "ronpet" - [IUnknown](http://msdn.microsoft.com/library/windows/desktop/ms680509.aspx) - However, [!INCLUDE[net_native](../../../includes/net-native-md.md)] doesn't support the following: + However, .NET Native doesn't support the following: - Using classic COM events @@ -330,11 +326,11 @@ ms.author: "ronpet" ### Other differences from .NET APIs for Windows Store apps - This section lists the remaining APIs that aren't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. The largest set of the unsupported APIs are Windows Communication Foundation (WCF) APIs. + This section lists the remaining APIs that aren't supported in .NET Native. The largest set of the unsupported APIs are Windows Communication Foundation (WCF) APIs. **DataAnnotations (System.ComponentModel.DataAnnotations)** - The types in the and namespaces aren't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. These include the following types that are present in the .NET for Windows Store apps for Windows 8: + The types in the and namespaces aren't supported in .NET Native. These include the following types that are present in the .NET for Windows Store apps for Windows 8: || |-| @@ -366,7 +362,7 @@ ms.author: "ronpet" **Visual Basic** - Visual Basic isn't currently supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. The following types in the and namespaces aren't available in [!INCLUDE[net_native](../../../includes/net-native-md.md)]: + Visual Basic isn't currently supported in .NET Native. The following types in the and namespaces aren't available in .NET Native: || |-| @@ -390,15 +386,15 @@ ms.author: "ronpet" **Reflection Context (System.Reflection.Context namespace)** - The class isn't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. + The class isn't supported in .NET Native. **RTC (System.Net.Http.Rtc)** - The class isn't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. + The class isn't supported in .NET Native. **Windows Communication Foundation (WCF) (System.ServiceModel.\*)** - The types in the [System.ServiceModel.* namespaces](http://msdn.microsoft.com/library/gg145010.aspx) aren't supported in [!INCLUDE[net_native](../../../includes/net-native-md.md)]. These includes the following types: + The types in the [System.ServiceModel.* namespaces](http://msdn.microsoft.com/library/gg145010.aspx) aren't supported in .NET Native. These includes the following types: || |-| @@ -584,7 +580,7 @@ ms.author: "ronpet" ### Differences in serializers The following differences concern serialization and deserialization with the , , and classes: -- In [!INCLUDE[net_native](../../../includes/net-native-md.md)], and fail to serialize or deserialize a derived class that has a base class member whose type isn't a root serialization type. For example, in the following code, trying to serialize or deserialize `Y` results in an error: +- In .NET Native, and fail to serialize or deserialize a derived class that has a base class member whose type isn't a root serialization type. For example, in the following code, trying to serialize or deserialize `Y` results in an error: [!code-csharp[ProjectN#10](../../../samples/snippets/csharp/VS_Snippets_CLR/projectn/cs/compat3.cs#10)] @@ -646,7 +642,7 @@ ms.author: "ronpet" ## Visual Studio differences **Exceptions and debugging** - When you're running apps compiled by using [!INCLUDE[net_native](../../../includes/net-native-md.md)] in the debugger, first-chance exceptions are enabled for the following exception types: + When you're running apps compiled by using .NET Native in the debugger, first-chance exceptions are enabled for the following exception types: - @@ -666,7 +662,7 @@ ms.author: "ronpet" **Unit Test Library projects** - Enabling [!INCLUDE[net_native](../../../includes/net-native-md.md)] on a Unit Test Library for a Windows Store apps project isn't supported and causes the project to fail to build. + Enabling .NET Native on a Unit Test Library for a Windows Store apps project isn't supported and causes the project to fail to build. ## See Also [Getting Started](../../../docs/framework/net-native/getting-started-with-net-native.md) diff --git a/docs/fsharp/get-started/get-started-command-line.md b/docs/fsharp/get-started/get-started-command-line.md index e0382c0450b1a..9f92639fefcad 100644 --- a/docs/fsharp/get-started/get-started-command-line.md +++ b/docs/fsharp/get-started/get-started-command-line.md @@ -9,21 +9,21 @@ This article covers how you can get started with F# on any operating system (Win ## Prerequisites -To begin, you must install the [.NET Core SDK 1.0 or later](https://www.microsoft.com/net/download/). There is no need to uninstall a previous version of the .NET Core SDK, as it supports side-by-side installations. +To begin, you must install the latest [.NET Core SDK](https://www.microsoft.com/net/download/). -This article assumes that you know how to use a command line and have a preferred text editor. If you don't already use it, [Visual Studio Code](https://code.visualstudio.com) is a great option as a text editor for F#. To get awesome features like IntelliSense, better syntax highlighting, and more, you can download the [Ionide Extension](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp). +This article assumes that you know how to use a command line and have a preferred text editor. If you don't already use it, [Visual Studio Code](get-started-vscode.md) is a great option as a text editor for F#. ## Build a simple multi-project solution Open a command prompt/terminal and use the [dotnet new](../../core/tools/dotnet-new.md) command to create new solution file called `FSNetCore`: -``` +```console dotnet new sln -o FSNetCore ``` The following directory structure is produced after running the previous command: -``` +```console FSNetCore ├── FSNetCore.sln ``` @@ -34,13 +34,13 @@ Change directories to *FSNetCore*. Use the `dotnet new` command, create a class library project in the **src** folder named Library. -``` +```console dotnet new lib -lang F# -o src/Library ``` The following directory structure is produced after running the previous command: -``` +```console └── FSNetCore ├── FSNetCore.sln └── src @@ -62,29 +62,29 @@ let getJsonNetJson value = Add the Newtonsoft.Json NuGet package to the Library project. -``` +```console dotnet add src/Library/Library.fsproj package Newtonsoft.Json ``` Add the `Library` project to the `FSNetCore` solution using the [dotnet sln add](../../core/tools/dotnet-sln.md) command: -``` +```console dotnet sln add src/Library/Library.fsproj ``` -Restore the NuGet dependencies using the `dotnet restore` command ([see note](#dotnet-restore-note)) and run `dotnet build` to build the project. +Run `dotnet build` to build the project. Unresolved dependencies will be restored when building. ### Write a console application that consumes the class library Use the `dotnet new` command, create a console application in the **src** folder named App. -``` +```console dotnet new console -lang F# -o src/App ``` The following directory structure is produced after running the previous command: -``` +```console └── FSNetCore ├── FSNetCore.sln └── src @@ -115,13 +115,13 @@ let main argv = Add a reference to the `Library` project using [dotnet add reference](../../core/tools/dotnet-add-reference.md). -``` +```console dotnet add src/App/App.fsproj reference src/Library/Library.fsproj ``` Add the `App` project to the `FSNetCore` solution using the `dotnet sln add` command: -``` +```console dotnet sln add src/App/App.fsproj ``` @@ -129,19 +129,20 @@ Restore the NuGet dependencies, `dotnet restore` ([see note](#dotnet-restore-not Change directory to the `src/App` console project and run the project passing `Hello World` as arguments: -``` +```console cd src/App dotnet run Hello World ``` You should see the following results: -``` +```console Nice command-line arguments! Here's what JSON.NET has to say about them: I used to be Hello but now I'm ""Hello"" thanks to JSON.NET! I used to be World but now I'm ""World"" thanks to JSON.NET! ``` - -[!INCLUDE[DotNet Restore Note](~/includes/dotnet-restore-note.md)] \ No newline at end of file +## Next steps + +Next, check out the [Tour of F#](../tour.md) to learn more about different F# features. \ No newline at end of file diff --git a/docs/fsharp/get-started/get-started-visual-studio.md b/docs/fsharp/get-started/get-started-visual-studio.md index c7c37da5407e2..c0e601844431e 100644 --- a/docs/fsharp/get-started/get-started-visual-studio.md +++ b/docs/fsharp/get-started/get-started-visual-studio.md @@ -1,29 +1,13 @@ --- title: Get started with F# in Visual Studio description: Learn how to use F# with Visual Studio. -ms.date: 02/13/2017 +ms.date: 07/03/2018 --- # Get started with F# in Visual Studio -F# and the Visual F# tooling are supported in the Visual Studio IDE. To begin, you should [download Visual Studio](https://aka.ms/vsdownload?utm_source=mscom&utm_campaign=msdocs), if you haven't already. This article uses the Visual Studio 2017 Community Edition, but you can use F# with the version of your choice. +F# and the Visual F# tooling are supported in the Visual Studio IDE. -## Installing F# # - -If you're downloading Visual Studio for the first time, it will first install the Visual Studio installer. Install any version of Visual Studio 2017 from the installer. If you already have it installed, click **Modify**. - -You'll next see a list of Workloads. You can install F# through any of the following workloads: - -|Workload|Action| -|--------|------| -| .NET Core cross-platform development | No action - F# is installed by default | -| ASP.NET and web development | No action - F# is installed by default | -| Azure development | No action - F# is installed by default | -| Mobile development with .NET | No action - F# is installed by default | -| Data science and analytical applications | No action - F# is installed by default | -| .NET desktop development | Select **F# desktop language support** from the right-hand side | -| Data storage and processing | Select **F# desktop language support** from the right-hand side | - -Next, click **Modify** in the lower right-hand side. This will install everything you have selected. You can then open Visual Studio 2017 with F# language support by clicking **Launch**. +To begin, ensure that you have [Visual Studio installed with F#](install-fsharp.md#install-f-with-visual-studio). ## Creating a console application @@ -72,8 +56,7 @@ Congratulations! You've created your first F# project in Visual Studio, written If you haven't already, check out the [Tour of F#](../tour.md), which covers some of the core features of the F# language. It will give you an overview of some of the capabilities of F#, and provide ample code samples that you can copy into Visual Studio and run. There are also some great external resources you can use, showcased in the [F# Guide](../index.md). ## See also - [Visual F#](index.md) - [Tour of F#](../tour.md) - [F# language reference](../language-reference/index.md) - [Type inference](../language-reference/type-inference.md) - [Symbol and operator reference](../language-reference/symbol-and-operator-reference/index.md) + [Tour of F#](../tour.md) + [F# language reference](../language-reference/index.md) + [Type inference](../language-reference/type-inference.md) + [Symbol and operator reference](../language-reference/symbol-and-operator-reference/index.md) diff --git a/docs/fsharp/get-started/get-started-vscode.md b/docs/fsharp/get-started/get-started-vscode.md index 92fd4ec67e57b..c9eaa7045bf9d 100644 --- a/docs/fsharp/get-started/get-started-vscode.md +++ b/docs/fsharp/get-started/get-started-vscode.md @@ -5,48 +5,9 @@ ms.date: 05/28/2018 --- # Get Started with F# in Visual Studio Code -You can write F# in [Visual Studio Code](https://code.visualstudio.com) with the [Ionide plugin](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp), to get a great cross-platform, lightweight Integrated Development Environment (IDE) experience with IntelliSense and basic code refactorings. Visit [Ionide.io](http://ionide.io) to learn more about the plugin suite. +You can write F# in [Visual Studio Code](https://code.visualstudio.com) with the [Ionide plugin](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp) to get a great cross-platform, lightweight Integrated Development Environment (IDE) experience with IntelliSense and basic code refactorings. Visit [Ionide.io](http://ionide.io) to learn more about the plugin. -## Prerequisites - -You must have [git installed](https://git-scm.com/download) and available on your PATH to make use of project templates in Ionide. You can verify that it is installed correctly by typing `git --version` at a command prompt and pressing **Enter**. - -### [macOS](#tab/macos) - -Ionide uses [Mono](http://www.mono-project.com). The easiest way to install Mono on macOS is via Homebrew. Simply type the following into your terminal: - -``` -brew install mono -``` - -You must also install the [.NET Core SDK](https://www.microsoft.com/net/download). - -### [Linux](#tab/linux) - -On Linux, Ionide also uses [Mono](https://www.mono-project.com). If you're on Debian or Ubuntu, you can use the following: - -``` -sudo apt-get update -sudo apt-get install mono-complete fsharp -``` - -You must also install the [.NET Core SDK](https://www.microsoft.com/net/download). - -### [Windows](#tab/windows) - -If you're on Windows, you must [install Visual Studio with F# support](get-started-visual-studio.md#installing-f). This installs all the necessary components to write, compile, and execute F# code. - -You must also install the [.NET Core SDK](https://www.microsoft.com/net/download/). - ---- - -## Installing Visual Studio Code and the Ionide plugin - -You can install Visual Studio Code from the [code.visualstudio.com](https://code.visualstudio.com) website. - -Next, click the Extensions icon and search for "Ionide": - -The only plugin required for F# support in Visual Studio Code is [Ionide-fsharp](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp). However, you can also install [Ionide-FAKE](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-FAKE) to get [FAKE](https://fsharp.github.io/FAKE/) support and [Ionide-Paket](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-Paket) to get [Paket](https://fsprojects.github.io/Paket/) support. FAKE and Paket are additional F# community tools for building projects and managing dependencies, respectively. +To begin, ensure that you have [F# and the Ionide plugin correctly installed](install-fsharp.md#install-f-with-visual-studio-code). ## Creating your first project with Ionide diff --git a/docs/fsharp/get-started/get-started-with-visual-studio-for-mac.md b/docs/fsharp/get-started/get-started-with-visual-studio-for-mac.md index e7ab6faaa0ac4..51a6349eec107 100644 --- a/docs/fsharp/get-started/get-started-with-visual-studio-for-mac.md +++ b/docs/fsharp/get-started/get-started-with-visual-studio-for-mac.md @@ -1,17 +1,11 @@ --- title: Get started with F# in Visual Studio for Mac description: Learn how to use F# with Visual Studio for Mac. -ms.date: 02/13/2017 +ms.date: 07/03/2018 --- # Get started with F# in Visual Studio for Mac -F# and the Visual F# tooling are supported in the Visual Studio for Mac IDE. To begin, you should [download Visual Studio for Mac](https://aka.ms/vsdownload?utm_source=mscom&utm_campaign=msdocs), if you haven't already. This article uses the Visual Studio Community 2017 for Mac, but you can use F# with the version of your choice. - -## Installing F# # - -After downloading Visual Studio for Mac, it will prompt you to choose what you want to install. For the purposes of this article we will be leaving the defaults. In contrast to Visual Studio for Windows, you do not need to specifically install F# support. Press "Install" to proceed. - -After the install completes, choose "Start Visual Studio". You can also launch it through Finder on macOS. +F# and the Visual F# tooling are supported in the Visual Studio for Mac IDE. Ensure that you have [Visual Studio for Mac installed](install-fsharp.md#install-f-with-visual-studio-for-mac). ## Creating a console application diff --git a/docs/fsharp/get-started/install-fsharp.md b/docs/fsharp/get-started/install-fsharp.md new file mode 100644 index 0000000000000..7237fc0830772 --- /dev/null +++ b/docs/fsharp/get-started/install-fsharp.md @@ -0,0 +1,62 @@ +--- +title: Install F# +description: Learn how to install F# based on your environment. +ms.date: 07/03/2018 +--- + +# Install F# # + +You can install F# in multiple ways, depending on your environment. + +## Install F# with Visual Studio + +If you're downloading [Visual Studio](https://visualstudio.microsoft.com/) for the first time, it will first install the Visual Studio installer. Install the appropriate SKU of Visual Studio from the installer. If you already have it installed, click **Modify**. + +You'll next see a list of Workloads. Select **ASP.NET and web development**, which will install F# support, .NET Core support, and F# support for ASP.NET Core projects. + +Next, click **Modify** in the lower right-hand side. This will install everything you have selected. You can then open Visual Studio 2017 with F# language support by clicking **Launch**. + +## Install F# with Visual Studio for Mac + +F# is installed by default in [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/), no matter what configuration you choose. + +After the install completes, choose "Start Visual Studio". You can also launch it through Finder on macOS. + +## Install F# with Visual Studio Code + +You must have [git installed](https://git-scm.com/download) and available on your PATH to make use of project templates in Ionide. You can verify that it is installed correctly by typing `git --version` at a command prompt and pressing **Enter**. + +### [macOS](#tab/macos) + +Ionide uses [Mono](http://www.mono-project.com). The easiest way to install Mono on macOS is via Homebrew. Simply type the following into your terminal: + +```console +brew install mono +``` + +You must also install the [.NET Core SDK](https://www.microsoft.com/net/download). + +### [Linux](#tab/linux) + +On Linux, Ionide also uses [Mono](https://www.mono-project.com). If you're on Debian or Ubuntu, you can use the following: + +```console +sudo apt-get update +sudo apt-get install mono-complete fsharp +``` + +You must also install the [.NET Core SDK](https://www.microsoft.com/net/download). + +### [Windows](#tab/windows) + +If you're on Windows, you must [install Visual Studio with F# support](#install-f-with-visual-studio). This installs all the necessary components to write, compile, and execute F# code. + +You must also install the [.NET Core SDK](https://www.microsoft.com/net/download/). + +--- + +You will then need [Visual Studio Code](https://code.visualstudio.com) installed. + +Next, click the Extensions icon and search for "Ionide": + +The only plugin required for F# support in Visual Studio Code is [Ionide-fsharp](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-fsharp). However, you can also install [Ionide-FAKE](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-FAKE) to get [FAKE](https://fsharp.github.io/FAKE/) support and [Ionide-Paket](https://marketplace.visualstudio.com/items?itemName=Ionide.Ionide-Paket) to get [Paket](https://fsprojects.github.io/Paket/) support. FAKE and Paket are additional F# community tools for building projects and managing dependencies, respectively. \ No newline at end of file diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/implement-custom-http-call-retries-exponential-backoff.md b/docs/standard/microservices-architecture/implement-resilient-applications/explore-custom-http-call-retries-exponential-backoff.md similarity index 71% rename from docs/standard/microservices-architecture/implement-resilient-applications/implement-custom-http-call-retries-exponential-backoff.md rename to docs/standard/microservices-architecture/implement-resilient-applications/explore-custom-http-call-retries-exponential-backoff.md index ee80cebcfe786..dd23b3051a7fb 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/implement-custom-http-call-retries-exponential-backoff.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/explore-custom-http-call-retries-exponential-backoff.md @@ -1,17 +1,17 @@ --- -title: Implementing custom HTTP call retries with exponential backoff -description: .NET Microservices Architecture for Containerized .NET Applications | Implementing custom HTTP call retries with exponential backoff +title: Explore custom HTTP call retries with exponential backoff +description: Learn how you could implement, from scratch, HTTP call retries with exponential backoff to handle possible HTTP failure scenarios. author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- -# Implementing custom HTTP call retries with exponential backoff +# Explore custom HTTP call retries with exponential backoff -In order to create resilient microservices, you need to handle possible HTTP failure scenarios. For that purpose, you could create your own implementation of retries with exponential backoff. +To create resilient microservices, you need to handle possible HTTP failure scenarios. One way of handling those failures, although not recommended, is to create your own implementation of retries with exponential backoff. -In addition to handling temporal resource unavailability, the exponential backoff also needs to take into account that the cloud provider might throttle availability of resources to prevent usage overload. For example, creating too many connection requests very quickly might be viewed as a Denial of Service ([DoS](https://en.wikipedia.org/wiki/Denial-of-service_attack)) attack by the cloud provider. As a result, you need to provide a mechanism to scale back connection requests when a capacity threshold has been encountered. +**Important note:** This section shows you how you could create your own custom code to implement HTTP call retries. However, it is not recommended to do it by your own but to use more powerful and reliable while simpler to use mechanisms, such as `HttpClientFactory` with Polly, available since .NET Core 2.1. Those recommended approaches are explained in the next sections. -As an initial exploration, you could implement your own code with a utility class for exponential backoff as in [RetryWithExponentialBackoff.cs](https://gist.github.com/CESARDELATORRE/6d7f647b29e55fdc219ee1fd2babb260), plus code like the following (which is also available on a [GitHub repo](https://gist.github.com/CESARDELATORRE/d80c6423a1aebaffaf387469f5194f5b)). +As an initial exploration, you could implement your own code with a utility class for exponential backoff as in [RetryWithExponentialBackoff.cs](https://gist.github.com/CESARDELATORRE/6d7f647b29e55fdc219ee1fd2babb260), plus code like the following (which is also available at this [GitHub repo](https://gist.github.com/CESARDELATORRE/d80c6423a1aebaffaf387469f5194f5b)). ```csharp public sealed class RetryWithExponentialBackoff @@ -107,9 +107,11 @@ public async Task GetCatalogItems(int page,int take, int? brand, int? t } ``` -However, this code is suitable only as a proof of concept. The next topic explains how to use more sophisticated and proven libraries. +Remember that this code is suitable only as a proof of concept. +The next sections explain how to use more sophisticated approaches while simpler, by using HttpClientFactory. +HttpClientFactory is available since .NET Core 2.1, with proven resiliency libraries like Polly. >[!div class="step-by-step"] [Previous](implement-resilient-entity-framework-core-sql-connections.md) -[Next](implement-http-call-retries-exponential-backoff-polly.md) +[Next](use-httpclientfactory-to-implement-resilient-http-requests.md) \ No newline at end of file diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/handle-partial-failure.md b/docs/standard/microservices-architecture/implement-resilient-applications/handle-partial-failure.md index 25eda515ffd6a..2c43e9c6b3f41 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/handle-partial-failure.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/handle-partial-failure.md @@ -3,11 +3,11 @@ title: Handling partial failure description: .NET Microservices Architecture for Containerized .NET Applications | Handling partial failure author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- # Handling partial failure -In distributed systems like microservices-based applications, there is an ever-present risk of partial failure. For instance, a single microservice/container can fail or might not be available to respond for a short time, or a single VM or server can crash. Since clients and services are separate processes, a service might not be able to respond in a timely way to a client’s request. The service might be overloaded and responding extremely slowly to requests, or might simply not be accessible for a short time because of network issues. +In distributed systems like microservices-based applications, there is an ever-present risk of partial failure. For instance, a single microservice/container can fail or might not be available to respond for a short time, or a single VM or server can crash. Since clients and services are separate processes, a service might not be able to respond in a timely way to a client’s request. The service might be overloaded and responding extremely slowly to requests or might simply not be accessible for a short time because of network issues. For example, consider the Order details page from the eShopOnContainers sample application. If the ordering microservice is unresponsive when the user tries to submit an order, a bad implementation of the client process (the MVC web application)—for example, if the client code were to use synchronous RPCs with no timeout—would block threads indefinitely waiting for a response. In addition to creating a bad user experience, every unresponsive wait consumes or blocks a thread, and threads are extremely valuable in highly scalable applications. If there are many blocked threads, eventually the application’s runtime can run out of threads. In that case, the application can become globally unresponsive instead of just partially unresponsive, as show in Figure 10-1. @@ -21,7 +21,7 @@ In a large microservices-based application, any partial failure can be amplified **Figure 10-2**. The impact of having an incorrect design featuring long chains of HTTP requests -Intermittent failure is virtually guaranteed in a distributed and cloud based system, even if every dependency itself has excellent availability. This should be a fact you need to consider. +Intermittent failure is guaranteed in a distributed and cloud-based system, even if every dependency itself has excellent availability. It is fact you need to consider. If you do not design and implement techniques to ensure fault tolerance, even small downtimes can be amplified. As an example, 50 dependencies each with 99.99% of availability would result in several hours of downtime each month because of this ripple effect. When a microservice dependency fails while handling a high volume of requests, that failure can quickly saturate all available request threads in each service and crash the whole application. @@ -29,7 +29,7 @@ If you do not design and implement techniques to ensure fault tolerance, even sm **Figure 10-3**. Partial failure amplified by microservices with long chains of synchronous HTTP calls -To minimize this problem, in the section "*Asynchronous microservice integration enforce microservice’s autonomy*” (in the architecture chapter), we encouraged you to use asynchronous communication across the internal microservices. We briefly explain more in the next section. +To minimize this problem, in the section "*Asynchronous microservice integration enforce microservice’s autonomy*” (in the architecture chapter), this guidance encourages you to use asynchronous communication across the internal microservices. In addition, it is essential that you design your microservices and client applications to handle partial failures—that is, to build resilient microservices and client applications. diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern.md b/docs/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern.md index 06ac34b261029..b1e5009a78a07 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/implement-circuit-breaker-pattern.md @@ -1,167 +1,98 @@ --- title: Implementing the Circuit Breaker pattern -description: .NET Microservices Architecture for Containerized .NET Applications | Implementing the Circuit Breaker pattern +description: .NET Microservices Architecture for Containerized .NET Applications | Implement the Circuit Breaker pattern as a complementary system to Http retries author: CESARDELATORRE ms.author: wiwagn -ms.date: 11/12/2017 +ms.date: 07/03/2018 --- -# Implementing the Circuit Breaker pattern -As noted earlier, you should handle faults that might take a variable amount of time to recover from, as might happen when you try to connect to a remote service or resource. Handling this type of fault can improve the stability and resiliency of an application. +# Implement the Circuit Breaker pattern -In a distributed environment, calls to remote resources and services can fail due to transient faults, such as slow network connections and timeouts, or if resources are being slow or are temporarily unavailable. These faults typically correct themselves after a short time, and a robust cloud application should be prepared to handle them by using a strategy like the Retry pattern. +As noted earlier, you should handle faults that might take a variable amount of time to recover from, as it might happen when you try to connect to a remote service or resource. Handling this type of fault can improve the stability and resiliency of an application. -However, there can also be situations where faults are due to unanticipated events that might take much longer to fix. These faults can range in severity from a partial loss of connectivity to the complete failure of a service. In these situations, it might be pointless for an application to continually retry an operation that is unlikely to succeed. Instead, the application should be coded to accept that the operation has failed and handle the failure accordingly. +In a distributed environment, calls to remote resources and services can fail due to transient faults, such as slow network connections and timeouts, or if resources are being slow or are temporarily unavailable. These faults typically correct themselves after a short time, and a robust cloud application should be prepared to handle them by using a strategy like the "Retry pattern". -The Circuit Breaker pattern has a different purpose than the Retry pattern. The Retry pattern enables an application to retry an operation in the expectation that the operation will eventually succeed. The Circuit Breaker pattern prevents an application from performing an operation that is likely to fail. An application can combine these two patterns by using the Retry pattern to invoke an operation through a circuit breaker. However, the retry logic should be sensitive to any exceptions returned by the circuit breaker, and it should abandon retry attempts if the circuit breaker indicates that a fault is not transient. +However, there can also be situations where faults are due to unanticipated events that might take much longer to fix. These faults can range in severity from a partial loss of connectivity to the complete failure of a service. In these situations, it might be pointless for an application to continually retry an operation that is unlikely to succeed. -## Implementing a Circuit Breaker pattern with Polly +Instead, the application should be coded to accept that the operation has failed and handle the failure accordingly. -As when implementing retries, the recommended approach for circuit breakers is to take advantage of proven .NET libraries like Polly. +Using Http retries carelessly could result in creating a Denial of Service ([DoS](https://en.wikipedia.org/wiki/Denial-of-service_attack)) attack within your own software. As a microservice fails or performs slowly, multiple clients might repeatedly retry failed requests. That creates a dangerous risk of exponentially increasing traffic targeted at the failing service. -The eShopOnContainers application uses the Polly Circuit Breaker policy when implementing HTTP retries. In fact, the application applies both policies to the ResilientHttpClient utility class. Whenever you use an object of type ResilientHttpClient for HTTP requests (from eShopOnContainers), you will be applying both those policies, but you could add additional policies, too. +Therefore, you need some kind of defense barrier so the retries stop requests when it is not worth to keep trying. That defense barrier is precisely the circuit breaker. -The only addition here to the code used for HTTP call retries is the code where you add the Circuit Breaker policy to the list of policies to use, as shown at the end of the following code: +The Circuit Breaker pattern has a different purpose than the "Retry pattern". The "Retry pattern" enables an application to retry an operation in the expectation that the operation will eventually succeed. The Circuit Breaker pattern prevents an application from performing an operation that is likely to fail. An application can combine these two patterns. However, the retry logic should be sensitive to any exception returned by the circuit breaker, and it should abandon retry attempts if the circuit breaker indicates that a fault is not transient. -```csharp -public ResilientHttpClient CreateResilientHttpClient() - => new ResilientHttpClient(CreatePolicies(), _logger); +## Implement Circuit Breaker pattern with HttpClientFactory and Polly -private Policy[] CreatePolicies() - => new Policy[] - { - Policy.Handle() - .WaitAndRetryAsync( - // number of retries - 6, - // exponential backofff - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), - // on retry - (exception, timeSpan, retryCount, context) => - { - var msg = $"Retry {retryCount} implemented with Polly RetryPolicy " + - $"of {context.PolicyKey} " + - $"at {context.ExecutionKey}, " + - $"due to: {exception}."; - _logger.LogWarning(msg); - _logger.LogDebug(msg); - }), - Policy.Handle() - .CircuitBreakerAsync( - // number of exceptions before breaking circuit - 5, - // time circuit opened before retry - TimeSpan.FromMinutes(1), - (exception, duration) => - { - // on circuit opened - _logger.LogTrace("Circuit breaker opened"); - }, - () => - { - // on circuit closed - _logger.LogTrace("Circuit breaker reset"); - }) - }; -} -``` +As when implementing retries, the recommended approach for circuit breakers is to take advantage of proven .NET libraries like Polly and its native integration with HttpClientFactory. -The code adds a policy to the HTTP wrapper. That policy defines a circuit breaker that opens when the code detects the specified number of consecutive exceptions (exceptions in a row), as passed in the exceptionsAllowedBeforeBreaking parameter (5 in this case). When the circuit is open, HTTP requests do not work, but an exception is raised. +Adding a circuit breaker policy into your HttpClientFactory outgoing middleware pipeline is as simple as adding a single incremental piece of code to what you already have when using HttpClientFactory. -Circuit breakers should also be used to redirect requests to a fallback infrastructure if you might have issues in a particular resource that is deployed in a different environment than the client application or service that is performing the HTTP call. That way, if there is an outage in the datacenter that impacts only your backend microservices but not your client applications, the client applications can redirect to the fallback services. Polly is planning a new policy to automate this [failover policy](https://github.com/App-vNext/Polly/wiki/Polly-Roadmap#failover-policy) scenario. +The only addition here to the code used for HTTP call retries is the code where you add the Circuit Breaker policy to the list of policies to use, as shown in the following incremental code, part of the ConfigureServices() method. -Of course, all those features are for cases where you are managing the failover from within the .NET code, as opposed to having it managed automatically for you by Azure, with location transparency. +```csharp +//ConfigureServices() - Startup.cs +services.AddHttpClient() + .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to 5 minutes + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); +``` -## Using the ResilientHttpClient utility class from eShopOnContainers +The `AddPolicyHandler()`method is what adds policies to the HttpClient objects you will use. In this case, it is adding a Polly’s policy for a circuit breaker. -You use the ResilientHttpClient utility class in a way similar to how you use the .NET HttpClient class. In the following example from the eShopOnContainers MVC web application (the OrderingService agent class used by OrderController), the ResilientHttpClient object is injected through the httpClient parameter of the constructor. Then the object is used to perform HTTP requests. +In order to have a more modular approach, the Circuit Breaker Policy is defined in a separate method named GetCircuitBreakerPolicy(), as the following code. ```csharp -public class OrderingService : IOrderingService +static IAsyncPolicy GetCircuitBreakerPolicy() { - private IHttpClient _apiClient; - private readonly string _remoteServiceBaseUrl; - private readonly IOptionsSnapshot _settings; - private readonly IHttpContextAccessor _httpContextAccesor; - - public OrderingService(IOptionsSnapshot settings, - IHttpContextAccessor httpContextAccesor, - IHttpClient httpClient) - { - _remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders"; - _settings = settings; - _httpContextAccesor = httpContextAccesor; - _apiClient = httpClient; - } - - async public Task> GetMyOrders(ApplicationUser user) - { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new - System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - var ordersUrl = _remoteServiceBaseUrl; - var dataString = await _apiClient.GetStringAsync(ordersUrl); - var response = JsonConvert.DeserializeObject>(dataString); - return response; - } - - // Other methods ... - async public Task CreateOrder(Order order) - { - var context = _httpContextAccesor.HttpContext; - var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient.Inst.DefaultRequestHeaders.Authorization = new - System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - _apiClient.Inst.DefaultRequestHeaders.Add("x-requestid", - order.RequestId.ToString()); - var ordersUrl = $"{_remoteServiceBaseUrl}/new"; - order.CardTypeId = 1; - order.CardExpirationApiFormat(); - SetFakeIdToProducts(order); - var response = await _apiClient.PostAsync(ordersUrl, order); - response.EnsureSuccessStatusCode(); - } + return HttpPolicyExtensions + .HandleTransientHttpError() + .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); } ``` -Whenever the \_apiClient member object is used, it internally uses the wrapper class with Polly policiesؙ—the Retry policy, the Circuit Breaker policy, and any other policy that you might want to apply from the Polly policies collection. +In the code example above, the circuit breaker policy is configured so it breaks or opens the circuit when there have been five exceptions when retrying the Http requests. Then, 30 seconds will be the duration or the break. -## Testing retries in eShopOnContainers +Circuit breakers should also be used to redirect requests to a fallback infrastructure if you had issues in a particular resource that is deployed in a different environment than the client application or service that is performing the HTTP call. That way, if there is an outage in the datacenter that impacts only your backend microservices but not your client applications, the client applications can redirect to the fallback services. Polly is planning a new policy to automate this [failover policy](https://github.com/App-vNext/Polly/wiki/Polly-Roadmap#failover-policy) scenario. -Whenever you start the eShopOnContainers solution in a Docker host, it needs to start multiple containers. Some of the containers are slower to start and initialize, like the SQL Server container. This is especially true the first time you deploy the eShopOnContainers application into Docker, because it needs to set up the images and the database. The fact that some containers start slower than others can cause the rest of the services to initially throw HTTP exceptions, even if you set dependencies between containers at the docker-compose level, as explained in previous sections. Those docker-compose dependencies between containers are just at the process level. The container’s entry point process might be started, but SQL Server might not be ready for queries. The result can be a cascade of errors, and the application can get an exception when trying to consume that particular container. +All those features are for cases where you're managing the failover from within the .NET code, as opposed to having it managed automatically for you by Azure, with location transparency. -You might also see this type of error on startup when the application is deploying to the cloud. In that case, orchestrators might be moving containers from one node or VM to another (that is, starting new instances) when balancing the number of containers across the cluster’s nodes. +From a usage point of view, when using HttpClient, there’s no need to add anything new here because the code is the same than when using HttpClient with HttpClientFactory, as shown in previous sections. + +## Testing Http retries and circuit breakers in eShopOnContainers -The way eShopOnContainers solves this issue is by using the Retry pattern we illustrated earlier. It is also why, when starting the solution, you might get log traces or warnings like the following: -> "**Retry 1 implemented with Polly's RetryPolicy**, due to: System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.CurlException: Couldn't connect to server\\n at System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)\\n at \[...\]. +Whenever you start the eShopOnContainers solution in a Docker host, it needs to start multiple containers. Some of the containers are slower to start and initialize, like the SQL Server container. This is especially true the first time you deploy the eShopOnContainers application into Docker, because it needs to set up the images and the database. The fact that some containers start slower than others can cause the rest of the services to initially throw HTTP exceptions, even if you set dependencies between containers at the docker-compose level, as explained in previous sections. Those docker-compose dependencies between containers are just at the process level. The container’s entry point process might be started, but SQL Server might not be ready for queries. The result can be a cascade of errors, and the application can get an exception when trying to consume that particular container. + +You might also see this type of error on startup when the application is deploying to the cloud. In that case, orchestrators might be moving containers from one node or VM to another (that is, starting new instances) when balancing the number of containers across the cluster’s nodes. -## Testing the circuit breaker in eShopOnContainers +The way 'eShopOnContainers' solves those issues when starting all the containers is by using the Retry pattern illustrated earlier. -There are a few ways you can open the circuit and test it with eShopOnContainers. +### Testing the circuit breaker in eShopOnContainers + +There are a few ways you can break/open the circuit and test it with eShopOnContainers. One option is to lower the allowed number of retries to 1 in the circuit breaker policy and redeploy the whole solution into Docker. With a single retry, there is a good chance that an HTTP request will fail during deployment, the circuit breaker will open, and you get an error. -Another option is to use custom middleware that is implemented in the `Basket` microservice. When this middleware is enabled, it catches all HTTP requests and returns status code 500. You can enable the middleware by making a GET request to the failing URI, like the following: +Another option is to use custom middleware that is implemented in the Basket microservice. When this middleware is enabled, it catches all HTTP requests and returns status code 500. You can enable the middleware by making a GET request to the failing URI, like the following: -- GET /failing +- `GET http://localhost:5103/failing` -This request returns the current state of the middleware. If the middleware is enabled, the request return status code 500. If the middleware is disabled, there is no response. +This request returns the current state of the middleware. If the middleware is enabled, the request return status code 500. If the middleware is disabled, there is no response. -- GET /failing?enable +- `GET http://localhost:5103/failing?enable` -This request enables the middleware. +This request enables the middleware. -- GET /failing?disable +- `GET http://localhost:5103/failing?disable` -This request disables the middleware. +This request disables the middleware. For instance, once the application is running, you can enable the middleware by making a request using the following URI in any browser. Note that the ordering microservice uses port 5103. -http://localhost:5103/failing?enable +`http://localhost:5103/failing?enable` -You can then check the status using the URI [http://localhost:5103/failing](http://localhost:5103/failing), as shown in Figure 10-4. +You can then check the status using the URI http://localhost:5103/failing, as shown in Figure 10-4. ![](./media/image4.png) @@ -169,9 +100,9 @@ You can then check the status using the URI [http://localhost:5103/failing](http At this point, the Basket microservice responds with status code 500 whenever you call invoke it. -Once the middleware is running, you can try making an order from the MVC web application. Because the requests fails, the circuit will open. +Once the middleware is running, you can try making an order from the MVC web application. Because the requests fail, the circuit will open. -In the following example, you can see that the MVC web application has a catch block in the logic for placing an order. If the code catches an open-circuit exception, it shows the user a friendly message telling them to wait. +In the following example, you can see that the MVC web application has a catch block in the logic for placing an order. If the code catches an open-circuit exception, it shows the user a friendly message telling them to wait. ```csharp public class CartController : Controller @@ -180,8 +111,11 @@ public class CartController : Controller public async Task Index() { try - { - //… Other code + { + var user = _appUserParser.Parse(HttpContext.User); + //Http requests using the Typed Client (Service Agent) + var vm = await _basketSvc.GetBasket(user); + return View(vm); } catch (BrokenCircuitException) { @@ -198,46 +132,23 @@ public class CartController : Controller } ``` -Here’s a summary. The Retry policy tries several times to make the HTTP request and gets HTTP errors. When the number of tries reaches the maximum number set for the Circuit Breaker policy (in this case, 5), the application throws a BrokenCircuitException. The result is a friendly message, as shown in Figure 10-5. +Here’s a summary. The Retry policy tries several times to make the HTTP request and gets HTTP errors. When the number of retries reaches the maximum number set for the Circuit Breaker policy (in this case, 5), the application throws a BrokenCircuitException. The result is a friendly message, as shown in Figure 10-5. ![](./media/image5.png) **Figure 10-5**. Circuit breaker returning an error to the UI -You can implement different logic for when to open the circuit. Or you can try an HTTP request against a different back-end microservice if there is a fallback datacenter or redundant back-end system. - -Finally, another possibility for the CircuitBreakerPolicy is to use Isolate (which forces open and holds open the circuit) and Reset (which closes it again). These could be used to build a utility HTTP endpoint that invokes Isolate and Reset directly on the policy. Such an HTTP endpoint could also be used, suitably secured, in production for temporarily isolating a downstream system, such as when you want to upgrade it. Or it could trip the circuit manually to protect a downstream system you suspect to be faulting. +You can implement different logic for when to open/break the circuit. Or you can try an HTTP request against a different back-end microservice if there is a fallback datacenter or redundant back-end system. -## Adding a jitter strategy to the retry policy +Finally, another possibility for the `CircuitBreakerPolicy` is to use `Isolate` (which forces open and holds open the circuit) and `Reset` (which closes it again). These could be used to build a utility HTTP endpoint that invokes Isolate and Reset directly on the policy. Such an HTTP endpoint could also be used, suitably secured, in production for temporarily isolating a downstream system, such as when you want to upgrade it. Or it could trip the circuit manually to protect a downstream system you suspect to be faulting. -A regular Retry policy can impact your system in cases of high concurrency and scalability and under high contention. To overcome peaks of similar retries coming from many clients in case of partial outages, a good workaround is to add a jitter strategy to the retry algorithm/policy. This can improve the overall performance of the end-to-end system by adding randomness to the exponential backoff. This spreads out the spikes when issues arise. When you use Polly, code to implement jitter could look like the following example: - -```csharp -Random jitterer = new Random(); -Policy.Handle() // etc - .WaitAndRetry(5, // exponential back-off plus some jitter - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) - + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) - ); -``` ## Additional resources -- **Retry pattern** - [*https://docs.microsoft.com/azure/architecture/patterns/retry*](https://docs.microsoft.com/azure/architecture/patterns/retry) - -- **Connection Resiliency** (Entity Framework Core) - [*https://docs.microsoft.com/ef/core/miscellaneous/connection-resiliency*](https://docs.microsoft.com/ef/core/miscellaneous/connection-resiliency) - -- **Polly** (.NET resilience and transient-fault-handling library) - [*https://github.com/App-vNext/Polly*](https://github.com/App-vNext/Polly) - **Circuit Breaker pattern** [*https://docs.microsoft.com/azure/architecture/patterns/circuit-breaker*](https://docs.microsoft.com/azure/architecture/patterns/circuit-breaker) -- **Marc Brooker. Jitter: Making Things Better With Randomness** - https://brooker.co.za/blog/2015/03/21/backoff.html - >[!div class="step-by-step"] [Previous](implement-http-call-retries-exponential-backoff-polly.md) diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md b/docs/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md index 15ce408ad139e..05f9fb2b2b5c3 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md @@ -1,169 +1,87 @@ --- -title: Implementing HTTP call retries with exponential backoff with Polly -description: .NET Microservices Architecture for Containerized .NET Applications | Implementing HTTP call retries with exponential backoff with Polly +title: Implement HTTP call retries with exponential backoff with Polly +description: Learn how to handle HTTP failures with Polly and HttpClientFactory author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/10/2018 --- -# Implementing HTTP call retries with exponential backoff with Polly -The recommended approach for retries with exponential backoff is to take advantage of more advanced .NET libraries like the open source [Polly](https://github.com/App-vNext/Polly) library. +# Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies -Polly is a .NET library that provides resilience and transient-fault handling capabilities. You can implement those capabilities easily by applying Polly policies such as Retry, Circuit Breaker, Bulkhead Isolation, Timeout, and Fallback. Polly targets .NET 4.x and the .NET Standard version 1.0 (which supports .NET Core). +The recommended approach for retries with exponential backoff is to take advantage of more advanced .NET libraries like the open-source [Polly library](https://github.com/App-vNext/Polly). -The Retry policy in Polly is the approach used in eShopOnContainers when implementing HTTP retries. You can implement an interface so you can inject either standard HttpClient functionality or a resilient version of HttpClient using Polly, depending on what retry policy configuration you want to use. +Polly is a .NET library that provides resilience and transient-fault handling capabilities. You can implement those capabilities by applying Polly policies such as Retry, Circuit Breaker, Bulkhead Isolation, Timeout, and Fallback. Polly targets .NET 4.x and the .NET Standard Library 1.0 (which supports .NET Core). -The following example shows the interface implemented in eShopOnContainers. +However, using Polly’s library with your own custom code with HttpClient can be significantly complex. In the original version of eShopOnContainers, there was a [ResilientHttpClient building-block](https://github.com/dotnet-architecture/eShopOnContainers/blob/master/src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs) based on Polly. But with the release of HttpClientFactory, resilient Http communication has become much simpler to implement, so that building-block was deprecated from eShopOnContainers. -```csharp -public interface IHttpClient -{ - Task GetStringAsync(string uri, string authorizationToken = null, - string authorizationMethod = "Bearer"); - Task PostAsync(string uri, T item, - string authorizationToken = null, string requestId = null, - string authorizationMethod = "Bearer"); +The following steps show how you can use Http retries with Polly integrated into HttpClientFactory, which is explained in the previous section. - Task DeleteAsync(string uri, - string authorizationToken = null, string requestId = null, - string authorizationMethod = "Bearer"); +**Reference the ASP.NET Core 2.1 packages** - // Other methods ... -} -``` +Your project has to be using the ASP.NET Core 2.1 packages from NuGet. You typically need the `AspNetCore` metapackage, and the extension package `Microsoft.Extensions.Http.Polly`. + +**Configure a client with Polly’s Retry policy, in Startup** -You can use the standard implementation if you do not want to use a resilient mechanism, as when you are developing or testing simpler approaches. The following code shows the standard HttpClient implementation allowing requests with authentication tokens as an optional case. +As shown in previous sections, you need to define a named or typed client HttpClient configuration in your standard Startup.ConfigureServices(...) method, but now, you add incremental code specifying the policy for the Http retries with exponential backoff, as below: ```csharp -public class StandardHttpClient : IHttpClient -{ - private HttpClient _client; - private ILogger _logger; - - public StandardHttpClient(ILogger logger) - { - _client = new HttpClient(); - _logger = logger; - } - - public async Task GetStringAsync(string uri, - string authorizationToken = null, - string authorizationMethod = "Bearer") - { - var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); - if (authorizationToken != null) - { - requestMessage.Headers.Authorization = - new AuthenticationHeaderValue(authorizationMethod, authorizationToken); - } - var response = await _client.SendAsync(requestMessage); - return await response.Content.ReadAsStringAsync(); - } - - public async Task PostAsync(string uri, T item, - string authorizationToken = null, string requestId = null, - string authorizationMethod = "Bearer") - { - // Rest of the code and other Http methods ... +//ConfigureServices() - Startup.cs +services.AddHttpClient() + .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes + .AddPolicyHandler(GetRetryPolicy()); ``` -The interesting implementation is to code another, similar class, but using Polly to implement the resilient mechanisms you want to use—in the following example, retries with exponential backoff. +The **AddPolicyHandler()** method is what adds policies to the `HttpClient` objects you will use. In this case, it is adding a Polly’s policy for Http Retries with exponential backoff. + +In order to have a more modular approach, the Http Retry Policy can be defined in a separate method within the ConfigureServices() method, as the following code. ```csharp -public class ResilientHttpClient : IHttpClient +static IAsyncPolicy GetRetryPolicy() { - private HttpClient _client; - private PolicyWrap _policyWrapper; - private ILogger _logger; - - public ResilientHttpClient(Policy[] policies, - ILogger logger) - { - _client = new HttpClient(); - _logger = logger; - // Add Policies to be applied - _policyWrapper = Policy.WrapAsync(policies); - } - - private Task HttpInvoker(Func> action) - { - // Executes the action applying all - // the policies defined in the wrapper - return _policyWrapper.ExecuteAsync(() => action()); - } - - public Task GetStringAsync(string uri, - string authorizationToken = null, - string authorizationMethod = "Bearer") - { - return HttpInvoker(async () => - { - var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); - // The Token's related code eliminated for clarity in code snippet - var response = await _client.SendAsync(requestMessage); - return await response.Content.ReadAsStringAsync(); - }); - } - // Other Http methods executed through HttpInvoker so it applies Polly policies - // ... + return HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) + .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, + retryAttempt))); } ``` -With Polly, you define a Retry policy with the number of retries, the exponential backoff configuration, and the actions to take when there is an HTTP exception, such as logging the error. In this case, the policy is configured so it will try the number of times specified when registering the types in the IoC container. Because of the exponential backoff configuration, whenever the code detects an HttpRequest exception, it retries the Http request after waiting an amount of time that increases exponentially depending on how the policy was configured. +With Polly, you can define a Retry policy with the number of retries, the exponential backoff configuration, and the actions to take when there is an HTTP exception, such as logging the error. In this case, the policy is configured to try six times with an exponential retry, starting at two seconds. + +so it will try six times and the seconds between each retry will be exponential, starting on two seconds. -The important method is HttpInvoker, which is what makes HTTP requests throughout this utility class. That method internally executes the HTTP request with \_policyWrapper.ExecuteAsync, which takes into account the retry policy. +### Adding a jitter strategy to the retry policy -In eShopOnContainers you specify Polly policies when registering the types at the IoC container, as in the following code from the [MVC web app at the startup.cs](https://github.com/dotnet-architecture/eShopOnContainers/blob/master/src/Web/WebMVC/Startup.cs) class. +A regular Retry policy can impact your system in cases of high concurrency and scalability and under high contention. To overcome peaks of similar retries coming from many clients in case of partial outages, a good workaround is to add a jitter strategy to the retry algorithm/policy. This can improve the overall performance of the end-to-end system by adding randomness to the exponential backoff. This spreads out the spikes when issues arise. When you use a plain Polly policy, code to implement jitter could look like the following example: ```csharp -// Startup.cs class -if (Configuration.GetValue("UseResilientHttp") == bool.TrueString) -{ - services.AddTransient(); - services.AddSingleton(sp => - sp.GetService(). - CreateResilientHttpClient()); -} -else -{ - services.AddSingleton(); -} +Random jitterer = new Random(); +Policy + .Handle() // etc + .WaitAndRetry(5, // exponential back-off plus some jitter + retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) + ); ``` -Note that the IHttpClient objects are instantiated as singleton instead of as transient so that TCP connections are used efficiently by the service and [an issue with sockets](https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) will not occur. +## Additional resources -But the important point about resiliency is that you apply the Polly WaitAndRetryAsync policy within ResilientHttpClientFactory in the CreateResilientHttpClient method, as shown in the following code: +- **Retry pattern** + [*https://docs.microsoft.com/azure/architecture/patterns/retry*](https://docs.microsoft.com/azure/architecture/patterns/retry) + +- **Polly and HttpClientFactory** + [*https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory*](https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory) + +- **Polly (.NET resilience and transient-fault-handling library)** + + [*https://github.com/App-vNext/Polly*](https://github.com/App-vNext/Polly) + +- **Marc Brooker. Jitter: Making Things Better With Randomness** + + [*https://brooker.co.za/blog/2015/03/21/backoff.html*](https://brooker.co.za/blog/2015/03/21/backoff.html) -```csharp -public ResilientHttpClient CreateResilientHttpClient() - => new ResilientHttpClient(CreatePolicies(), _logger); - -// Other code -private Policy[] CreatePolicies() - => new Policy[] - { - Policy.Handle() - .WaitAndRetryAsync( - // number of retries - 6, - // exponential backoff - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), - // on retry - (exception, timeSpan, retryCount, context) => - { - var msg = $"Retry {retryCount} implemented with Pollys RetryPolicy " + - $"of {context.PolicyKey} " + - $"at {context.ExecutionKey}, " + - $"due to: {exception}."; - _logger.LogWarning(msg); - _logger.LogDebug(msg); - }), - } -``` >[!div class="step-by-step"] -[Previous](implement-custom-http-call-retries-exponential-backoff.md) +[Previous](explore-custom-http-call-retries-exponential-backoff.md) [Next](implement-circuit-breaker-pattern.md) diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/implement-resilient-entity-framework-core-sql-connections.md b/docs/standard/microservices-architecture/implement-resilient-applications/implement-resilient-entity-framework-core-sql-connections.md index 374bf4c5ae6f1..dc26e59876198 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/implement-resilient-entity-framework-core-sql-connections.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/implement-resilient-entity-framework-core-sql-connections.md @@ -1,11 +1,11 @@ --- -title: Implementing resilient Entity Framework Core SQL connections -description: .NET Microservices Architecture for Containerized .NET Applications | Implementing resilient Entity Framework Core SQL connections +title: Implement resilient Entity Framework Core SQL connections +description: .NET Microservices Architecture for Containerized .NET Applications | Implement resilient Entity Framework Core SQL connections. This technique is especially important when using Azure SQL Database in the cloud. author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- -# Implementing resilient Entity Framework Core SQL connections +# Implement resilient Entity Framework Core SQL connections For Azure SQL DB, Entity Framework Core already provides internal database connection resiliency and retry logic. But you need to enable the Entity Framework execution strategy for each DbContext connection if you want to have [resilient EF Core connections](https://docs.microsoft.com/ef/core/miscellaneous/connection-resiliency). @@ -19,13 +19,13 @@ public class Startup public IServiceProvider ConfigureServices(IServiceCollection services) { // ... - services.AddDbContext(options => + services.AddDbContext(options => { options.UseSqlServer(Configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.EnableRetryOnFailure( - maxRetryCount: 5, + maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); @@ -37,7 +37,7 @@ public class Startup ## Execution strategies and explicit transactions using BeginTransaction and multiple DbContexts -When retries are enabled in EF Core connections, each operation you perform using EF Core becomes its own retriable operation. Each query and each call to SaveChanges will be retried as a unit if a transient failure occurs. +When retries are enabled in EF Core connections, each operation you perform using EF Core becomes its own retryable operation. Each query and each call to SaveChanges will be retried as a unit if a transient failure occurs. However, if your code initiates a transaction using BeginTransaction, you are defining your own group of operations that need to be treated as a unit—everything inside the transaction has be rolled back if a failure occurs. You will see an exception like the following if you attempt to execute that transaction when using an EF execution strategy (retry policy) and you include several SaveChanges calls from multiple DbContexts in the transaction. @@ -79,13 +79,15 @@ The first DbContext is \_catalogContext and the second DbContext is within the \ ## Additional resources +- **EF Connection Resiliency** (Entity Framework Core) + [*https://docs.microsoft.com/ef/core/miscellaneous/connection-resiliency*](https://docs.microsoft.com/ef/core/miscellaneous/connection-resiliency) + - **Connection Resiliency and Command Interception with the Entity Framework** [*https://docs.microsoft.com/azure/architecture/patterns/category/resiliency*](https://docs.microsoft.com/azure/architecture/patterns/category/resiliency) - **Cesar de la Torre. Using Resilient Entity Framework Core Sql Connections and Transactions** - >[!div class="step-by-step"] [Previous](implement-retries-exponential-backoff.md) -[Next](implement-custom-http-call-retries-exponential-backoff.md) +[Next]explore-custom-http-call-retries-exponential-backoff.md) diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/implement-retries-exponential-backoff.md b/docs/standard/microservices-architecture/implement-resilient-applications/implement-retries-exponential-backoff.md index 9bb966defcfc3..9abd680f524af 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/implement-retries-exponential-backoff.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/implement-retries-exponential-backoff.md @@ -1,11 +1,11 @@ --- -title: Implementing retries with exponential backoff +title: Implement retries with exponential backoff description: .NET Microservices Architecture for Containerized .NET Applications | Implementing retries with exponential backoff author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- -# Implementing retries with exponential backoff +# Implement retries with exponential backoff [*Retries with exponential backoff*](https://docs.microsoft.com/azure/architecture/patterns/retry) is a technique that attempts to retry an operation, with an exponentially increasing wait time, until a maximum retry count has been reached (the [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)). This technique embraces the fact that cloud resources might intermittently be unavailable for more than a few seconds for any reason. For example, an orchestrator might be moving a container to another node in a cluster for load balancing. During that time, some requests might fail. Another example could be a database like SQL Azure, where a database can be moved to another server for load balancing, causing the database to be unavailable for a few seconds. diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/index.md b/docs/standard/microservices-architecture/implement-resilient-applications/index.md index b0c94b3a6de9a..2094508b515b4 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/index.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/index.md @@ -3,13 +3,13 @@ title: Implementing Resilient Applications description: .NET Microservices Architecture for Containerized .NET Applications | Implementing Resilient Applications author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- # Implementing Resilient Applications -*Your microservice and cloud based applications must embrace the partial failures that will certainly occur eventually. You need to design your application so it will be resilient to those partial failures.* +*Your microservice and cloud-based applications must embrace the partial failures that will certainly occur eventually. You need to design your application so it will be resilient to those partial failures.* -Resiliency is the ability to recover from failures and continue to function. It is not about avoiding failures, but accepting the fact that failures will happen and responding to them in a way that avoids downtime or data loss. The goal of resiliency is to return the application to a fully functioning state after a failure. +Resiliency is the ability to recover from failures and continue to function. It is not about avoiding failures but accepting the fact that failures will happen and responding to them in a way that avoids downtime or data loss. The goal of resiliency is to return the application to a fully functioning state after a failure. It is challenging enough to design and deploy a microservices-based application. But you also need to keep your application running in an environment where some sort of failure is certain. Therefore, your application should be resilient. It should be designed to cope with partial failures, like network outages or nodes or VMs crashing in the cloud. Even microservices (containers) being moved to a different node within a cluster can cause intermittent short failures within the application. diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/media/image3.5.png b/docs/standard/microservices-architecture/implement-resilient-applications/media/image3.5.png new file mode 100644 index 0000000000000..21a16ed5c5bea Binary files /dev/null and b/docs/standard/microservices-architecture/implement-resilient-applications/media/image3.5.png differ diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/partial-failure-strategies.md b/docs/standard/microservices-architecture/implement-resilient-applications/partial-failure-strategies.md index 4e1434a7a79e1..ec3bdc96488c5 100644 --- a/docs/standard/microservices-architecture/implement-resilient-applications/partial-failure-strategies.md +++ b/docs/standard/microservices-architecture/implement-resilient-applications/partial-failure-strategies.md @@ -3,7 +3,7 @@ title: Strategies for handling partial failure description: .NET Microservices Architecture for Containerized .NET Applications | Strategies for handling partial failure author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/08/2018 --- # Strategies for handling partial failure @@ -19,7 +19,7 @@ Strategies for dealing with partial failures include the following. **Provide fallbacks**. In this approach, the client process performs fallback logic when a request fails, such as returning cached data or a default value. This is an approach suitable for queries, and is more complex for updates or commands. -**Limit the number of queued requests**. Clients should also impose an upper bound on the number of outstanding requests that a client microservice can send to a particular service. If the limit has been reached, it is probably pointless to make additional requests, and those attempts should fail immediately. In terms of implementation, the Polly [Bulkhead Isolation](https://github.com/App-vNext/Polly/wiki/Bulkhead) policy can be used to fulfil this requirement. This approach is essentially a parallelization throttle with as the implementation. It also permits a "queue" outside the bulkhead. You can proactively shed excess load even before execution (for example, because capacity is deemed full). This makes its response to certain failure scenarios faster than a circuit breaker would be, since the circuit breaker waits for the failures. The BulkheadPolicy object in Polly exposes how full the bulkhead and queue are, and offers events on overflow so can also be used to drive automated horizontal scaling. +**Limit the number of queued requests**. Clients should also impose an upper bound on the number of outstanding requests that a client microservice can send to a particular service. If the limit has been reached, it is probably pointless to make additional requests, and those attempts should fail immediately. In terms of implementation, the Polly [Bulkhead Isolation](https://github.com/App-vNext/Polly/wiki/Bulkhead) policy can be used to fulfill this requirement. This approach is essentially a parallelization throttle with as the implementation. It also permits a "queue" outside the bulkhead. You can proactively shed excess load even before execution (for example, because capacity is deemed full). This makes its response to certain failure scenarios faster than a circuit breaker would be, since the circuit breaker waits for the failures. The BulkheadPolicy object in Polly exposes how full the bulkhead and queue are, and offers events on overflow so can also be used to drive automated horizontal scaling. ## Additional resources diff --git a/docs/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests.md b/docs/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests.md new file mode 100644 index 0000000000000..c1fb9d0ce036c --- /dev/null +++ b/docs/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests.md @@ -0,0 +1,163 @@ +--- +title: Use HttpClientFactory to implement resilient HTTP requests +description: HttpClientFactory is an opinionated factory, available since .NET Core 2.1, for creating `HttpClient` instances to be used in your applications. +author: CESARDELATORRE +ms.author: wiwagn +ms.date: 07/03/2018 +--- +# Use HttpClientFactory to implement resilient HTTP requests + +`HttpClientFactory` is an opinionated factory, available since .NET Core 2.1, for creating `HttpClient` instances to be used in your applications. + +## Issues with the original HttpClient class available in .NET Core + +The original and well-know [HttpClient](https://docs.microsoft.com/dotnet/api/system.net.http.httpclient?view=netstandard-2.0) class can be easily used, but in some cases, it is not being properly used by many developers. + +As a first issue, while this class is disposable, using it with the `using` statement is not the best choice because even when you dispose `HttpClient` object, the underlying socket is not immediately released and can cause a serious issue named ‘sockets exhaustion’. For more information about this issue, see [You're using HttpClient wrong and it is destabilizing your software](https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) blog post. + +Therefore, `HttpClient` is intended to be instantiated once and reused throughout the life of an application. Instantiating an `HttpClient` class for every request will exhaust the number of sockets available under heavy loads. That issue will result in `SocketException` errors. Possible approaches to solve that problem are based on the creation of the `HttpClient` object as singleton or static, as explained in this [Microsoft article on HttpClient usage](https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/console-webapiclient). + +But there’s a second issue with `HttpClient` that you can have when you use it as singleton or static object. In this case, a singleton or static `HttpClient` doesn't respect DNS changes, as explained in this [issue at the .NET Core GitHub repo](https://github.com/dotnet/corefx/issues/11224). + +To address those mentioned issues and make the management of `HttpClient` instances easier, .NET Core 2.1 offers a new `HttpClientFactory` that can also be used to implement resilient HTTP calls by integrating Polly with it. + +## What is HttpClientFactory + +`HttpClientFactory` is designed to: + +- Provide a central location for naming and configuring logical HttpClients. For example, you may configure a client (Service Agent) that is pre-configured to access a specific microservice. +- Codify the concept of outgoing middleware via delegating handlers in `HttpClient` and implementing Polly-based middleware to take advantage of Polly’s policies for resiliency. +- `HttpClient` already has the concept of delegating handlers that could be linked together for outgoing HTTP requests. You register http clients into the factory plus you can use a Polly handler that allows Polly policies to be used for Retry, CircuitBreakers, etc. +- Manage the lifetime of HttpClientMessageHandlers to avoid the mentioned problems/issues that can occur when managing `HttpClient` lifetimes yourself. + +## Multiple ways to use HttpClientFactory + +There are several ways that you can use `HttpClientFactory` in your application: + +- Use `HttpClientFactory` Directly +- Use Named Clients +- Use Typed Clients +- Use Generated Clients + +For the sake of brevity, this guidance shows the most structured way to use `HttpClientFactory` that is to use Typed Clients (Service Agent pattern), but all options are documented and are currently listed in this [article covering HttpClientFactory usage](https://docs.microsoft.com/aspnet/core/fundamentals/http-requests?#consumption-patterns). + +## How to use Typed Clients with HttpClientFactory + +The following diagram shows how Typed Clients are used with HttpClientFactory. + +![Diagram with an MVC controller using an injected ClientService, which internally is using a configured HttpClient by HttpClientFactory and Polly's policies](./media/image3.5.png) + +**Figure 10-4**. Using `HttpClientFactory`with Typed Client classes. + +First, setup `HttpClientFactory` in your application. Add a reference to the `Microsoft.Extensions.Http` package which includes the `AddHttpClient()` extension method for `IServiceCollection`. This extension method registers the `DefaultHttpClientFactory` to be used as a singleton for the interface `IHttpClientFactory`. It defines a transient configuration for the `HttpMessageHandlerBuilder`. This message handler (`HttpMessageHandler` object), taken from a pool, is used by the `HttpClient` returned from the factory. + +In the next code, you can see how `AddHttpClient()` can be used to register Typed Clients (Service Agents) that need to use `HttpClient`. + +```csharp +// Startup.cs +//Add http client services at ConfigureServices(IServiceCollection services) +services.AddHttpClient(); +services.AddHttpClient(); +services.AddHttpClient(); +``` + +Just by adding your typed client classes with AddHttpClient(), whenever you use the `HttpClient` object that will be injected to your class through its constructor, that `HttpClient` object will be using all the configuration and policies provided. In the next sections, you will see those policies like Polly’s retries or circuit-breakers. + +### HttpClient lifetimes + +Each time you get an `HttpClient` object from IHttpClientFactory, a new instance of an `HttpClient` is returned. There will be an HttpMessageHandler** per named of typed client. I`HttpClientFactory` will pool the HttpMessageHandler instances created by the factory to reduce resource consumption. An HttpMessageHandler instance may be reused from the pool when creating a new `HttpClient` instance if its lifetime hasn't expired. + +Pooling of handlers is desirable as each handler typically manages its own underlying HTTP connections; creating more handlers than necessary can result in connection delays. Some handlers also keep connections open indefinitely, which can prevent the handler from reacting to DNS changes. + +The HttpMessageHandler objects in the pool have a lifetime that is the length of time that an HttpMessageHandler instance in the pool can be reused. The default value is two minutes, but it can be overridden per named or typed client basis. To override it, call SetHandlerLifetime() on the IHttpClientBuilder that is returned when creating the client, as shown in the following code. + +```csharp +//Set 5 min as the lifetime for the HttpMessageHandler objects in the pool used for the Basket Typed Client +services.AddHttpClient() + .SetHandlerLifetime(TimeSpan.FromMinutes(5)); +``` + +Each typed client or named client can have its own configured handler lifetime value. Set the lifetime to InfiniteTimeSpan to disable handler expiry. + +### Implement your Typed Client classes that use the injected and configured HttpClient + +As a previous step, you need to have your Typed Client classes defined, such as the classes in the sample code, like ‘BasketService’, ‘CatalogService’, ‘OrderingService’, etc. – A typed client is a class that accepts an `HttpClient` object (injected through its constructor) and uses it to call some remote HTTP service. For example: + +```csharp +public class CatalogService : ICatalogService +{ + private readonly HttpClient _httpClient; + private readonly string _remoteServiceBaseUrl; + + public CatalogService(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task GetCatalogItems(int page, int take, + int? brand, int? type) + { + var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, + page, take, brand, type); + + var responseString = await _httpClient.GetStringAsync(uri); + + var catalog = JsonConvert.DeserializeObject(responseString); + return catalog; + } +} +``` + +The typed client (CatalogService in the example) is activated by DI (Dependency Injection), meaning that it can accept any registered service in its constructor, in addition to HttpClient. + +A typed client is, effectively, a transient object, meaning that a new instance is created each time one is needed and it will receive a new `HttpClient` instance each time it is constructed. However, the HttpMessageHandler objects in the pool are the objects that are reused by multiple Http requests. + +### Use your Typed Client classes + +Finally, once you have your type classes implemented and have them registered with AddHttpClient(), you can use it anywhere you can have services injected by DI, for example in any Razor page code or any controller of an MVC web app, like in the following code from eShopOnContainers. + +```csharp +namespace Microsoft.eShopOnContainers.WebMVC.Controllers +{ + public class CatalogController : Controller + { + private ICatalogService _catalogSvc; + + public CatalogController(ICatalogService catalogSvc) => + _catalogSvc = catalogSvc; + + public async Task Index(int? BrandFilterApplied, + int? TypesFilterApplied, + int? page, + [FromQuery]string errorMsg) + { + var itemsPage = 10; + var catalog = await _catalogSvc.GetCatalogItems(page ?? 0, + itemsPage, + BrandFilterApplied, + TypesFilterApplied); + //… Additional code + } + + } +} +``` + +Until this point, the code shown is just performing regular Http requests, but the ‘magic’ comes in the following sections where, just by adding policies and delegating handlers to your registered typed clients, all the Http requests to be done by `HttpClient` will behave taking into account resilient policies such as retries with exponential backoff, circuit breakers, or any other custom delegating handler to implement additional security features, like using auth tokens, or any other custom feature. + + +## Additional resources + +- **Using HttpClientFactory in .NET Core 2.1** + [*https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1*](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1) + + +- **HttpClientFactory GitHub repo** + + [*https://github.com/aspnet/HttpClientFactory*](https://github.com/aspnet/HttpClientFactory) + + + +>[!div class="step-by-step"] +[Previous] (explore-custom-http-call-retries-exponential-backoff.md) +[Next] (implement-http-call-retries-exponential-backoff-polly.md) diff --git a/docs/standard/microservices-architecture/microservice-ddd-cqrs-patterns/index.md b/docs/standard/microservices-architecture/microservice-ddd-cqrs-patterns/index.md index 472826e9fbc5c..0a41044b8e5ad 100644 --- a/docs/standard/microservices-architecture/microservice-ddd-cqrs-patterns/index.md +++ b/docs/standard/microservices-architecture/microservice-ddd-cqrs-patterns/index.md @@ -3,7 +3,7 @@ title: Tackling Business Complexity in a Microservice with DDD and CQRS Patterns description: .NET Microservices Architecture for Containerized .NET Applications | Tackling Business Complexity in a Microservice with DDD and CQRS Patterns author: CESARDELATORRE ms.author: wiwagn -ms.date: 05/26/2017 +ms.date: 06/06/2018 --- # Tackling Business Complexity in a Microservice with DDD and CQRS Patterns @@ -64,5 +64,5 @@ DDD training >[!div class="step-by-step"] -[Previous](../multi-container-microservice-net-applications/background-tasks-with-ihostedservice.md) -[Next](apply-simplified-microservice-cqrs-ddd-patterns.md) +[Previous](../multi-container-microservice-net-applications/implement-api-gateways-with-ocelot.md) +[Next](apply-simplified-microservice-cqrs-ddd-patterns.md) \ No newline at end of file diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/implement-api-gateways-with-ocelot.md b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/implement-api-gateways-with-ocelot.md new file mode 100644 index 0000000000000..a8d8a1db67df7 --- /dev/null +++ b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/implement-api-gateways-with-ocelot.md @@ -0,0 +1,578 @@ +--- +title: Implementing API Gateways with Ocelot +description: Learn how to implement API Gateways with Ocelot and how to use Ocelot in a container-based environment. +author: CESARDELATORRE +ms.author: wiwagn +ms.date: 07/03/2018 +--- +# Implementing API Gateways with Ocelot + +The reference microservice application [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers) is using [Ocelot](https://github.com/ThreeMammals/Ocelot) because Ocelot is a simple and lightweight API Gateway that you can deploy anywhere along with your microservices/containers such as in any of the following environments used by eShopOnContainers. + +- Docker host, in your local dev PC, on-premises or in the cloud. +- Kubernetes cluster, on-premises or in managed cloud such as Azure Kubernetes Service (AKS). +- Service Fabric cluster, on-premises or in the cloud. +- Service Fabric mesh, as PaaS/Serverless in Azure. + +## Architect and design your API Gateways + +The following architecture diagram shows how API Gateways are implemented with Ocelot in eShopOnContainers. + +![eShopOnContainers architecture diagram showing client apps, microservices and the API Gateways in between](./media/image28.png) + +**Figure 8-27.** eShopOnContainers architecture with API Gateways + +That diagram shows how the whole application is deployed into a single Docker host or development PC with “Docker for Windows” or “Docker for Mac”. However, deploying into any orchestrator would be pretty similar but any container in the diagram could be scaled-out in the orchestrator. + +In addition, the infrastructure assets such as databases, cache, and message brokers should be offloaded from the orchestrator and deployed into high available systems for infrastructure, like Azure SQL Database, Azure Cosmos DB, Azure Redis, Azure Service Bus, or any HA clustering solution on-premises. + +As you can also notice in the diagram, having several API Gateways allows multiple development teams to be autonomous (in this case Marketing features vs. Shopping features) when developing and deploying their microservices plus their own related API Gateways. + +If you had a single monolithic API Gateway that would mean a single point to be updated by several development teams, which could couple all the microservices with a single part of the application. + +Going much further in the design, sometimes a fine-grained API Gateway can also be limited to a single business microservice depending on the chosen architecture. Having the API Gateway’s boundaries dictated by the business or domain will help you to get a better design. + +For instance, fine granularity in the API Gateway tier can be especially useful for more advanced composite UI applications that are based on microservices, because the concept of a fine-grained API Gateway is similar to a UI composition service. + +For more information about UI composition services, see [Creating composite UI based on microservices](https://docs.microsoft.com/dotnet/standard/microservices-architecture/architect-microservice-container-applications/microservice-based-composite-ui-shape-layout). + +As key takeaway, for many medium- and large-size applications, using a custom-built API Gateway product is usually a good approach, but not as a single monolithic aggregator or unique central custom API Gateway unless that API Gateway allows multiple independent configuration areas for the several development teams creating autonomous microservices. + +### Sample microservices/containers to reroute through the API Gateways + +As an example, `eShopOnContainers` has around six internal microservice-types that have to be published through the API Gateways, as shown in the following image. + +![](./media/image29.png) + +**Figure 8-28.** Microservice folders in eShopOnContainers solution in Visual Studio + +About the Identity service, in the design it is left out of the API Gateway routing because it is the only cross-cutting concern in the system, but with Ocelot it is also possible to include it as part of the rerouting lists. + +All those services are currently implemented as ASP.NET Core Web API services, as you can tell because of the code. Let’s focus on one of the microservices like the Catalog microservice code. + +![](./media/image30.png) + +**Figure 8-29.** Sample Web API microservice (Catalog microservice) + +You can see that the Catalog microservice is a typical ASP.NET Core Web API project with several controllers and methods like in the following code. + +```csharp +[HttpGet] +[Route("items/{id:int}")] +[ProducesResponseType((int)HttpStatusCode.NotFound)] +[ProducesResponseType(typeof(CatalogItem),(int)HttpStatusCode.OK)] +public async Task GetItemById(int id) +{ + if (id <= 0) + { + return BadRequest(); + } + var item = await _catalogContext.CatalogItems. + SingleOrDefaultAsync(ci => ci.Id == id); + //… + + if (item != null) + { + return Ok(item); + } + return NotFound(); +} +``` +The HTTP request will end up running that kind of C# code accessing the microservice database plus any additional action. + +In regards to the microservice URL, when the containers are deployed in your local development PC (local Docker host), each microservice’s container has always an internal port, usually port 80, specified in its dockerfile, as in the following dockerfile: + +``` +FROM microsoft/aspnetcore:2.0.5 AS base +WORKDIR /app +EXPOSE 80 +``` + +The port 80 shown in the code is internal within the Docker host, so it cannot be reached by the client apps. +The client apps can access only to the external ports (if any) published when deploying with `docker-compose`. + +Those external ports shouldn't be published when deploying into a production environment. This is precisely why you want to use the API Gateway, to avoid the direct communication between the client apps and the microservices. + +However, when developing, you want to access the microservice/container directly and run it through Swagger. That’s why in eShopOnContainers, the external ports are still specified even when they won’t be used by the API Gateway or the client apps. + +Here’s an example of the `docker-compose.override.yml` file for the Catalog microservice: + +``` +catalog.api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=YOUR_VALUE + - ... Other Environment Variables + ports: + - "5101:80" # Important: In a production environment you should remove the external port (5101) kept here for microservice debugging purposes. + # The API Gateway redirects and access through the internal port (80). +``` + +You can see how in the docker-compose.override.yml configuration the internal port for the Catalog container is port 80, but the port for external access is 5101. But this port shouldn’t be used by the application when using an API Gateway, only to debug, run and test just the Catalog microservice. + +Normally, you won’t be deploying with docker-compose into a production environment because the right production deployment environment for microservices is an orchestrator like Kubernetes or Service Fabric. When deploying to those environments you use different configuration files where you won’t publish directly any external port for the microservices but, you'll always use the reverse proxy from the API Gateway. + +Run the catalog microservice in your local Docker host either by running the full eShopOnContainers solution from Visual Studio (it’ll run all the services in the docker-compose files) or just starting the Catalog microservice with the following docker-compose command in CMD or PowerShell positioned at the folder where the `docker-compose.yml` and docker-compose.override.yml are placed. + +``` +docker-compose run --service-ports catalog.api +``` + +This command only runs the catalog.api service container plus dependencies that are specified in the docker-compose.yml. In this case, the SQL Server container and RabbitMQ container. + +Then, you can directly access the Catalog microservice and see its methods through the Swagger UI accessing directly through that “external” port, in this case `http://localhost:5101`. + +![](./media/image31.png) + +**Figure 8-30.** Testing the Catalog microservice with its Swagger UI + +At this point, you could set a breakpoint in C# code in Visual Studio, test the microservice with the methods exposed in Swagger UI, and finally clean-up everything with the `docker-compose down` command. + +However, this direct-access communication to the microservice, in this case through the external port 5101, is precisely what you want to avoid in your application. And you can avoid that by setting the additional level of indirection of the API Gateway (Ocelot, in this case). That way, the client app won’t directly access the microservice. + +## Implementing your API Gateways with Ocelot + +Ocelot is basically a set of middlewares that you can apply in a specific order. + +Ocelot is designed to work with ASP.NET Core only. It targets netstandard2.0 so it can be used anywhere .NET Standard 2.0 is supported, including .NET Core 2.0 runtime and .NET Framework 4.6.1 runtime and up. + +You install Ocelot and its dependencies in your ASP.NET Core project with [Ocelot's NuGet package](https://www.nuget.org/packages/Ocelot/), from Visual Studio. + +``` +Install-Package Ocelot +``` + +In eShopOnContainers, its API Gateway implementation is a simple ASP.NET Core WebHost project, and Ocelot’s middlewares handle all the API Gateway features, as shown in the following image: + +![](./media/image32.png) + +**Figure 8-31.** The OcelotApiGw base project in eShopOnContainers + +This ASP.NET Core WebHost project is made by two simple files, the `Program.cs` and `Startup.cs`. + +The Program.cs just needs to create and configure the typical ASP.NET Core BuildWebHost. + +```csharp +namespace OcelotApiGw +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) + { + var builder = WebHost.CreateDefaultBuilder(args); + + builder.ConfigureServices(s => s.AddSingleton(builder)) + .ConfigureAppConfiguration( + ic => ic.AddJsonFile(Path.Combine("configuration", + "configuration.json"))) + .UseStartup(); + var host = builder.Build(); + return host; + } + } +} +``` + +The important point here for Ocelot is the `configuration.json` file that you must provide to the builder through the `AddJsonFile()` method. That `configuration.json` is where you specify all the API Gateway ReRoutes, meaning the external endpoints with specific ports and the correlated internal endpoints, usually using different ports. + +``` +{ + "ReRoutes": [], + "GlobalConfiguration": {} +} +``` + +There are two sections to the configuration. An array of Re-Routes and a GlobalConfiguration. The Re-Routes are the objects that tell Ocelot how to treat an upstream request. The Global configuration allows overrides of Re-Route specific settings. It’s useful if you don’t want to manage lots of Re-Route specific settings. + +Here’s a simplified example of [ReRoute configuration](https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/ApiGateways/Web.Bff.Shopping/apigw/configuration.json) file from one of the API Gateways from eShopOnContainers. + +``` +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "catalog.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/c/{everything}", + "UpstreamHttpMethod": [ "POST", "PUT", "GET" ] + }, + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/b/{everything}", + "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + } + + ], + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId", + "AdministrationPath": "/administration" + } + } +``` + +The main functionality of an Ocelot API Gateway is to take incoming HTTP requests and forward them on to a downstream service, currently as another HTTP request. Ocelot’s describes the routing of one request to another as a Re-Route. + +For instance, let’s focus on one of the Re-Routes in the configuration.json from above, the configuration for the Basket microservice. + +``` +{ + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/b/{everything}", + "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } +} +``` + +The DownstreamPathTemplate, Scheme, and DownstreamHostAndPorts make the internal microservice URL that this request will be forwarded to. + +The port is the internal port used by the service. When using containers, the port specified at its dockerfile. + +The `Host` is a service name that depends on the service name resolution you are using. When using docker-compose, the services names are provided by the Docker Host, which is using the service names provided in the docker-compose files. If using an orchestrator like Kubernetes or Service Fabric, that name should be resolved by the DNS or name resolution provided by each orchestrator. + +DownstreamHostAndPorts is an array that contains the host and port of any downstream services that you wish to forward requests to. Usually this will just contain one entry but sometimes you might want to load balance requests to your downstream services and Ocelot lets you add more than one entry and then select a load balancer. But if using Azure and any orchestrator it is probably a better idea to load balance with the cloud and orchestrator infrastructure. + +The UpstreamPathTemplate is the URL that Ocelot will use to identify which DownstreamPathTemplate to use for a given request from the client. Finally, the UpstreamHttpMethod is used so Ocelot can distinguish between different requests (GET, POST, PUT) to the same URL. + +At this point, you could have a single Ocelot API Gateway (ASP.NET Core WebHost) using one or [multiple merged configuration.json files](http://ocelot.readthedocs.io/en/latest/features/configuration.html#merging-configuration-files) or you can also store the [configuration in a Consul KV store](http://ocelot.readthedocs.io/en/latest/features/configuration.html#store-configuration-in-consul). + +But as introduced in the architecture and design sections, if you really want to have autonomous microservices, it might be better to split that single monolithic API Gateway into multiple API Gateways and/or BFF (Backend for Frontend). For that purpose, let’s see how to implement that approach with Docker containers. + +### Using a single Docker container image to run multiple different API Gateway / BFF container types + +The design in eShopOnContainers implements a single Docker container image with the Ocelot API Gateway but then, when deploying to Docker, it creates different services/containers for each type of API-Gateway/BFF by providing a different configuration.json file for each container. + +![](./media/image33.png) + +**Figure 8-32.** Reusing a single Ocelot Docker image across multiple API Gateway types + +In eShopOnContainers, the “Generic Ocelot API Gateway Docker Image” is created with the project named 'OcelotApiGw' and the image name “eshop/ocelotapigw” that is specified in the docker-compose.yml file. Then, when deploying to Docker, there will be four API-Gateway containers created from that same Docker image, as shown in the following extract from the docker-compose.yml file. + +``` +PARTIAL DOCKER-COMPOSE.YML + + mobileshoppingapigw: + image: eshop/ocelotapigw:${TAG:-latest} + build: + context: . + dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile + + mobilemarketingapigw: + image: eshop/ocelotapigw:${TAG:-latest} + build: + context: . + dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile + + webshoppingapigw: + image: eshop/ocelotapigw:${TAG:-latest} + build: + context: . + dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile + + webmarketingapigw: + image: eshop/ocelotapigw:${TAG:-latest} + build: + context: . + dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile +``` + +Additionally, and as you can see in the docker-compose.override.yml file, the only difference between those API Gateway containers is the Ocelot configuration file, which is different for each service container and is specified at runtime through a Docker volume, as shown in the following docker-compose.override.yml file. + +``` +mobileshoppingapigw: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - IdentityUrl=http://identity.api + ports: + - "5200:80" + volumes: + - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration + +mobilemarketingapigw: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - IdentityUrl=http://identity.api + ports: + - "5201:80" + volumes: + - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration + +webshoppingapigw: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - IdentityUrl=http://identity.api + ports: + - "5202:80" + volumes: + - ./src/ApiGateways/Web.Bff.Shopping/apigw:/app/configuration + +webmarketingapigw: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - IdentityUrl=http://identity.api + ports: + - "5203:80" + volumes: + - ./src/ApiGateways/Web.Bff.Marketing/apigw:/app/configuration +``` + +Because of that previous code, and as shown in the Visual Studio Explorer below, the only file needed to define each specific business/BFF API Gateway is just a configuration.json file, because the four API Gateways are based on the same Docker image. + +![](./media/image34.png) + +**Figure 8-33.** The only file needed to define each API Gateway / BFF with Ocelot is a configuration file + +By splitting the API Gateway into multiple API Gateways, different development teams focusing on different subsets of microservices can manage their own API Gateways by using independent Ocelot configuration files. Plus, at the same time they can reuse the same Ocelot Docker image. + +Now, if you run eShopOnContainers with the API Gateways (included by default in VS when opening eShopOnContainers-ServicesAndWebApps.sln solution or if running “docker-compose up”), the following sample routes will be performed. + +For instance, when visiting the upstream URL http://localhost:5202/api/v1/c/catalog/items/2/ served by the webshoppingapigw API Gateway, you get the result from the internal Downstream URL http://catalog.api/api/v1/2 within the Docker host, as in the following browser. + +![](./media/image35.png) + +**Figure 8-34.** Accessing a microservice through a URL provided by the API Gateway + +Because of testing or debugging reasons, if you wanted to directly access to the Catalog Docker container (only at the development environment) without passing through the API Gateway, since 'catalog.api' is a DNS resolution internal to the Docker host (service discovery handled by docker-compose service names), the only way to directly access the container is through the external port published in the docker-compose.override.yml, which is provided only for development tests, such as http://localhost:5101/api/v1/Catalog/items/1 in the following browser. + +![](./media/image36.png) + +**Figure 8-35.** Direct access to a microservice for testing purposes + +But the application is configured so it accesses all the microservices through the API Gateways, not though the direct port “shortcuts”. + +### The Gateway aggregation pattern in eShopOnContainers + +As introduced previously, a flexible way to implement requests aggregation is with custom services, by code. You could also implement request aggregation with the Request Aggregation feature in Ocelot, but it might not be as flexible as you need. Therefore, the selected way to implement aggregation in eShopOnContainers is with an explicit ASP.NET Core Web API services for each aggregator. + +According to that approach, the API Gateway composition diagram is in reality a bit more extended when taking into account the aggregator services that are not shown in the simplified global architecture diagram shown previously. + +In the following diagram, you can also see how the aggregator services work with their related API Gateways. + +![](./media/image37.png) + +**Figure 8-36.** eShopOnContainers architecture with aggregator services + +The following image is zooming in further, so you can notice how for the “Shopping” business area, the client apps could be improved by reducing chattiness with microservices when using those aggregator services under the realm of the API Gateways. + + ![](./media/image38.png) + +**Figure 8-37.** Zoom in vision of the Aggregator services + +You can notice how when the diagram shows the possible requests coming from the API Gateways it can get pretty complex. Although you can see how the arrows in blue would be simplified, from a client apps perspective, when using the aggregator pattern by reducing chattiness and latency in the communication, ultimately significantly improving the user experience for the remote apps (mobile and SPA apps), especially. + +In the case of the “Marketing” business area and microservices, it is a very simple use case so there was no need to use aggregators, but it could also be possible, if needed. + +### Authentication and authorization in Ocelot API Gateways + +In an Ocelot API Gateway you can sit the authentication service, such as an ASP.NET Core Web API service using [IdentityServer](http://identityserver.io/) providing the auth token, either out or inside the API Gateway. + +Since eShopOnContainers is using multiple API Gateways with boundaries based on BFF and business areas, the Identity/Auth service is left out of the API Gateways, as highlighted in yellow in the following diagram. + + ![](./media/image39.png) + +**Figure 8-38.** Position of the Identity service in eShopOnContainers + +However, Ocelot also supports to sit the Identity/Auth microservice within the API Gateway boundary, as in this other diagram. + + ![](./media/image40.png) + +**Figure 8-39.** Authentication in Ocelot API Gateway + +Because eShopOnContainers application has split the API Gateway into multiple BFF (Backend for Frontend) and business areas API Gateways, another option would had been to create an additional API Gateway for cross-cutting concerns. That choice would be fair in a more complex microservice based architecture with multiple cross-cutting concerns microservices. Since there's only one cross-cutting concern in eShopOnContainers, it was decided to just handle the security service out of the API Gateway realm, for simplicity’s sake. + +In any case, if the app is secured at the API Gateway level, the authentication module of the Ocelot API Gateway is visited at first when trying to use any secured microservice. That re-directs the HTTP request to visit the Identity or auth microservice to get the access token so so you can visit the protected services with the access_token. + +The way you secure with authentication any service at the API Gateway level is by setting the AuthenticationProviderKey in its related settings at the configuration.json. + +``` + { + "DownstreamPathTemplate": "/api/{version}/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "basket.api", + "Port": 80 + } + ], + "UpstreamPathTemplate": "/api/{version}/b/{everything}", + "UpstreamHttpMethod": [], + "AuthenticationOptions": { + "AuthenticationProviderKey": "IdentityApiKey", + "AllowedScopes": [] + } + } +``` + +When Ocelot runs, it will look at the Re-Routes AuthenticationOptions.AuthenticationProviderKey and check that there is an Authentication Provider registered with the given key. If there isn't, then Ocelot will not start up. If there is, then the ReRoute will use that provider when it executes. + +Because the Ocelot WebHost is configured with the `authenticationProviderKey = "IdentityApiKey"`, that will require authentication whenever that service has any requests without any auth token. + +```csharp +namespace OcelotApiGw +{ + public class Startup + { + private readonly IConfiguration _cfg; + + public Startup(IConfiguration configuration) => _cfg = configuration; + + public void ConfigureServices(IServiceCollection services) + { + var identityUrl = _cfg.GetValue("IdentityUrl"); + var authenticationProviderKey = "IdentityApiKey"; + //… + services.AddAuthentication() + .AddJwtBearer(authenticationProviderKey, x => + { + x.Authority = identityUrl; + x.RequireHttpsMetadata = false; + x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() + { + ValidAudiences = new[] { "orders", "basket", "locations", "marketing", "mobileshoppingagg", "webshoppingagg" } + }; + }); + //... +``` + +Then, you also need to set authorization with the [Authorize] attribute on any resource to be accessed like the microservices, such as in the following Basket microservice controller. + +```csharp +namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers +{ + [Route("api/v1/[controller]")] + [Authorize] + public class BasketController : Controller + { + //... + } +} +``` + +The ValidAudiences such as “basket” are correlated with the audience defined in each microservice with `AddJwtBearer()` at the ConfigureServices() of the Startup class, such as in the code below. + +```csharp +// prevent from mapping "sub" claim to nameidentifier. +JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + +var identityUrl = Configuration.GetValue("IdentityUrl"); + +services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + +}).AddJwtBearer(options => +{ + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "basket"; +}); +``` + +As next step, if you try to access any secured microservice like the Basket microservice with a Re-Route URL based on the API Gateway like http://localhost:5202/api/v1/b/basket/1 then you’ll get a 401 Unauthorized unless you provide a valid token. On the other hand, if a Re-Route URL is authenticated, Ocelot will invoke whatever downstream scheme is associated with it (the internal microservice URL). + +**Authorization at Ocelot’s Re-Routes tier.** Ocelot supports claims-based authorization evaluated after the authentication. You set the authorization at a route level by adding the following code to the re-route configuration. + +``` +"RouteClaimsRequirement": { + "UserType": "employee" +} +``` + +In that example, when the authorization middleware is called, Ocelot will find if the user has the claim type 'UserType' in the token and if the value of that claim is 'employee'. If it isn’t, then the user will not be authorized and the response will be 403 forbidden. + +## Using Kubernetes Ingress plus Ocelot API Gateways + +When using Kubernetes (like in an Azure Kubernetes Service cluster),, you usually unify all the HTTP requests through the [Kuberentes Ingress tier](https://kubernetes.io/docs/concepts/services-networking/ingress/) based on *Nginx*. + +In Kuberentes, if you don’t use any ingress approach, then your services and pods have IPs only routable by the cluster network. + +But if you use an ingress approach, you'll have a middle tier between the Internet and your services (including your API Gateways), acting as a reverse proxy. + +As a definition, an Ingress is a collection of rules that allow inbound connections to reach the cluster services. An ingress is configured to provide services externally reachable URLs, load balance traffic, SSL termination and more. Users request ingress by POSTing the Ingress resource to the API server. + +In eShopOnContainers, when developing locally and using just your development machine as the Docker host, you are not using any ingress but only the multiple API Gateways. + +However, when targeting a “production” environment based on Kuberentes, eShopOnCOntainers is using an ingress in front of the API gateways. That way, the clients still call the same base URL but the requests are routed to multiple API Gateways or BFF. + +Note that API Gateways are front-ends or facades surfacing only the services but not the web applications that are usually out of their scope. In addition, the API Gateways might hide certain internal microservices. + +The ingress, however, is just redirecting HTTP requests but not trying to hide any microservice or web app. + +Having an ingress Nginx tier in Kuberentes in front of the web applications plus the several Ocelot API Gateways / BFF is the ideal architecture, as shown in the following diagram. + + ![](./media/image41.png) + +**Figure 8-40.** The ingress tier in eShopOnContainers when deployed into Kubernetes + +When you deploy eShopOnContainers into Kuberentes, it exposes just a few services or endpoints via _ingress_, basically the following list of postfixes on the URLs: + +- `/` for the client SPA web application +- `/webmvc` for the client MVC web application +- `/webstatus` for the client web app showing the status/healchecks +- `/webshoppingapigw` for the web BFF and shopping business processes +- `/webmarketingapigw` for the web BFF and marketing business processes +- `/mobileshoppingapigw` for the mobile BFF and shopping business processes +- `/mobilemarketingapigw` for the mobile BFF and marketing business processes + +When deploying to Kubernetes, each Ocelot API Gateway is using a different “configuration.json” file for each _pod_ running the API Gateways. Those “configuration.json” files are provided by mounting (originally with the deploy.ps1 script) a volume created based on a Kuberentes _config map_ named ‘ocelot’. Each container mounts its related configuration file in the container’s folder named `/app/configuration`. + +In the source code files of eShopOnContainers, the original “configuration.json” files can be found within the `k8s/ocelot/` folder. There’s one file for each BFF/APIGateway. + + +## Additional cross-cutting features in an Ocelot API Gateway + +There are other important features to research and use, when using an Ocelot API Gateway, described in the following links. + +- **Service discovery in the client side integrating Ocelot with Consul or Eureka** + [*http://ocelot.readthedocs.io/en/latest/features/servicediscovery.html*](http://ocelot.readthedocs.io/en/latest/features/servicediscovery.html) + +- **Caching at the API Gateway tier** + [*http://ocelot.readthedocs.io/en/latest/features/caching.html*](http://ocelot.readthedocs.io/en/latest/features/caching.html) + +- **Logging at the API Gateway tier** + [*http://ocelot.readthedocs.io/en/latest/features/logging.html*](http://ocelot.readthedocs.io/en/latest/features/logging.html) + +- **Quality of Service (Retries and Circuit breakers) at the API Gateway tier** + [*http://ocelot.readthedocs.io/en/latest/features/qualityofservice.html*](http://ocelot.readthedocs.io/en/latest/features/qualityofservice.html) + +- **Rate limiting** + [*http://ocelot.readthedocs.io/en/latest/features/ratelimiting.html*](http://ocelot.readthedocs.io/en/latest/features/ratelimiting.html ) + + + + +>[!div class="step-by-step"] +[Previous] (background-tasks-with-ihostedservice.md) +[Next] (../microservice-ddd-cqrs-patterns/index.md) diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image28.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image28.png new file mode 100644 index 0000000000000..2949667a09da8 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image28.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29-large.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29-large.png new file mode 100644 index 0000000000000..7c9392ac057f4 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29-large.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29.png new file mode 100644 index 0000000000000..768c13087e02f Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image29.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image30.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image30.png new file mode 100644 index 0000000000000..2532e01d9f786 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image30.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image31.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image31.png new file mode 100644 index 0000000000000..82190af86c5ad Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image31.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image32.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image32.png new file mode 100644 index 0000000000000..3d364c0a30373 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image32.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image33.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image33.png new file mode 100644 index 0000000000000..953da53c9d1d3 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image33.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image34.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image34.png new file mode 100644 index 0000000000000..06c1b1b9d12f7 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image34.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image35.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image35.png new file mode 100644 index 0000000000000..8c62e3a9b1cad Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image35.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image36.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image36.png new file mode 100644 index 0000000000000..1f5bb64cf55a0 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image36.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image37.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image37.png new file mode 100644 index 0000000000000..ac6fafeb8914f Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image37.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image38.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image38.png new file mode 100644 index 0000000000000..c099a2da1c66f Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image38.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image39.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image39.png new file mode 100644 index 0000000000000..68188cfc1a80e Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image39.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image40.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image40.png new file mode 100644 index 0000000000000..9c20d46aff85c Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image40.png differ diff --git a/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image41.png b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image41.png new file mode 100644 index 0000000000000..e1073913a6d44 Binary files /dev/null and b/docs/standard/microservices-architecture/multi-container-microservice-net-applications/media/image41.png differ diff --git a/docs/standard/microservices-architecture/toc.md b/docs/standard/microservices-architecture/toc.md index 9864e518a8ccc..09653d675d5bd 100644 --- a/docs/standard/microservices-architecture/toc.md +++ b/docs/standard/microservices-architecture/toc.md @@ -42,6 +42,7 @@ ### [Subscribing to events](multi-container-microservice-net-applications/subscribe-events.md) ### [Testing ASP.NET Core services and web apps](multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.md) ### [Implement background tasks in microservices with IHostedService](multi-container-microservice-net-applications/background-tasks-with-ihostedservice.md) +### [Implementing API Gateways with Ocelot](multi-container-microservice-net-applications/implement-api-gateways-with-ocelot.md) ## [Tackling Business Complexity in a Microservice with DDD and CQRS Patterns](microservice-ddd-cqrs-patterns/index.md) ### [Applying simplified CQRS and DDD patterns in a microservice](microservice-ddd-cqrs-patterns/apply-simplified-microservice-cqrs-ddd-patterns.md) ### [Applying CQRS and CQS approaches in a DDD microservice in eShopOnContainers](microservice-ddd-cqrs-patterns/eshoponcontainers-cqrs-ddd-microservice.md) @@ -65,9 +66,10 @@ ### [Strategies for handling partial failure](implement-resilient-applications/partial-failure-strategies.md) ### [Implementing retries with exponential backoff](implement-resilient-applications/implement-retries-exponential-backoff.md) ### [Implementing resilient Entity Framework Core SQL connections](implement-resilient-applications/implement-resilient-entity-framework-core-sql-connections.md) -### [Implementing custom HTTP call retries with exponential backoff](implement-resilient-applications/implement-custom-http-call-retries-exponential-backoff.md) -### [Implementing HTTP call retries with exponential backoff with Polly](implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md) -### [Implementing the Circuit Breaker pattern](implement-resilient-applications/implement-circuit-breaker-pattern.md) +### [Exploring custom HTTP call retries with exponential backoff](implement-resilient-applications/explore-custom-http-call-retries-exponential-backoff.md) +### [Use HttpClientFactory to implement resilient HTTP requests](implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests.md) +### [Implement HTTP call retries with exponential backoff with Polly](implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly.md) +### [Implement the Circuit Breaker pattern](implement-resilient-applications/implement-circuit-breaker-pattern.md) ### [Health monitoring](implement-resilient-applications/monitor-app-health.md) ## [Securing NET Microservices and Web Applications](secure-net-microservices-web-applications/index.md) ### [About authorization in .NET microservices and web applications](secure-net-microservices-web-applications/authorization-net-microservices-web-applications.md) diff --git a/docs/standard/threading/threading-objects-and-features.md b/docs/standard/threading/threading-objects-and-features.md index 6757035386764..23b46b659556d 100644 --- a/docs/standard/threading/threading-objects-and-features.md +++ b/docs/standard/threading/threading-objects-and-features.md @@ -19,7 +19,7 @@ The .NET Framework provides a number of objects that help you create and manage Explains the **ThreadPool** class, which enables you to request a thread to execute a task without having to do any thread management yourself. [Timers](../../../docs/standard/threading/timers.md) - Explains how to use a **Timer** to specify a delegate to be called at a specified time. + Describes timers that can be used in a multithreaded environment. [Monitors](http://msdn.microsoft.com/library/33fe4aef-b44b-42fd-9e72-c908e39e75db) Explains how to use the **Monitor** class to synchronize access to a member or to build your own thread management types. diff --git a/docs/standard/threading/timers.md b/docs/standard/threading/timers.md index 43706e912a158..48bb985982d43 100644 --- a/docs/standard/threading/timers.md +++ b/docs/standard/threading/timers.md @@ -1,6 +1,7 @@ --- title: "Timers" -ms.date: "03/30/2017" +description: Learn what .NET timers to use in a multithreaded environment. +ms.date: "07/03/2018" ms.technology: dotnet-standard dev_langs: - "csharp" @@ -10,23 +11,47 @@ helpviewer_keywords: - "threading [.NET Framework], timers" - "timers, about timers" ms.assetid: 7091500d-be18-499b-a942-95366ce185e5 -author: "rpetrusha" +author: "pkulikov" ms.author: "ronpet" --- # Timers -Timers are lightweight objects that enable you to specify a delegate to be called at a specified time. A thread in the thread pool performs the wait operation. - - Using the class is straightforward. You create a **Timer**, passing a delegate to the callback method, an object representing state that will be passed to the callback, an initial raise time, and a time representing the period between callback invocations. To cancel a pending timer, call the **Timer.Dispose** function. - + +.NET provides two timers to use in a multithreaded environment: + +- , which executes a single callback method on a thread at regular intervals. +- , which by default raises an event on a thread at regular intervals. + > [!NOTE] -> There are two other timer classes. The class is a control that works with visual designers and is meant to be used in user interface contexts; it raises events on the user interface thread. The class derives from , so it can be used with visual designers; it also raises events, but it raises them on a thread. The class makes callbacks on a thread and does not use the event model at all. It also provides a state object to the callback method, which the other timers do not. It is extremely lightweight. - - The following code example starts a timer that starts after one second (1000 milliseconds) and ticks every second until you press the **Enter** key. The variable containing the reference to the timer is a class-level field, to ensure that the timer is not subject to garbage collection while it is still running. For more information on aggressive garbage collection, see . - - [!code-cpp[System.Threading.Timer#2](../../../samples/snippets/cpp/VS_Snippets_CLR_System/system.Threading.Timer/CPP/source2.cpp#2)] - [!code-csharp[System.Threading.Timer#2](../../../samples/snippets/csharp/VS_Snippets_CLR_System/system.Threading.Timer/CS/source2.cs#2)] - [!code-vb[System.Threading.Timer#2](../../../samples/snippets/visualbasic/VS_Snippets_CLR_System/system.Threading.Timer/VB/source2.vb#2)] +> Some .NET implementations may include additional timers: +> +> - : a Windows Forms component that fires an event at regular intervals. The component has no user interface and is designed for use in a single-threaded environment. +> - : an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval. +> - : a timer that is integrated into the queue which is processed at a specified interval of time and at a specified priority. + +## The System.Threading.Timer class + +The class enables you to continuously call a delegate at specified time intervals. You also can use this class to schedule a single call to a delegate in a specified time interval. The delegate is executed on a thread. + +When you create a object, you specify a delegate that defines the callback method, an optional state object that is passed to the callback, the amount of time to delay before the first invocation of the callback, and the time interval between callback invocations. To cancel a pending timer, call the method. + +The following example creates a timer that calls the provided delegate for the first time after one second (1000 milliseconds) and then calls it every two seconds. The state object in the example is used to count how many times the delegate is called. The timer is stopped when the delegate has been called at least 10 times. + +[!code-cpp[System.Threading.Timer#2](../../../samples/snippets/cpp/VS_Snippets_CLR_System/system.Threading.Timer/CPP/source2.cpp#2)] +[!code-csharp[System.Threading.Timer#2](../../../samples/snippets/csharp/VS_Snippets_CLR_System/system.Threading.Timer/CS/source2.cs#2)] +[!code-vb[System.Threading.Timer#2](../../../samples/snippets/visualbasic/VS_Snippets_CLR_System/system.Threading.Timer/VB/source2.vb#2)] + +For more information and examples, see . + +## The System.Timers.Timer class + +Another timer that can be used in a multithreaded environment is that by default raises an event on a thread. + +When you create a object, you may specify the time interval in which to raise an event. Use the property to indicate if a timer should raise an event. If you need an event to be raised only once after the specified interval has elapsed, set the to `false`. The default value of the property is `true`, which means that an event is raised regularly at the interval defined by the property. + +For more information and examples, see . -## See Also - - [Threading Objects and Features](../../../docs/standard/threading/threading-objects-and-features.md) +## See also + + + + [Threading Objects and Features](threading-objects-and-features.md) diff --git a/docs/toc.md b/docs/toc.md index 75935d1f68fcb..1c9c06071b390 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -295,6 +295,7 @@ ## [Tour of F#](fsharp/tour.md) ## [Get Started](fsharp/get-started/index.md) +### [Install F#](fsharp/get-started/install-fsharp.md) ### [Get Started with Visual Studio](fsharp/get-started/get-started-visual-studio.md) ### [Get Started with Visual Studio for Mac](fsharp/get-started/get-started-with-visual-studio-for-mac.md) ### [Get Started with Visual Studio Code and Ionide](fsharp/get-started/get-started-vscode.md) diff --git a/docs/visual-basic/programming-guide/concepts/threading/index.md b/docs/visual-basic/programming-guide/concepts/threading/index.md index b3a2a15c3ff33..703ec882e7652 100644 --- a/docs/visual-basic/programming-guide/concepts/threading/index.md +++ b/docs/visual-basic/programming-guide/concepts/threading/index.md @@ -35,7 +35,6 @@ Threading enables your Visual Basic program to perform concurrent processing so |[Parameters and Return Values for Multithreaded Procedures (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md)|Describes how to pass and return parameters with multithreaded applications.| |[Walkthrough: Multithreading with the BackgroundWorker Component (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/walkthrough-multithreading-with-the-backgroundworker-component.md)|Shows how to create a simple multithreaded application.| |[Thread Synchronization (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-synchronization.md)|Describes how to control the interactions of threads.| -|[Thread Timers (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-timers.md)|Describes how to run procedures on separate threads at fixed intervals.| |[Thread Pooling (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-pooling.md)|Describes how to use a pool of worker threads that are managed by the system.| |[How to: Use a Thread Pool (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/how-to-use-a-thread-pool.md)|Demonstrates synchronized use of multiple threads in the thread pool.| |[Threading](../../../../standard/threading/index.md)|Describes how to implement threading in the .NET Framework.| diff --git a/docs/visual-basic/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md b/docs/visual-basic/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md index 8ad5360f3ccb0..4568ff8117ed5 100644 --- a/docs/visual-basic/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md +++ b/docs/visual-basic/programming-guide/concepts/threading/parameters-and-return-values-for-multithreaded-procedures.md @@ -93,7 +93,7 @@ Private Sub BackgroundWorker1_RunWorkerCompleted( End Sub ``` - You can provide parameters and return values to thread-pool threads by using the optional `ByVal` state-object variable of the method. Thread-timer threads also support a state object for this purpose. For information on thread pooling and thread timers, see [Thread Pooling (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-pooling.md)[Thread Pooling](http://msdn.microsoft.com/library/4b8bb2c8-8ca4-457c-9afd-d11bc9a05701) and [Thread Timers (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-timers.md). + You can provide parameters and return values to thread-pool threads by using the optional `ByVal` state-object variable of the method. Thread-timer threads also support a state object for this purpose. For information on thread pooling and thread timers, see [Thread Pooling (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/thread-pooling.md)[Thread Pooling](http://msdn.microsoft.com/library/4b8bb2c8-8ca4-457c-9afd-d11bc9a05701) and [Timers](../../../../standard/threading/timers.md). ## See Also [Walkthrough: Multithreading with the BackgroundWorker Component (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/walkthrough-multithreading-with-the-backgroundworker-component.md) diff --git a/docs/visual-basic/programming-guide/concepts/threading/thread-timers.md b/docs/visual-basic/programming-guide/concepts/threading/thread-timers.md deleted file mode 100644 index 450b0f015813a..0000000000000 --- a/docs/visual-basic/programming-guide/concepts/threading/thread-timers.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Thread Timers (Visual Basic)" -ms.date: 07/20/2015 -ms.assetid: 809cba93-cc93-4e21-afda-f299f9a39818 ---- -# Thread Timers (Visual Basic) -The class is useful for periodically running a task on a separate thread. For example, you could use a thread timer to check the status and integrity of a database or to back up critical files. - -## Thread Timer Example - The following example starts a task every two seconds and uses a flag to initiate the method that stops the timer. This example posts status to the output window. - -```vb -Private Class StateObjClass - ' Used to hold parameters for calls to TimerTask. - Public SomeValue As Integer - Public TimerReference As System.Threading.Timer - Public TimerCanceled As Boolean -End Class - -Public Sub RunTimer() - Dim StateObj As New StateObjClass - StateObj.TimerCanceled = False - StateObj.SomeValue = 1 - Dim TimerDelegate As New System.Threading.TimerCallback(AddressOf TimerTask) - ' Create a timer that calls a procedure every 2 seconds. - ' Note: There is no Start method; the timer starts running as soon as - ' the instance is created. - Dim TimerItem As New System.Threading.Timer(TimerDelegate, StateObj, - 2000, 2000) - ' Save a reference for Dispose. - StateObj.TimerReference = TimerItem - - ' Run for ten loops. - While StateObj.SomeValue < 10 - ' Wait one second. - System.Threading.Thread.Sleep(1000) - End While - - ' Request Dispose of the timer object. - StateObj.TimerCanceled = True -End Sub - -Private Sub TimerTask(ByVal StateObj As Object) - Dim State As StateObjClass = CType(StateObj, StateObjClass) - ' Use the interlocked class to increment the counter variable. - System.Threading.Interlocked.Increment(State.SomeValue) - System.Diagnostics.Debug.WriteLine("Launched new thread " & Now.ToString) - If State.TimerCanceled Then - ' Dispose Requested. - State.TimerReference.Dispose() - System.Diagnostics.Debug.WriteLine("Done " & Now) - End If -End Sub -``` - - Thread timers are particularly useful when the object is unavailable, such as when you are developing console applications. - -## See Also - - [Multithreaded Applications (Visual Basic)](../../../../visual-basic/programming-guide/concepts/threading/multithreaded-applications.md) diff --git a/docs/visual-basic/programming-guide/concepts/threading/toc.md b/docs/visual-basic/programming-guide/concepts/threading/toc.md index 1e3af3afe5020..6c05a7373bff5 100644 --- a/docs/visual-basic/programming-guide/concepts/threading/toc.md +++ b/docs/visual-basic/programming-guide/concepts/threading/toc.md @@ -3,6 +3,5 @@ ## [Parameters and Return Values for Multithreaded Procedures](parameters-and-return-values-for-multithreaded-procedures.md) ## [Walkthrough: Multithreading with the BackgroundWorker Component](walkthrough-multithreading-with-the-backgroundworker-component.md) ## [Thread Synchronization](thread-synchronization.md) -## [Thread Timers](thread-timers.md) ## [Thread Pooling](thread-pooling.md) ### [How to: Use a Thread Pool](how-to-use-a-thread-pool.md)