Reputation: 164
Say I have a Class Library containing a HelloWorld.js file.
This file contains a couple javascript functions, like say:
function Hello_alert() {
alert("Hello World!!");
}
and
function Hello_console() {
console.log("Hello World!!");
}
I want to make so I can access the functions inside the HelloWorld.js file individually, on an ASP.NET MVC page, say, the Index.cshtml inside the Home folder. (Failing that, I'd be happy just accessing the .js file at all.)
I have already changed the .js as EmbeddedResource and added it to the Assembly as such:
[assembly: WebResource("JSLibrary.Scriptss.HelloWorld.js", "application/x-javascript")]
; referenced the DLL on my MVC project, and the DLL namespace shows up on Intellisense so I'm guessing it's linked right.
Now, I've been googling incessantly the whole day, and I've found a solution that kinda does what I need, but it's for Web Forms, using Page.ClientScript to register the scripts into the page itself, which allows one to call the functions inside the .js file on that page. This is pretty much what I'm trying to do, except I need it in MVC, which doesn't use the "Page" class like that.
The closes equivalent I've found has something to do with bundles, but I couldn't find any tutorials that I could viably follow.
So again, my question is, how do I somehow register Javascript files from a DLL in order for me to be able to call them from an ASP.NET MVC project?
--------Update:---------
Following the tutorial I linked above, my DLL has a class with a method that is used to register the scripts in a Script Manager, that it receives as a parameter. Like so
public static void includeHelloWorld(ClientScriptManager manager)
{
manager.RegisterClientScriptResource(typeof(JSLibrary.JSAccess), ScriptPath_HelloWorld);
}//JSLibrary being the DLL namespace and JSAccess being the class
Then, in the main project, using Web Forms, you can call that method and pass it the ClientScript property of the current Page, where the scripts get registered, I assume. Like so:
protected void Page_Load(object sender, EventArgs e)
{
JSLibrary.JSAccess.includeHelloWorld(Page.ClientScript);
}
I've tried it and it works on Web Forms. I need the equivalent of the Page.ClientScript in MVC, that I can send to the method in the DLL that takes in a ClientScriptManager.
Thanks
Upvotes: 5
Views: 2522
Reputation: 55
If you implement Zidd's technique and get "Failed to load resource: the server responded with a status of 404 (Not Found)" than add this line:
BundleTable.EnableOptimizations = true;
at the end of BundleConfig.RegisterBundles
method.
Upvotes: 4
Reputation: 164
OK I figured it out.
Since nobody responded, I figured I would come back and share with the world the solution to my problem, just in case someone else finds it useful.
Apparently, MVC has this Blundles feature that allows you to bundle, amongst other stuff, JS scripts for future use. Bundles use Virtual Paths to access their files, but the default Virtual Paths can't access DLLs (at least not the files in it), so we have to create a custom Virtual Path in our DLL. After registering this VP in the main program, we can access files on the DLL as if they were on our main program and thus, include the scripts in our bundle.
Notice this probably isn't the best or most efficient method, just something I scrapped together that seems to work.
Ok, so here's how we do it:
First off, install the following NuGet package:
Install-Package EmbeddedResourceVirtualPathProvider
Then, in our DLL, make sure your .js file is set as embedded resource. Next we create a class in the root of the namespace, which is gonna be our Virtual Path provider and Virtual File. Basically, just put this code in the root of the namespace:
public class EmbeddedVirtualPathProvider : VirtualPathProvider
{
private readonly Assembly assembly = typeof(EmbeddedVirtualPathProvider).Assembly;
private readonly string[] resourceNames;
public EmbeddedVirtualPathProvider()
{
this.resourceNames = assembly.GetManifestResourceNames();
}
private bool IsEmbeddedResourcePath(string virtualPath)
{
var checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
var resourceName = this.GetType().Namespace + "." + checkPath.Replace("~/", "").Replace("/", ".");
return this.resourceNames.Contains(resourceName);
}
public override bool FileExists(string virtualPath)
{
return IsEmbeddedResourcePath(virtualPath) || base.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
if (IsEmbeddedResourcePath(virtualPath))
{
return new EmbeddedVirtualFile(virtualPath);
}
return base.GetFile(virtualPath);
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
if (IsEmbeddedResourcePath(virtualPath))
{
return null;
}
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
}
public class EmbeddedVirtualFile : VirtualFile
{
private readonly string virtualPath;
private readonly Assembly assembly;
public EmbeddedVirtualFile(string virtualPath)
: base(virtualPath)
{
this.assembly = this.GetType().Assembly;
this.virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);
}
public override System.IO.Stream Open()
{
var resourceName = this.GetType().Namespace + "." + virtualPath.Replace("~/", "").Replace("/", ".");
return assembly.GetManifestResourceStream(resourceName);
}
}
That's two classes in the code above.
You will need to include a few libraries such as
using System.Reflection;
using System.Web.Hosting;
using System.Web;
using System.Web.Caching;
using System.Collections;
Now, in our main project, we're going to register this Virtual Path. If you haven't referenced the DLL in your main: in the solution explorer, under your Main project, right click References -> Add Reference and select your DLL.
In order to register the VP, simply add this line in your main project's Global.asax file (on the very top of your Application_Start() method):
HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedVirtualPathProvider());
You will need to include in the Global.asax:
using System.Web.Hosting;
using <your dll namespace>;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
Now to add the script(s) to the bundles. Inside the App_Start folder should be a BundleConfig.cs file. Inside the RegisterBundles method, you can just write:
bundles.Add(new ScriptBundle("~/bundles/external/helloworld").Include(
"~/Scripts/HelloWorld.js"));
where the first argument ("~/bundles/external/helloworld") can be anything you want after the ~/, and the second argument ("~/Scripts/HelloWorld.js") has to be the path to your script inside the DLL.
To finalize, let's render the scripts in our views. Pick a view, say Index.cshtml, and just include the line:
@Scripts.Render("~/bundles/external/helloworld")
the parameter being whatever you named it when creating the bundle, and now it should work!
Upvotes: 7