Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions Microsoft.FeatureManagement.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{FB
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.FeatureManagement.AspNetCore", "tests\Tests.FeatureManagement.AspNetCore\Tests.FeatureManagement.AspNetCore.csproj", "{FC0DC3E2-5646-4AEC-A7DB-2D6167BC3BB4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "examples\ConsoleApp\ConsoleApp.csproj", "{7B98D293-F270-423E-A9A6-0D388E903AE9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "examples\ConsoleApp\ConsoleApp.csproj", "{7B98D293-F270-423E-A9A6-0D388E903AE9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorPages", "examples\RazorPages\RazorPages.csproj", "{36DBB413-D9CA-4C56-AE5B-EAEA4C344DB3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPages", "examples\RazorPages\RazorPages.csproj", "{36DBB413-D9CA-4C56-AE5B-EAEA4C344DB3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FeatureFlagDemo", "examples\FeatureFlagDemo\FeatureFlagDemo.csproj", "{DACAB624-4611-42E8-844C-529F93A54980}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FeatureFlagDemo", "examples\FeatureFlagDemo\FeatureFlagDemo.csproj", "{DACAB624-4611-42E8-844C-529F93A54980}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TargetingConsoleApp", "examples\TargetingConsoleApp\TargetingConsoleApp.csproj", "{283D3EBB-4716-4F1D-BA51-A435F7E2AB82}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TargetingConsoleApp", "examples\TargetingConsoleApp\TargetingConsoleApp.csproj", "{283D3EBB-4716-4F1D-BA51-A435F7E2AB82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EvaluationDataToApplicationInsights", "examples\EvaluationDataToApplicationInsights\EvaluationDataToApplicationInsights.csproj", "{1502529E-47E9-4306-98C4-BF6CF7C7C275}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement.Telemetry.ApplicationInsights", "src\Microsoft.FeatureManagement.Telemetry.ApplicationInsights\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.csproj", "{3448BDE1-5145-49D4-936A-757B68387439}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -61,6 +65,14 @@ Global
{283D3EBB-4716-4F1D-BA51-A435F7E2AB82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{283D3EBB-4716-4F1D-BA51-A435F7E2AB82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{283D3EBB-4716-4F1D-BA51-A435F7E2AB82}.Release|Any CPU.Build.0 = Release|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Release|Any CPU.Build.0 = Release|Any CPU
{3448BDE1-5145-49D4-936A-757B68387439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3448BDE1-5145-49D4-936A-757B68387439}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3448BDE1-5145-49D4-936A-757B68387439}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3448BDE1-5145-49D4-936A-757B68387439}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -72,6 +84,7 @@ Global
{36DBB413-D9CA-4C56-AE5B-EAEA4C344DB3} = {FB5C34DF-695C-4DF9-8AED-B3EA2516EA72}
{DACAB624-4611-42E8-844C-529F93A54980} = {FB5C34DF-695C-4DF9-8AED-B3EA2516EA72}
{283D3EBB-4716-4F1D-BA51-A435F7E2AB82} = {FB5C34DF-695C-4DF9-8AED-B3EA2516EA72}
{1502529E-47E9-4306-98C4-BF6CF7C7C275} = {FB5C34DF-695C-4DF9-8AED-B3EA2516EA72}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {84DA6C54-F140-4518-A1B4-E4CF42117FBD}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="6.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.FeatureManagement.AspNetCore\Microsoft.FeatureManagement.AspNetCore.csproj" />
<ProjectReference Include="..\..\src\Microsoft.FeatureManagement.Telemetry.ApplicationInsights\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Microsoft.FeatureManagement.FeatureFilters;

namespace EvaluationDataToApplicationInsights
{
/// <summary>
/// Provides an implementation of <see cref="ITargetingContextAccessor"/> that creates a targeting context using info from the current HTTP request.
/// </summary>
public class HttpContextTargetingContextAccessor : ITargetingContextAccessor
{
private const string TargetingContextLookup = "HttpContextTargetingContextAccessor.TargetingContext";
private readonly IHttpContextAccessor _httpContextAccessor;

public HttpContextTargetingContextAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}

public ValueTask<TargetingContext> GetContextAsync()
{
HttpContext httpContext = _httpContextAccessor.HttpContext;

//
// Try cache lookup
if (httpContext.Items.TryGetValue(TargetingContextLookup, out object value))
{
return new ValueTask<TargetingContext>((TargetingContext)value);
}

string username = httpContext.Request.Cookies["username"];

var groups = new List<string>();

//
// Build targeting context based on user info
var targetingContext = new TargetingContext
{
UserId = username,
Groups = groups
};

//
// Cache for subsequent lookup
httpContext.Items[TargetingContextLookup] = targetingContext;

return new ValueTask<TargetingContext>(targetingContext);
}
}
}
12 changes: 12 additions & 0 deletions examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@page
@model CheckoutModel
@{
ViewData["Title"] = "Checkout";
}
<h1>@ViewData["Title"]</h1>

<p>Click Below To Check Out!</p>

<button id="checkout" name="checkout" onclick="appInsights.trackEvent({ name: 'checkout', properties: { 'success' : 'yes' } }); appInsights.trackMetric({ name: 'checkoutAmount', average: Math.floor(Math.random() * 100) }); alert('Checked Out!');">
Check Out
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace EvaluationDataToApplicationInsights.Pages
{
public class CheckoutModel : PageModel
{
}
}
26 changes: 26 additions & 0 deletions examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
27 changes: 27 additions & 0 deletions examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;

namespace EvaluationDataToApplicationInsights.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}

public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}
72 changes: 72 additions & 0 deletions examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}

<div class="text-center mb-40">
<h1 class="display-4">Welcome, @Model.Username !</h1>
</div>

<div class="text-center">
<div style="display:inline-block;width:500px;">
<img class="mb-40" src="@ViewData["ImageUri"]" />
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">
<span class="glyphicon glyphicon-arrow-right"></span>Rate the image on a scale of 1 - 5 !<span class="glyphicon glyphicon-new-window"></span></a>
</h3>
</div>
<form action="/" method="post">
<div class="panel-body mb-5">
<ul class="list-group">
<li class="list-group-item">
<div class="radio">
<label>
<input type="radio" name="imageScore" value="5">
5
</label>
</div>
</li>
<li class="list-group-item">
<div class="radio">
<label>
<input type="radio" name="imageScore" value="4">
4
</label>
</div>
</li>
<li class="list-group-item">
<div class="radio">
<label>
<input type="radio" name="imageScore" value="3">
3
</label>
</div>
</li>
<li class="list-group-item">
<div class="radio">
<label>
<input type="radio" name="imageScore" value="2">
2
</label>
</div>
</li>
<li class="list-group-item">
<div class="radio">
<label>
<input type="radio" name="imageScore" value="1">
1
</label>
</div>
</li>
</ul>
</div>
@Html.AntiForgeryToken()
<div class="panel-footer">
<input type="submit" class="btn btn-primary btn-sm" value="Vote" />
</div>
</form>
</div>
</div>
</div>
66 changes: 66 additions & 0 deletions examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.FeatureManagement;

namespace EvaluationDataToApplicationInsights.Pages
{
public class IndexModel : PageModel
{
private readonly IVariantFeatureManager _featureManager;
private readonly TelemetryClient _telemetry;

public string Username { get; set; }

public IndexModel(
IVariantFeatureManager featureManager,
TelemetryClient telemetry)
{
_featureManager = featureManager ?? throw new ArgumentNullException(nameof(featureManager));
_telemetry = telemetry ?? throw new ArgumentNullException(nameof(telemetry));
}

public async Task<IActionResult> OnGet()
{
Username = Request.Cookies["username"];

if (string.IsNullOrEmpty(Username))
{
return Redirect("/RandomizeUser");
}

//
// Use application's feature manager to get assigned variant for current user
Variant variant = await _featureManager
.GetVariantAsync("ImageRating", HttpContext.RequestAborted);

//
// Set the page's display image based on the assigned variant.
ViewData["ImageUri"] = variant.Configuration.Value;

return Page();
}

public IActionResult OnPost()
{
if (Request.Form != null)
{
string val = Request.Form["imageScore"];

if (val != null &&
int.TryParse(val, out int rating))
{
_telemetry.TrackEvent(
"Vote",
properties: null,
metrics: new Dictionary<string, double>
{
{ "ImageRating", rating }
});
}
}

return Redirect("/RandomizeUser");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@page
@model EvaluationDataToApplicationInsights.Pages.RandomizeUserModel
@{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace EvaluationDataToApplicationInsights.Pages
{
public class RandomizeUserModel : PageModel
{
public IActionResult OnGet()
{
// Clear Application Insights cookies and generate new username
Response.Cookies.Delete("ai_user");
Response.Cookies.Delete("ai_session");
Response.Cookies.Append("username", Random.Shared.Next().ToString());

return RedirectToPage("/Index");
}
}
}
Loading