ASP.NET MVC: How to obtain assembly information from HtmlHelper instance? - c#

I have an HtmlHelper extension method in an assembly separate from my MVC application assembly. Within the extension method I would like to get the version number of the MVC application assembly. Is this possible?
The calling assembly is the razor view dynamic assembly so that doesn't help. Is there some object nested within the HtmlHelper that can provide me with the version number of the MVC application assembly? I've been exploring the HtmlHelper class documentation but so far haven't found a solution to my problem.
Thanks!

This is a notoriously evil thing - because unfortunately there's no one specific reliable way to do it.
Since it's an MVC application, however, the chances are that it has a Global.asax.cs - therefore it has a locally defined HttpApplication class.
From within an html helper you can get to this:
public static string AppVersion(this HtmlHelper html)
{
var appInstance = html.ViewContext.HttpContext.ApplicationInstance;
//given that you should then be able to do
var assemblyVersion = appInstance.GetType().BaseType.Assembly.GetName().Version;
//note the use of the BaseType - see note below
return assemblyVersion.ToString();
}
Note
You might wonder why the code uses the BaseType of the application instance, and not simply the type. That's because the Global.asax.cs file is the primary type of the MVC application, but then Asp.Net dynamically compiles another HttpApplication type that inherits from that via the Global.asax.
As I said earlier; this works in most MVC sites because they should all have an application class defined in a Global.asax.cs file by convention (because that's the way the project is set up).

Just in case anyone comes across this, here is what worked for me (MVC5 VS2013). Enter straight into the view:
#ViewContext.HttpContext.ApplicationInstance.GetType().BaseType.Assembly.GetName().Version.ToString();

Just search for the assembly which should be the source for your version number
AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name.Equals("MyDll")).First().GetName().Version.ToString();

Related

MVC 5 Custom ViewEngine to Load External Controllers and Views

REQUIREMENT
I have a project and one of requirements is load external small websites like plugins.
This websites must accomplish few requirements of course (like mvc and net version and other more to make it compatible).
This plugins must be allocated in a new folder inside my MVC Website. And in it there are Views folder and compiled website dll result (controllers, models,...)
CURRENT DEVELOPMENT
I implementented a custom ViewEngine to load Views from this folder, and a ControllerFactory that makes the trick for controllers that are not located in my main website.
I based my code in http://christianjvella.com/wordpress/mef-mvc-defining-controllerfactory/ for ControllerFactory and Can I specify a custom location to "search for views" in ASP.NET MVC? for ViewEngines
PROBLEM
All seems to works well with a simple html view. But when I use some MVC helpers or objects like ViewBag, #Url.Content, #Html.DropDownList i have an error that the object is null or not exist.
Overriding CreateView method in ViewEngine, it returns an IView instance correctly and controllerContext have ViewBag and other necessary features.
It seems that, at the moment of view rendering, MVC doesn't attach controllerContext to view instance...
Is this a limitation of MVC that don't pass controllerContext to external loaded views or externals controllers? Any idea or workaround?
Your views have to be pre-compiled. You can use precompiled MVC views for doing so.
Precompiled views are created using a VS Addin called as RazorGenerator.
You can read more about here, below example puts Views in separate class library! ,some thing that you are looking for:
http://www.c-sharpcorner.com/UploadFile/97fc7a/article-precompiled-razor-view-using-razorgenerator-mvc-and/
Well, I forget to include web.config in plugins Views folder, with it works fine because it defines Razor and MVC dll references.
Thanks for all
You could also use a VirtualPathProvider to serve things from other assemblies, including static assets and views. This way you can use the standard ViewENgine
https://www.nuget.org/packages/EmbeddedResourceVirtualPathProvider/

MVC4, Getting the AbsolutePath in Class Library

I have a class in my Class Library that's doing all sorts of validations and consistency checks for files before returning the result to the Web, and it used to work fine in WebForms with:
System.Web.HttpContext.Current.Server.MapPath("myFilePath here");
But now that I'm doing the same with MVC, the routing is messing up the MapPath.
How can I get the "base" path of the application in the Class Library using MvC?
Use:
HttpContext.Server.MapPath("~/myFilePath here");
I normally end up passing that path from controller to the helper library where it is needed.
Other option is using:
System.Web.Hosting.HostingEnvironment.MapPath("~/Your relative path from root website")
BTW, to use HostingEnvironment.MapPath(), you will need to add reference to System.Web.

Import Razor #helper from Class Project

Is there a way to import a dll from a class project (or maybe another web application project) into a web application project and reuse a #helper? The reusability for web applications with Razor seems pretty much zero if that cannot be achieved.
You can do it, but you have to jump through several hoops.
You need to obtain RazorGenerator: "This is a Custom Tool for Visual Studio that allows processing Razor files at design time instead of runtime, allowing them to be built into an assembly for simpler reuse and distribution. "
Using RazorGenerator, you can create .cshtml files in your class library project that declare helper functions. For example, in a file called Foo.cshtml:
#helper MyHelper(string parameter) {<text>#parameter</text>}
These helpers will exist as static methods in the static class representing your .cshtml file. In the above example, that would translate to Foo.MyHelper.
You can invoke these static methods from your web application's .cshtml file just like any other static method. (assuming you've added the correct using directives to point to the namespace containing your helper.) For example:
<div>#Foo.MyHelper("hello world")</div>

RouteValueDictionary in a c# library project to support html extension helpers?

I am trying to refactor a solution that includes 2 MVC projects: a "User-Experience" project and a corresponding "Content Management System project"
I have set up an independent C# library -- "Services" -- project in the same solution space to do many things. I want to share Html extension methods used by both web projects by placing them in this "neutral" project so that there are no dependencies between the two MVC projects.
I have a problem with using the RouteValueDictionary object (to.MergeAttributes) in this class library. I've included a reference to Sytem.Web.Routing in the Services project, but when I attempt to include a using statement at the top of the helper-class file, VStudio refuses to recognize the declaration ("Cannot resolve symbol 'Routing'").
This makes intuitive sense -- only a web project that can engage in URL routing should need a RouteValueDictionary.
But it appears common to use the RouteValueDictionary object inside htmlhelper classes because it can take an anonymous object consisting of name-value pairs and convert it to a Dictionary in its constructor like this:
tag.MergeAttributes(new RouteValueDictionary(htmlAttributes));
...thus providing a way of passing in any number of tag attribute name-value pairs into a tag and a relatively simple syntax for calling the helper in the view:
<%:Html.SomeTag(Model.Id, new {#class = "myClass", title = "myTitle"} %>
So if I can't use the RouteValueDictionary in my helper class, I'm forced with a more cumbersome syntax for my views, like this:
<%:Html.SomeTag(Model.Id, new Dictionary<string, string>{ {"class", "myClass"}, {"title", "myTitle} }%>
QUESTION: So, is there a way to re-write the helper class to get the simpler view syntax without using RouteValueDictionary, or is there a way to allow the use of RouteValueDictionary in a C# library project?
What project target have you given your class? The only thing I can think of is that you have your project target set to .NET 3.5 Client Profile which doesn't support any web stuff.
UPDATE: Based on your comments, the final resolution was to add a reference to System.Web.dll to your project.
In .NET 4.0, the System.Web.Routing.dll is type-forwarded to System.Web.dll. This is because the functionality in System.Web.Routing.dll from .NET 3.5 was migrated to the core System.Web assembly. The System.Web.Routing.dll (v4.0) exists to satisfy type-forwarding (to maintain backwards compatibility when migrating projects).
When you add a reference to System.Web.Routing.dll to your .NET 4.0 project, you also need to add a reference to System.Web.dll.

Strongly typed Html.ActionLink<T>() helper extension from MVC Futures doesn't do well with areas

I noticed some odd behaviour when using the strongly typed HtmlHelper.ActionLink() extension method from ASP.NET MVC 2 Futures. When I use it to link to a controller in an area I have to use the following attribute on this controller
[ActionLinkArea("SomeArea")]
It links properly to the actions of the controller located in SomeArea from the default area. The problem is when I want to link back to a Controller action located in the default area from within SomeArea. The link appears with "/SomeArea/" prefix. The workaround I use is:
[ActionLinkArea("")]
on the controller on all controllers that are located in the default area (using inheritance).
This seems odd because in my opinion that should be the default behavior of this method. Using .NET Reflector on this extension method I noticed that the error lies here:
return helper.RouteLink(linkText, routeValuesFromExpression, new RouteValueDictionary(htmlAttributes));
So it's actually the default behaviour of the HtmlHelper.
Known issue in MVC 2 Futures - same underlying cause as http://forums.asp.net/p/1535698/3732346.aspx.
From our internal database, if you wanted to patch the file and recompile MVC Futures yourself:
The bug is in LinkBuilder.cs, line 21.
The method call GetVirtualPath()
should be GetVirtualPathForArea().

Categories