Using Assembly.GetCallingAssembly() inside custom HTML helpers in ASP.NET MVC
Suppose you need to get a reference to the assembly that originated the call to a custom HTML helper, you have probably tried calling Assembly.GetCallingAssembly()
within your helper method to achieve this. Instead, it will return an assembly name that you didn’t expect, perhaps something like: App_Web_views.home.index.cshtml.26149570.q0lhhvru
. This can happen in several situations, for instance placing your custom HTML helpers in a different class library, or embedding your Razor views in seperate .dlls.
You probably know that by default, ASP.NET web pages (.aspx), user controls (.ascx), and MVC Razor views (.cshtml and .vbhtml) are compiled dynamically on the server by the ASP.NET compiler (although it is possible to pre-compile them). What some don’t realize is that Razor views are compiled as separate assemblies by the ASP.NET runtime. Those assemblies are dynamic, hence the cryptic assembly naming.
For example, you may have code in your index.cshtml file that calls your custom helper:
@Html.GetMyAssemblyName()
And your custom HTML helper:
public static string GetMyAssemblyName(this HtmlHelper htmlHelper) { // returns the name of the dynamically generated dll that // the razor was compiled into return Assembly.GetCallingAssembly().GetName().Name; }
When the Razor code, within its dynamically generated dll, calls the helper method, it will end up returning the name of the dynamically generated dll. So how could you get the name of the project assembly that originally contained the .cshtml Razor view file?
One solution involves digging through the ViewContext to get the Controller that is associated with the view. Unlike views, code files in a web application project are compiled into a single assembly. Once you know the name of the Controller, you can search through the app domain for the assembly that contains it. Here is the modified HTML helper that does this:
public static string GetMyAssemblyName(this HtmlHelper htmlHelper) { var controllerType = htmlHelper.ViewContext.Controller.GetType() var callingAssembly = Assembly.GetAssembly(controllerType); if(callingAssembly != null) return callingAssembly.GetName().Name; return null; }
Not all views have a controller associated with them, for instance, layouts. In this case another way of getting the originating controller would be through calling:
htmlHelper.ViewContext.RouteData.Values["controller"]
And then retrieving the controller type through reflection.