<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>asp net controller &#8211; ASP.NET Hosting Reviews and Guides</title>
	<atom:link href="https://topreviewhostingasp.net/tag/asp-net-controller/feed/" rel="self" type="application/rss+xml" />
	<link>https://topreviewhostingasp.net</link>
	<description>ASP.NET Hosting &#124; Reviews &#124; Tips &#38; Tutorial</description>
	<lastBuildDate>Tue, 16 Mar 2021 03:59:45 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://topreviewhostingasp.net/wp-content/uploads/2017/01/cropped-trhaico-32x32.png</url>
	<title>asp net controller &#8211; ASP.NET Hosting Reviews and Guides</title>
	<link>https://topreviewhostingasp.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using ASP.NET Core to Find Controllers in Your App</title>
		<link>https://topreviewhostingasp.net/using-asp-net-core-to-find-controllers-in-your-app/</link>
					<comments>https://topreviewhostingasp.net/using-asp-net-core-to-find-controllers-in-your-app/#respond</comments>
		
		<dc:creator><![CDATA[Jacques Hunt]]></dc:creator>
		<pubDate>Tue, 16 Mar 2021 03:57:20 +0000</pubDate>
				<category><![CDATA[Hosting Tips]]></category>
		<category><![CDATA[asp net controller]]></category>
		<category><![CDATA[ASP.NET Hosting]]></category>
		<category><![CDATA[asp.net tips]]></category>
		<category><![CDATA[asp.net tutorial]]></category>
		<guid isPermaLink="false">https://topreviewhostingasp.net/?p=2942</guid>

					<description><![CDATA[In this post I describe application parts and how ASP.NET Core uses them to find the controllers in your app. I then show how you can retrieve the list at runtime for debugging purposes. Debugging a missing controller A while ago I was converting an ASP.NET application to ASP.NET Core. The solution had many class [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>In this post I describe application parts and how ASP.NET Core uses them to find the controllers in your app. I then show how you can retrieve the list at runtime for debugging purposes.</p>



<h2 class="wp-block-heading">Debugging a missing controller</h2>



<p>A while ago I was converting an ASP.NET application to ASP.NET Core. The solution had many class library projects, where each project represented a module or vertical slice of the application. These modules contained everything for that feature: the database code, the domain, and the Web API controllers. There was then a &#8220;top level&#8221; application that referenced all these modules and served the requests.</p>



<p>As the whole solution was based on Katana/Owin and used Web API controllers exclusively, it wasn&#8217;t too hard to convert it to ASP.NET Core. But, of course, there were bugs in the conversion process. One thing that had me stumped for a while was why the controllers from some of the modules didn&#8217;t seem to be working. All of the requests to certain modules were returning 404s.</p>



<p>There were a few possibilities in my mind for what was going wrong:</p>



<ol>
<li>There was a routing issue, so requests meant for the controllers were not reaching them</li>
<li>There was a problem with the controllers themselves, meaning they were generating 404s</li>
<li>The ASP.NET Core app wasn&#8217;t aware of the controllers in the module at all.</li>
</ol>



<p>My gut feeling was the problem was either 1 or 3, but I needed a way to check. The solution I present in this post let me rule out point 3, by listing all the <code>ApplicationPart</code>s and controllers the app was aware of.</p>



<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://www.asphostportal.com"><img fetchpriority="high" decoding="async" width="300" height="271" class="wp-image-2584 aligncenter" src="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png" alt="" srcset="https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01.png 300w, https://topreviewhostingasp.net/wp-content/uploads/2018/11/ahp-banner-aspnet-01-50x45.png 50w" sizes="(max-width: 300px) 100vw, 300px" /></a></figure>
</div>



<h2 class="wp-block-heading">What are application parts?</h2>



<p>Application Parts allow you to share the same resources (controllers, Razor Pages etc) between multiple apps. If you&#8217;re familiar with <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-3.1&amp;tabs=visual-studio">Razor Class Libraries</a>, then think of application parts as being the abstraction behind it.</p>



<p>One application part implementation is <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationparts.assemblypart?view=aspnetcore-3.1">an <code>AssemblyPart</code></a> which is an application part associated with an assembly. This is the situation I had in the app I described previously &#8211; each of the module projects was compiled into a separate <code>Assembly</code>, and then added to the application as application parts.</p>



<p>You can add application parts in <code>ConfigureServices</code> when you configure MVC. The current assembly is added automatically, but you can add additional application parts too. The example below adds the assembly that contains <code>TestController</code> (which resides in a different project) as an application part.</p>



<pre class="wp-block-code"><code>public void ConfigureServices(IServiceCollection services)
{
    services
        .AddControllers()
        .AddApplicationPart(typeof(TestController).Assembly);
}</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em>Note that in ASP.NET Core 3.x, when you compile an assembly that references ASP.NET Core, </em><a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationparts.applicationpartattribute?view=aspnetcore-3.1">an assembly attribute is added to the output, <code>[ApplicationPart]</code></a><em>. ASP.NET Core 3.x apps look for this attribute on referenced assemblies and registers them as application parts automatically, so the code above isn&#8217;t necessary.</em></p>
</blockquote>



<p>We&#8217;ve covered how you register application parts, but how do we debug when things go wrong?</p>



<h2 class="wp-block-heading">Providing features with the ApplicationPartManager</h2>



<p>When you add an application part (or when ASP.NET Core adds it automatically), it&#8217;s added to the <code>ApplicationPartManager</code>. <a href="https://github.com/dotnet/aspnetcore/blob/6255c1ed960f5277d2e96ac2d0968c2c7e844ce2/src/Mvc/Mvc.Core/src/ApplicationParts/ApplicationPartManager.cs">This class</a> is responsible for keeping track of all the application parts in the app, and for populating various <em>features</em> based on the registered parts, in conjunction with registered <em>feature providers</em>.</p>



<p>There are a variety of <em>features</em> used in MVC, such as the <code>ControllerFeature</code> and <code>ViewsFeature</code> for example. <a href="https://github.com/dotnet/aspnetcore/blob/6255c1ed960f5277d2e96ac2d0968c2c7e844ce2/src/Mvc/Mvc.Core/src/Controllers/ControllerFeature.cs">The <code>ControllerFeature</code> (shown below)</a> contains a list of all the controllers available to an application, across all of the registered application parts.</p>



<pre class="wp-block-code"><code>public class ControllerFeature
{
    public IList&lt;TypeInfo&gt; Controllers { get; } = new List&lt;TypeInfo&gt;();
}</code></pre>



<p>The list of controllers is obtained <a href="https://github.com/dotnet/aspnetcore/blob/6255c1ed960f5277d2e96ac2d0968c2c7e844ce2/src/Mvc/Mvc.Core/src/Controllers/ControllerFeatureProvider.cs">by using the <code>ControllerFeatureProvider</code></a>. <a href="https://github.com/dotnet/aspnetcore/blob/6255c1ed960f5277d2e96ac2d0968c2c7e844ce2/src/Mvc/Mvc.Core/src/ApplicationParts/IApplicationFeatureProviderOfT.cs">This class implements the <code>IApplicationFeatureProvider&lt;T&gt;</code> interface</a>, which, when given a list of application parts, populates an instance of <code>ControllerFeature</code> with all the controllers it finds.</p>



<pre class="wp-block-code"><code>public class ControllerFeatureProvider : IApplicationFeatureProvider&lt;ControllerFeature&gt;
{
    public void PopulateFeature(IEnumerable&lt;ApplicationPart&gt; parts, ControllerFeature feature)
    {
        <em>// Loop through all the application parts</em>
        foreach (var part in parts.OfType&lt;IApplicationPartTypeProvider&gt;())
        {
            <em>// Loop through all the types in the application part</em>
            foreach (var type in part.Types)
            {
                <em>// If the type is a controller (and isn't already added) add it to the list</em>
                if (IsController(type) &amp;&amp; !feature.Controllers.Contains(type))
                {
                    feature.Controllers.Add(type);
                }
            }
        }
    }

    protected virtual bool IsController(TypeInfo typeInfo) =&gt; { <em>/* Elided for brevity*/</em> }
}
</code></pre>



<p>The <code>ApplicationPartManager</code> exposes <a href="https://github.com/dotnet/aspnetcore/blob/6255c1ed960f5277d2e96ac2d0968c2c7e844ce2/src/Mvc/Mvc.Core/src/ApplicationParts/ApplicationPartManager.cs#L40-L50">a <code>PopulateFeature</code> method which calls all the appropriate feature providers for a given feature</a>:</p>



<pre class="wp-block-code"><code>public class ApplicationPartManager
{
    <em>// The list of application parts</em>
    public IList&lt;ApplicationPart&gt; ApplicationParts { get; } = new List&lt;ApplicationPart&gt;();

    <em>// The list of feature providers for the various possible features</em>
    public IList&lt;IApplicationFeatureProvider&gt; FeatureProviders { get; } =
            new List&lt;IApplicationFeatureProvider&gt;();


    <em>// Populate the feature of type TFeature</em>
    public void PopulateFeature&lt;TFeature&gt;(TFeature feature)
    {
        foreach (var provider in FeatureProviders.OfType&lt;IApplicationFeatureProvider&lt;TFeature&gt;&gt;())
        {
            provider.PopulateFeature(ApplicationParts, feature);
        }
    }</code></pre>



<p>That covers all the background for <code>ApplicationPartManager</code> and features.</p>



<h2 class="wp-block-heading">Listing all the Application parts and controllers added to an application</h2>



<p>To quickly work out whether my <code>404</code> problem was due to routing or missing controllers, I needed to interrogate the <code>ApplicationPartManager</code>. If the application parts and controllers for the problematic modules were missing, then that was the problem; if they were present, then it was probably some sort of routing issue!</p>



<p>To debug the issue I wrote a quick <code>IHostedService</code> that logs the application parts added to an application, along with all of the controllers discovered.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I used an <code>IHostedService</code> because it runs after application part discovery, and only executes once on startup.</p>
</blockquote>



<p>The example below takes an <code>ILogger</code> and the <code>ApplicationPartManager</code> as dependencies. It then lists the names of the application parts, populates an instance of the <code>ControllerFeature</code>, and lists all the controllers known to the app. These are written to a log message which can be safely inspected</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/app-parts?view=aspnetcore-3.1#display-available-features">A similar example in the documentation</a><em> exposes this information via a Controller, which seems like a bit of a bad idea to me!</em></p>
</blockquote>



<pre class="wp-block-code"><code>public class ApplicationPartsLogger : IHostedService
{
    private readonly ILogger&lt;ApplicationPartsLogger&gt; _logger;
    private readonly ApplicationPartManager _partManager;

    public ApplicationPartsLogger(ILogger&lt;ApplicationPartsLogger&gt; logger, ApplicationPartManager partManager)
    {
        _logger = logger;
        _partManager = partManager;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        <em>// Get the names of all the application parts. This is the short assembly name for AssemblyParts</em>
        var applicationParts = _partManager.ApplicationParts.Select(x =&gt; x.Name);

        <em>// Create a controller feature, and populate it from the application parts</em>
        var controllerFeature = new ControllerFeature();
        _partManager.PopulateFeature(controllerFeature);

        <em>// Get the names of all of the controllers</em>
        var controllers = controllerFeature.Controllers.Select(x =&gt; x.Name);

        <em>// Log the application parts and controllers</em>
        _logger.LogInformation("Found the following application parts: '{ApplicationParts}' with the following controllers: '{Controllers}'",
            string.Join(", ", applicationParts), string.Join(", ", controllers));

        return Task.CompletedTask;
    }

    <em>// Required by the interface</em>
    public Task StopAsync(CancellationToken cancellationToken) =&gt; Task.CompletedTask;
}</code></pre>



<p>All that remains is to register the hosted service in <code>Startup.ConfigureServices</code>:</p>



<pre class="wp-block-code"><code>public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddHostedService&lt;ApplicationPartsLogger&gt;();
}</code></pre>



<p>Below is example log message, in which an API project (<em>ApplicationPartsDebugging.Api</em>) references a class library (<em>ApplicationPartsDebugging.Controllers</em>) which contains a controller, <code>TestController</code>.</p>



<pre class="wp-block-code"><code>info: ApplicationPartsDebugging.Api.ApplicationPartsLogger[0]
      Found the following application parts: 'ApplicationPartsDebugging.Api, ApplicationPartsDebugging.Controllers' 
      with the following controllers: 'WeatherForecastController, TestController'</code></pre>



<p>Both the API app and the class library are referenced as application parts, and controllers from both application parts are available.</p>



<p>And yes, this was exactly the problem I had during my conversion, I&#8217;d failed to register one of the modules as an application part, shown by it&#8217;s absence from my log message!</p>



<h2 class="wp-block-heading" id="summary">Summary</h2>



<p>In this post I described a problem I faced when converting an application to ASP.NET Core &#8211; the controllers from a referenced project could not be found. ASP.NET Core looks for controllers, views, and other features in <em>application parts</em> that it knows about. You can add additional application parts to an ASP.NET Core manually, though ASP.NET Core 3.x will generally handle this for you automatically. To debug my problem I created an <code>ApplicationPartsLogger</code> that lists all the registered application parts for an app. This allows you to easily spot when an expected assembly is missing.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://topreviewhostingasp.net/using-asp-net-core-to-find-controllers-in-your-app/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
