Skip to content
Open
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
12 changes: 12 additions & 0 deletions Microsoft.FeatureManagement.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ 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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.FeatureManagement.Telemetry.AzureMonitor", "tests\Tests.FeatureManagement.Telemetry.AzureMonitor\Tests.FeatureManagement.Telemetry.AzureMonitor.csproj", "{B7D4E5F6-3A2B-4C8D-9E1F-7A8B9C0D1E2F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "examples\ConsoleApp\ConsoleApp.csproj", "{7B98D293-F270-423E-A9A6-0D388E903AE9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPages", "examples\RazorPages\RazorPages.csproj", "{36DBB413-D9CA-4C56-AE5B-EAEA4C344DB3}"
Expand All @@ -25,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TargetingConsoleApp", "exam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement.Telemetry.ApplicationInsights", "src\Microsoft.FeatureManagement.Telemetry.ApplicationInsights\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.csproj", "{7964DC66-B2D3-412D-B18A-86D1E07D149D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement.Telemetry.AzureMonitor", "src\Microsoft.FeatureManagement.Telemetry.AzureMonitor\Microsoft.FeatureManagement.Telemetry.AzureMonitor.csproj", "{A8F5C3D7-2E41-4B92-A3D1-6C7E8F9A1B2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VariantAndTelemetryDemo", "examples\VariantAndTelemetryDemo\VariantAndTelemetryDemo.csproj", "{1502529E-47E9-4306-98C4-BF6CF7C7C275}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServerApp", "examples\BlazorServerApp\BlazorServerApp.csproj", "{12BAB5A6-4EEB-4917-B5D9-4AFB6253008E}"
Expand Down Expand Up @@ -53,6 +57,10 @@ Global
{FC0DC3E2-5646-4AEC-A7DB-2D6167BC3BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC0DC3E2-5646-4AEC-A7DB-2D6167BC3BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC0DC3E2-5646-4AEC-A7DB-2D6167BC3BB4}.Release|Any CPU.Build.0 = Release|Any CPU
{B7D4E5F6-3A2B-4C8D-9E1F-7A8B9C0D1E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7D4E5F6-3A2B-4C8D-9E1F-7A8B9C0D1E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7D4E5F6-3A2B-4C8D-9E1F-7A8B9C0D1E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7D4E5F6-3A2B-4C8D-9E1F-7A8B9C0D1E2F}.Release|Any CPU.Build.0 = Release|Any CPU
{7B98D293-F270-423E-A9A6-0D388E903AE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B98D293-F270-423E-A9A6-0D388E903AE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B98D293-F270-423E-A9A6-0D388E903AE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -73,6 +81,10 @@ Global
{7964DC66-B2D3-412D-B18A-86D1E07D149D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7964DC66-B2D3-412D-B18A-86D1E07D149D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7964DC66-B2D3-412D-B18A-86D1E07D149D}.Release|Any CPU.Build.0 = Release|Any CPU
{A8F5C3D7-2E41-4B92-A3D1-6C7E8F9A1B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8F5C3D7-2E41-4B92-A3D1-6C7E8F9A1B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8F5C3D7-2E41-4B92-A3D1-6C7E8F9A1B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8F5C3D7-2E41-4B92-A3D1-6C7E8F9A1B2C}.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
Expand Down
25 changes: 25 additions & 0 deletions examples/VariantAndAzureMonitorDemo/LoggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace VariantAndAzureMonitorDemo
{
public static class LoggerExtensions
{
private static readonly Action<ILogger, string, int, Exception?> _vote = LoggerMessage.Define<string, int>(
LogLevel.Information,
new EventId(1, "microsoft.custom_event.name"),
"{microsoft.custom_event.name} {ImageRating}");

private static readonly Action<ILogger, string, string, long, Exception?> _checkout = LoggerMessage.Define<string, string, long>(
LogLevel.Information,
new EventId(1, "microsoft.custom_event.name"),
"{microsoft.custom_event.name} {success} {amount}");

public static void LogVote(this ILogger logger, int rating)
{
_vote(logger, "Vote", rating, null);
}

public static void LogCheckout(this ILogger logger, long amount)
{
_checkout(logger, "checkout", "yes", amount, null);
}
}
}
21 changes: 21 additions & 0 deletions examples/VariantAndAzureMonitorDemo/Pages/Checkout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@page
@model CheckoutModel
@{
ViewData["Title"] = "Checkout";
}
<h1>@ViewData["Title"]</h1>

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

<form method="post">
<button type="submit" id="checkout" name="checkout">
Check Out
</button>
</form>

@if (TempData["CheckedOut"] != null)
{
<script>
alert('Checked Out!');
</script>
}
35 changes: 35 additions & 0 deletions examples/VariantAndAzureMonitorDemo/Pages/Checkout.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Diagnostics.Metrics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace VariantAndAzureMonitorDemo.Pages
{
public class CheckoutModel : PageModel
{
private readonly Meter _meter;
private readonly ILogger<CheckoutModel> _logger;

public CheckoutModel(IMeterFactory meterFactory, ILogger<CheckoutModel> logger)
{
_meter = meterFactory?.Create("VariantAndAzureMonitorDemo") ?? throw new ArgumentNullException(nameof(meterFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public IActionResult OnPost()
{
long amount = Random.Shared.Next(1, 100);

// Track the checkout event using ILogger custom event
_logger.LogCheckout(amount);

// Track the checkout amount metric
var checkoutAmountHistogram = _meter.CreateHistogram<long>("checkoutAmount");
checkoutAmountHistogram.Record(amount);

TempData["CheckedOut"] = true;

return Page();
}
}
}
26 changes: 26 additions & 0 deletions examples/VariantAndAzureMonitorDemo/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/VariantAndAzureMonitorDemo/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 VariantAndAzureMonitorDemo.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/VariantAndAzureMonitorDemo/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>
</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/VariantAndAzureMonitorDemo/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Diagnostics.Metrics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Microsoft.FeatureManagement;

namespace VariantAndAzureMonitorDemo.Pages
{
public class IndexModel : PageModel
{
private readonly IVariantFeatureManager _featureManager;
private readonly Meter _meter;
private readonly ILogger<IndexModel> _logger;

public IndexModel(IVariantFeatureManager featureManager, IMeterFactory meterFactory, ILogger<IndexModel> logger)
{
_featureManager = featureManager ?? throw new ArgumentNullException(nameof(featureManager));
_meter = meterFactory?.Create("VariantAndAzureMonitorDemo") ?? throw new ArgumentNullException(nameof(meterFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public string Username { get; set; }

public async Task<IActionResult> OnGet()
{
Username = HttpContext.User.Identity.Name;

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))
{
// Create a histogram to track the image rating
var imageRatingHistogram = _meter.CreateHistogram<long>("ImageRating");
imageRatingHistogram.Record(rating);

// Track the vote event using ILogger custom event
_logger.LogVote(rating);
}
}

return Redirect("/RandomizeUser");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@page
@model VariantAndAzureMonitorDemo.Pages.RandomizeUserModel
@{
}
26 changes: 26 additions & 0 deletions examples/VariantAndAzureMonitorDemo/Pages/RandomizeUser.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;

namespace VariantAndAzureMonitorDemo.Pages
{
public class RandomizeUserModel : PageModel
{
public IActionResult OnGet()
{
// Generate new user claim
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, Random.Shared.Next().ToString())
};

var identity = new ClaimsIdentity(claims, "CookieAuth");
var principal = new ClaimsPrincipal(identity);

HttpContext.SignInAsync("CookieAuth", principal);

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