File: AcceptanceTests.cs
Web Access
Project: src\test\Libraries\Microsoft.Extensions.Options.ContextualOptions.Tests\Microsoft.Extensions.Options.Contextual.Tests.csproj (Microsoft.Extensions.Options.Contextual.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.Testing;
using Microsoft.Extensions.Options.Contextual.Provider;
using Xunit;
 
namespace Microsoft.Extensions.Options.Contextual.Test;
 
#pragma warning disable SA1402 // File may only contain a single type
 
[OptionsContext]
internal partial class WeatherForecastContext // Note class must be partial
{
    public Guid UserId { get; set; }
    public string? Country { get; set; }
}
 
internal class WeatherForecastOptions
{
    public string TemperatureScale { get; set; } = "Celsius"; // Celsius or Fahrenheit
    public int ForecastDays { get; set; }
}
 
internal class CountryContextReceiver : IOptionsContextReceiver
{
    public string? Country { get; private set; }
 
    public void Receive<T>(string key, T value)
    {
        if (key == nameof(Country))
        {
            Country = value?.ToString();
        }
    }
}
 
internal class WeatherForecastService : IWeatherForecastService
{
    private readonly IContextualOptions<WeatherForecastOptions, WeatherForecastContext> _contextualOptions;
    private readonly Random _rng = new(0);
 
    public WeatherForecastService(IContextualOptions<WeatherForecastOptions, WeatherForecastContext> contextualOptions)
    {
        _contextualOptions = contextualOptions;
    }
 
    public async Task<IEnumerable<WeatherForecast>> GetForecast(WeatherForecastContext context, CancellationToken cancellationToken)
    {
        WeatherForecastOptions options = await _contextualOptions.GetAsync(context, cancellationToken).ConfigureAwait(false);
        return Enumerable.Range(1, options.ForecastDays).Select(index => new WeatherForecast
        {
            Date = new DateTime(2000, 1, 1).AddDays(index),
            Temperature = _rng.Next(-20, 55),
            TemperatureScale = options.TemperatureScale,
        });
    }
}
 
internal interface IWeatherForecastService
{
    Task<IEnumerable<WeatherForecast>> GetForecast(WeatherForecastContext context, CancellationToken cancellationToken);
}
 
internal class WeatherForecast
{
    public DateTime Date { get; set; }
    public int Temperature { get; set; }
    public string TemperatureScale { get; set; } = string.Empty;
}
 
public class AcceptanceTests
{
    [Fact]
    public async Task Foo()
    {
        using var host = FakeHost.CreateBuilder()
            .ConfigureServices(services => services
                .Configure<WeatherForecastOptions>(options => options.ForecastDays = 7)
                .AddContextualOptions()
                .Configure<WeatherForecastOptions>(ConfigureTemperatureScaleBasedOnCountry)
                .AddSingleton<IWeatherForecastService, WeatherForecastService>())
                .Build();
 
        var forecastService = host
                .Services
                .GetRequiredService<IWeatherForecastService>();
 
        Assert.Equal("Fahrenheit", (await forecastService.GetForecast(new WeatherForecastContext { Country = "US" }, CancellationToken.None)).First().TemperatureScale);
        Assert.Equal("Celsius", (await forecastService.GetForecast(new WeatherForecastContext { Country = "CA" }, CancellationToken.None)).First().TemperatureScale);
 
        static void ConfigureTemperatureScaleBasedOnCountry(IOptionsContext context, WeatherForecastOptions options)
        {
            CountryContextReceiver receiver = new();
            context.PopulateReceiver(receiver);
            if (receiver.Country == "US")
            {
                options.TemperatureScale = "Fahrenheit";
            }
        }
    }
}