* Minor updates

* Updating sample to use configuration for quotes instead of hard-coding them.

* Updated to describe sample

* Finishing config

* remove placeholder

* Adding notes about usings and packages
This commit is contained in:
Steve Smith 2016-11-30 22:05:52 -05:00 коммит произвёл GitHub
Родитель 20be2e821e
Коммит e151a10e52
6 изменённых файлов: 184 добавлений и 9 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -234,3 +234,4 @@ _Pvt_Extensions
# FAKE - F# Make
.fake/
.vscode/

Просмотреть файл

@ -6,15 +6,86 @@ Download a ZIP containing this tutorial's sample files:
- [Initial Version] - Use this as a starting point when following along with the tutorial yourself
- [Completed Version] - Includes the completed versions of all samples
See the [Issue](https://github.com/dotnet/training-tutorials/issues/51) to claim this lesson and/or view what should be included in it.
## Adding Support for Configuration
## First Header
So far the Quotes app you're building hasn't needed any configuration values. However, most real apps need to store some values related to their configuration somewhere, typically in a file that's deployed with the app. ASP.NET Core has a very extensible configuration system, allowing you to choose from a variety of built-in configuration sources or to customize your own. You're not limited to a particular file or file format, and you can even add configuration values directly using code.
Start the lesson here.
Typically in ASP.NET Core apps, configuration is set up in the ``Startup`` class. An instance of the ``IConfigurationRoot`` type is created using a ``ConfigurationBuilder``. This can be done in your ``Startup`` class's constructor:
...
```c#
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("quotes.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set;}
```
In this code, the constructor uses an ``IHostingEnvironment`` instance to set the base configuration path to the content root path (the root of the project). Then, it specifies that configuration will come from a required JSON file, ``quotes.json``. The result of the ``Build`` method is stored in the ``Configuration`` property, which is accessible from elsewhere in ``Startup``.
Note that for the above code to compile, you'll need to be sure to include these namespaces:
```c#
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
```
You'll also need to reference these packages:
* Microsoft.Extensions.Configuration.Json
* Microsoft.Extensions.Options.ConfigurationExtensions
## Accessing Configuration Values as Options
ASP.NET Core uses the [options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration#options-config-objects) to access configuration values in a strongly-typed manner. Once configured, strongly typed values may be requested from any type or method that supports [dependency injection](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) (which includes most ASP.NET Core types, as well as the ``Configure`` method in ``Startup``, as you'll see in a moment). To use the pattern, simply request an instance of ``IOptions<T>`` where ``T`` is the type you're trying to access from configuration. Currently, the quotes app stores its data in a hard-coded ``List<Quotation>`` in ``QuotationStore``. To load these quotes from a configuration source, an instance of ``IOptions<List<Quotation>>`` is used. To access the strongly-typed value, use the ``Value`` property.
```c#
public void Configure(IApplicationBuilder app,
IOptions<List<Quotation>> quoteOptions)
{
// other code omitted
var quotes = quoteOptions.Value;
if(quotes != null)
{
QuotationStore.Quotations = quotes;
}
}
```
Ultimately the app can be refactored so that the ``QuotationStore`` isn't static, and can accept the configured quotes through dependency injection itself. The current design works, but isn't ideal since any code can manipulate the ``Quotations`` property, violating the principle of [encapsulation](http://deviq.com/encapsulation/).
## Setting up Options
In order for the options pattern to work, you first need to add options support in ``ConfigureServices``. Then, you need to add the options value to the services container. You can specify the value of the options directly, or you can specify that it should be loaded from configuration, as the following code demonstrates:
```c#
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<List<Quotation>>(Configuration.GetSection("Quotes"));
}
```
It's important when using a file for your configuration that you format it appropriately. In this example, the ``quotes.json`` file needs to container a ``quotes`` section, which in turn should contain a collection of ``Quotation`` instances. An example of ``quotes.json``:
```json
{
"Quotes": [
{ "author": "Ralph Johnson", "quote": "Before software can be reusable it first has to be usable." },
{ "author": "Albert Einstein", "quote": "Make everything as simple as possible, but not simpler." },
{ "author": "Dwight Eisenhower", "quote": "I have always found that plans are useless, but planning is indispensable." }
]
}
```
## Next Steps
Give the reader some additional exercises/tasks they can perform to try out what they've just learned.
Since the configuration options needed in this lesson were inside of the ``Startup`` class, the method could have directly accessed the settings from the ``Configuration`` property. Modify the code to use this approach, and consider whether you prefer it to the use of the options pattern in this instance.
Note that in most situations, such as using configuration options from controllers, middleware, or filters, your code won't have direct access to a configuration instance.

Просмотреть файл

@ -5,7 +5,7 @@ namespace ConsoleApplication
{
public static class QuotationStore
{
public static List<Quotation> Quotations {get; private set;}
public static List<Quotation> Quotations {get; set;}
static QuotationStore()
{

Просмотреть файл

@ -3,14 +3,34 @@ using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace ConsoleApplication
{
public class Startup
{
public void Configure(IApplicationBuilder app)
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("quotes.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set;}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<List<Quotation>>(Configuration.GetSection("Quotes"));
}
public void Configure(IApplicationBuilder app,
IOptions<List<Quotation>> quoteOptions)
{
// app.UseDefaultFiles();
app.UseStaticFiles();
app.Use(async (context, next) =>
@ -19,7 +39,12 @@ namespace ConsoleApplication
await next();
});
// next steps solution
var quotes = quoteOptions.Value;
if(quotes != null)
{
QuotationStore.Quotations = quotes;
}
app.Map("/quote", builder => builder.Run(async context =>
{
var id = int.Parse(context.Request.Path.ToString().Split('/')[1]);

Просмотреть файл

@ -0,0 +1,71 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
<PropertyGroup>
<PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wp8+wpa81;</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="$(GlobalExclude)" />
<EmbeddedResource Include="**\*.resx" Exclude="$(GlobalExclude)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App">
<Version>1.0.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.NET.Sdk.Web">
<Version>1.0.0-alpha-20161104-2-112</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc">
<Version>1.0.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Razor.Tools">
<Version>1.0.0-preview2-final</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Routing">
<Version>1.0.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel">
<Version>1.0.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.StaticFiles">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Json">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Console">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink.Loader">
<Version>14.0.0</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,7 @@
{
"Quotes": [
{ "author": "Ralph Johnson", "quote": "Before software can be reusable it first has to be usable." },
{ "author": "Albert Einstein", "quote": "Make everything as simple as possible, but not simpler." },
{ "author": "Dwight Eisenhower", "quote": "I have always found that plans are useless, but planning is indispensable." }
]
}