Skip to content

Commit

Permalink
Normalize transaction names for ASP.NET Full Framework (#973)
Browse files Browse the repository at this point in the history
This commit normalizes the transaction name for ASP.NET MVC
Full Framework to use the convention of

<HTTP method> <area>/<controller>/<action> [<param>*]

which aligns with the convention used in ASP.NET Core
transaction names. The transaction name is determined from
the RouteData values.

- set unknown route only when the route data did not end up routing 
to a controller action. This is determined by looking for a 404 
HttpException coming from System.Web.Mvc.

- Add webforms page, routed webforms page, web api controller,
and area controller, to assert transaction name in each case.

- Integration tests introduce an MVC area with a HomeController
and Index action, to assert that the area route datatoken is
taken into account. Without taking into account the area,
same named controller actions in areas would end up
aggregrated under the same transaction name.

Closes #201
  • Loading branch information
russcam authored Oct 28, 2020
1 parent 3edcc20 commit 531d37c
Show file tree
Hide file tree
Showing 49 changed files with 969 additions and 282 deletions.
33 changes: 32 additions & 1 deletion sample/AspNetFullFrameworkSampleApp/App_Start/RouteConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,53 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Web;
using System.Web.Http;
using System.Web.Http.Batch;
using System.Web.Mvc;
using System.Web.Routing;

namespace AspNetFullFrameworkSampleApp
{
public class RouteConfig
{
/// <summary>
/// Registers Web API routes
/// </summary>
public static void RegisterWebApiRoutes(HttpConfiguration configuration, HttpBatchHandler batchHandler)
{
configuration.MapHttpAttributeRoutes();

configuration.Routes.MapHttpBatchRoute("Batch", "api/batch", batchHandler);
configuration.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
}

/// <summary>
/// Registers MVC and Webpage routes
/// </summary>
/// <param name="routes"></param>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { notRoutedWebforms = new NotRoutedWebformsConstraint() },
new[] { "AspNetFullFrameworkSampleApp.Controllers" }
);

routes.MapPageRoute(Webforms.RoutedWebforms,
Webforms.RoutedWebforms,
"~/Webforms.aspx"
);
}
}

public class NotRoutedWebformsConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) =>
values.TryGetValue("controller", out var controller) && (string)controller != Webforms.RoutedWebforms;
}
}
21 changes: 21 additions & 0 deletions sample/AspNetFullFrameworkSampleApp/App_Start/WebApiConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to Elasticsearch B.V under
// one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Linq;
using System.Web.Http;

namespace AspNetFullFrameworkSampleApp
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
// remove xml support
var appXmlType = configuration.Formatters.XmlFormatter.SupportedMediaTypes
.FirstOrDefault(t => t.MediaType == "application/xml");
configuration.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to Elasticsearch B.V under
// one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Web.Mvc;

namespace AspNetFullFrameworkSampleApp.Areas.MyArea.Controllers
{
public class HomeController : Controller
{
internal const string HomePageRelativePath = "MyArea/Home";

public ActionResult Index() => View();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to Elasticsearch B.V under
// one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Web.Mvc;

namespace AspNetFullFrameworkSampleApp.Areas.MyArea
{
public class MyAreaRegistration : AreaRegistration
{
public override void RegisterArea(AreaRegistrationContext context) =>
context.MapRoute("MyArea_Default",
"MyArea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "AspNetFullFrameworkSampleApp.Areas.MyArea.Controllers" });

public override string AreaName => "MyArea";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@{
ViewBag.Title = "My Area Home Page";
}

<div class="jumbotron">
<h1>ASP.NET</h1>
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
<p>
<a href="https://asp.net" class="btn btn-primary btn-lg">Learn more &raquo;</a>
</p>
</div>

<div class="row">
<div class="col-md-4">
<h2>Getting started</h2>
<p>
ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
enables a clean separation of concerns and gives you full control over markup
for enjoyable, agile development.
</p>
<p>
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301865">Learn more &raquo;</a>
</p>
</div>
<div class="col-md-4">
<h2>Get more libraries</h2>
<p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
<p>
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301866">Learn more &raquo;</a>
</p>
</div>
<div class="col-md-4">
<h2>Web Hosting</h2>
<p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
<p>
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a>
</p>
</div>
</div>
43 changes: 43 additions & 0 deletions sample/AspNetFullFrameworkSampleApp/Areas/MyArea/Web.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0"?>

<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>

<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
<add namespace="AspNetFullFrameworkSampleApp" />
</namespaces>
</pages>
</system.web.webPages.razor>

<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>

<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>

<system.web>
<compilation>
<assemblies>
<add assembly="System.Web.Mvc, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
</system.web>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand All @@ -42,6 +43,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<UseIISExpress>true</UseIISExpress>
Expand Down Expand Up @@ -113,6 +115,16 @@
<Compile Include="Models\ResetPasswordViewModel.cs" />
<Compile Include="Services\Auth\ApplicationSignInManager.cs" />
<Compile Include="Services\Auth\ApplicationUserManager.cs" />
<Compile Include="ActionFilters\RedirectIfAuthenticatedAttribute.cs" />
<Compile Include="App_Start\Startup.cs" />
<Compile Include="Extensions\TempDataExtensions.cs" />
<Compile Include="Services\Auth\ApplicationUserClaimsIdentityFactory.cs" />
<Compile Include="Areas\MyArea\Controllers\HomeController.cs" />
<Compile Include="Areas\MyArea\MyAreaRegistration.cs" />
<Compile Include="Webforms.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
<DependentUpon>Webforms.aspx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(OS)' == 'WINDOWS_NT'">
<Content Include="Content\bootstrap-grid.css" />
Expand Down Expand Up @@ -189,6 +201,11 @@
<Content Include="Views\Account\Register.cshtml" />
<Content Include="Views\Account\ResetPassword.cshtml" />
<Content Include="Views\Account\ResetPasswordConfirmation.cshtml" />
<Content Include="Views\Shared\_LoginPartial.cshtml" />
<Content Include="Areas\MyArea\Views\Home\Index.cshtml" />
<Content Include="Areas\MyArea\Web.config" />
<Content Include="Areas\MyArea\_ViewStart.cshtml" />
<Content Include="Webforms.aspx" />
<Content Include="Scripts\umd\popper.min.js.map" />
<Content Include="Scripts\umd\popper.js.map" />
<Content Include="Scripts\umd\popper-utils.min.js.map" />
Expand Down Expand Up @@ -267,13 +284,13 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="Views\Shared\_LoginPartial.cshtml" />
<Compile Include="App_Start\WebApiConfig.cs" />
<Compile Include="Controllers\WebApiController.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ActionFilters\RedirectIfAuthenticatedAttribute.cs" />
<Compile Include="App_Start\Startup.cs" />
<Compile Include="Extensions\TempDataExtensions.cs" />
<Compile Include="Services\Auth\ApplicationUserClaimsIdentityFactory.cs" />
<PackageReference Include="Microsoft.AspNet.WebApi">
<Version>5.2.4</Version>
</PackageReference>
</ItemGroup>
<PropertyGroup Condition="'$(OS)' == 'WINDOWS_NT'">
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
Expand All @@ -292,6 +309,13 @@
<TypeScriptMapRoot />
<TypeScriptSourceRoot />
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<UseIISExpress>true</UseIISExpress>
<Use64BitIISExpress />
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" Condition="'$(OS)' == 'WINDOWS_NT'" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="'$(OS)' == 'WINDOWS_NT' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
Expand All @@ -308,7 +332,9 @@
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>51565</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:51565/</IISUrl>
<IISUrl>http://localhost/Elastic.Apm.AspNetFullFramework.Tests.SampleApp</IISUrl>
<OverrideIISAppRootUrl>false</OverrideIISAppRootUrl>
<IISAppRootUrl>http://localhost:51565</IISAppRootUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
Expand Down
Loading

0 comments on commit 531d37c

Please sign in to comment.