I have a MVC application that developed partially by someone else. It works in that particular Machine.
When i run the application in my machine, I found the scripts in bundle are rendering with relative path.
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.js"></script>
all the scripts rendering same way where as the CSS files are rendering good. I am using bundles this way.
in BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/EMRMobileScript").Include (
"~/MobileQuerys/js/jquery.js",
"~/MobileQuerys/docs/_assets/js/jqm-demos.js"
));
In _Layout.cshtml
#Styles.Render("~/Content/EMRMobilecss")
#System.Web.Optimization.Scripts.Render("~/bundles/EMRMobileScript")
In browser console
GET http://localhost:6326/~/Scripts/jquery-1.9.1.js 404 (Not Found)
Why its rendering with ~ ??
Your client doesn't know what the "~" sign means while the server does. It's just another char the you placed in a string.
When you add a relative src it will be "concated" to the current path, which is
http://localhost:6326/
and thats why you get this request:
http://localhost:6326/~/Scripts/jquery-1.9.1.js
Now, when you use this line of code in the server:
#Styles.Render("~/Content/EMRMobilecss")
The server knows how to map the path(where ~ is the applications "root" directory).
In order to render the specifc bundle from your js, use this:
<script src='http://localhost:6326/Scripts/jquery-1.9.1.js'></script>
If it's running on the local host, it's a known bug that occurs. If IIS is running the application it more than likely is an issue with that. Have you tried just running this with just the MVC?
Otherwise there isn't really a work around for this when running it on IIS.
Related
I've got an ASP.NET web page where I want to ensure users get the latest version of the javascript file each time they load the page, but I do not want them to download the file unless it's actually changed. It is a continually evolving web app and the js files get modified frequently. I have a version number in the url that I update manually. But I keep forgetting to update it when I change the js file.
<script type="text/javascript" src="js/Sched.js?v=1"></script>
So doing some searching for auto-versioning methods, I found one using re-writes and php, which made me think about my environment. The only thing I came up with was to use the LastWriteTime of the js file for the version. So I built a function:
protected string GetFileTime(string file)
{
FileInfo fi = new FileInfo(Server.MapPath(file));
if (fi.Exists)
{
Debug.WriteLine(fi.FullName);
return fi.LastWriteTimeUtc.ToFileTime().ToString();
}
else
{
Debug.WriteLine("0");
return "0";
}
}
And changed my script url in the page:
<script type="text/javascript" src="js/Sched.js?dev=<%= GetFileTime("js/Sched.js") %>"></script>
It seems to work great on my dev server. The browser sees this:
<script type="text/javascript" src="js/Sched.js?dev=131969009464369343"></script>
I've tested it with many page loads and the number remains the same until I make a change to the file.
So it seems like a great solution. I've looked at FileInfo and it reads the file meta data from the disk and does not open or lock the file. But when I put it live on the production server with about 1000 users, is there a possibility of performance or other issues?
I have a website in IIS, under the website there are couples of web applications (website and web applications all are mvc web application).
The website uses ASP.NET MVC bundling -
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/css")
.IncludeDirectory("~/Content/Styles", "*.css", true));
bundles.Add(new ScriptBundle("~/Content/js")
.IncludeDirectory("~/Content/Scripts", "*.js", true));
}
In website _Layout.cshtml -
#Styles.Render("~/Content/css")
#Script.Render("~/Content/js")
When website is browsed (e.g. mywebsite.com), I can see querystring attached to those references.
<link href="/Content/css?v=asdsf$dfsdfdslkko" rel="stylesheet" />
<script src="/Content/js?v=jjkase$rads#asdasd"></script>
And for my child web application under that website in IIS, if I have to use same bundled resources, I can do (in webapp layout page) -
#Styles.Render("/Content/css")
#Script.Reder("/Content/js")
When webapp is browsed (e.g. mywebsite.com/mywebapp), I can access those resource from parent website but I couldnot get those querystrings in style and script references.
<link href="/Content/css" rel="stylesheet" />
<script src="/Content/js></scripts>
The only difference is I must use starting / for webapp which is the cause for not generating querystring. It's a weird behavior. I need querystring while browsing webapp too (to avoid cache). If I used / instead of ~ in my parent website also, querystring gets dissapeared (DISGUSTING).
Is there anyway to retain querystring even / is used for referencing bundles? Any help will be highly appreciated.
Thanks in advance.
First off, bundling is project-centric. There's no way to share bundles in one application with another, child or not. What you're doing here is essentially taking advantage of the fact that the bundling framework actually caches the created bundles to a real file, which then allows you to reference it in the other project as you would any other random static JavaScript/CSS file. However, with this approach, you're going to lose some of the niceties of using a bundle directly, such as the automatic appending of that cache-busting query string.
Technically, you can append your own query string. There's nothing special about it, really; it's just a random string that tricks the user's browser into thinking it's a different resource, and thus making it fetch it again. For example:
<script src="/Content/js?foo123></scripts>
However, you're going to be responsible for updating the query string whenever you change any of the scripts in that bundle. Using the actual bundle directly, it's smart enough to know something has changed and append a different query string, but if you're just statically linking, then there's no automated process to do that for you.
Let's assume our app is offline, i.e. we can't use 3rd party CDNs thus we're creating our own.
I'd like to host all of the vendor scripts in a separate (Parent) web app and then include them in the bundles in several other MVC Apps.
e.g.
http://localhost/parentWeb/Scripts/jquery.js
http://localhost/parentWeb/Scripts/jquery-ui.js
http://localhost/parentWeb/Scripts/globalize.js
I'd like to include in the ASP.NET MVC App Website located in: http://localhost/parentWeb/childWeb
i.e. do something like this:
bundles.UseCdn = true;
bundles.Add(
new ScriptBundle(
"~/bundles/VendorScripts",
"http://localhost/parentWeb/Scripts/jquery.js",
"http://localhost/parentWeb/Scripts/jquery-ui.js",
"http://localhost/parentWeb/Scripts/globalize.js"));
...which of course isn't currently possible. Is there a good workaround?
You can't bundle external resources. If you think about it, it makes sense why you can't. It would require the bundler to actually download the resource and save it to the filesystem before it could work with it, and of course do it all asynchronously with some sort of fallback if the external resource couldn't be reached. And, then, it would have to do this on every page load because it can't check for lastmod (and therefore, know whether it actually needs to rebundle or not) without fetching the resource first.
If you use a CDN resource, the bundler merely prints the URL directly to the page; it doesn't make any modifications. Even then, it only lets you create a "bundle" of just that one URL, because 1) it wouldn't make sense to bundle multiple CDN resources since that would defeat the purpose of a CDN and 2) the bundle only exists in this scenario to provide a fallback if the CDN resource is unavailable. Otherwise, you would be served just as well by just hardcoding it to the page and not worrying about setting up a bundle at all.
I know this is an old topic, but I came here looking for an actual way to bundle CDN resources. From #Chris Pratt's answer, I understood it wasn't possible.
If you're wondering, I am working on optimizing an an existing project according to Google's Web Performance Best Practises which gives a low score when there are multiple script tags and a higher one when all scripts are bundled into a single script reference.
I needed a way to bundle all the CDN script resources as well as local resources in order. I worked on this github repo, which solved my problem.
With it, you build a bundle with a list of bundles, each containing a reference to the cdn resource, local resource to save to, and a Boolean indicating whether or not you want the bundle to be minified.
List<Bundle> jsBundles = new List<Bundle>();
jsBundles.Add(new Bundle("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js", #"~/jquery.min.js", Bundle.BundleType.JavaScript, false));
jsBundles.Add(new Bundle("https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js", #"~/jquery-ui.min.js", Bundle.BundleType.JavaScript, false));
jsBundles.Add(new Bundle(#"~/my-local-script.js", Bundle.BundleType.JavaScript, true));
To place on the page, you use
#jsBundles.Load();
This will process all bundles in the list, downloading content for bundles that have not been downloaded in the last 24 hours (It updates every 24 hours or when the web application restarts). All content downloaded will be placed in local files (where specified).
All content will be combined into the final result which will be spooled into the page in a script tag (or link tag for CSS).
The Load function also accepts a local File URL for the final script/css content. If specified, a tag with a src to the relative path for that local file will be given instead. E.g.
#jsBundles.Load("~/js/all-my-scripts.js");
The above statement will return something like:
<script src="~/js/all-my-scripts.js"></script>
An async attribute may be added to the script tag if the second parameter of the Load function is provided.
It also works on css cdn resources too. E.g.
List<Bundle> cssBundles = new List<Bundle>();
cssBundles.Add(new Bundle("https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.css", #"~/jquery.ui.css", Bundle.BundleType.CSS, false));
cssBundles.Add(new Bundle(#"~/css/my-local-style.css", Bundle.BundleType.CSS, true));
#cssBundles.Load("~/css/all-my-styles.css");
This is for the benefit of those, who like me, came in here looking for a way to actually bundle CDN resources.
I have found a solution, which has nothing to do with CDN. Basically, granted the childWeb is hosted in the parentWeb's subdirectory, the following bundle configuration in the childWeb apps picks the file from the parentWeb and bundles them as usual:
bundles.Add(
new ScriptBundle(
"~/bundles/VendorScripts").Include(
"~/../Scripts/jquery.js",
"~/../Scripts/Scripts/jquery-ui.js",
"~/../Scripts/globalize.js"));
the important bit being: ~/../, which takes you one level up from the root location.
To use ScriptBundles with CDN resources, you need to use the overloaded constructor. Unfortunately you need to specify multiple ScriptBundles per file.
Here's a great blog post explaining things:
http://www.hanselman.com/blog/CDNsFailButYourScriptsDontHaveToFallbackFromCDNToLocalJQuery.aspx
And here's a code snippet:
bundles.UseCdn = true;
var bundle = new ScriptBundle("~/bundles/bundleNameHere", "//cdn.host.path/to/file");
// Path to the version of the file on your server (in case the CDN fails)
bundle.Include("~/../Scripts/path/to/file");
// JS expression to run, to test if CDN delivered the file or not
bundle.CdnFallbackExpression = "window.ValueYouExpectToBeTruthy";
bundles.Add(bundle);
The purpose of bundle is reduce the traffic of your web server where your web application hosted. using bundle the script files will not load in parallel. this is needed when you are using your local files.
but in case of cdn the files will load from cdn server so you don't have need to make bundle for cdn. you need bundle for local files only
i'm working on an asp.net app, the following link works in IE but not in FF.
<a href="~/BusinessOrderInfo/page.aspx" >
Isn't the tilde something that can only be used in asp.net server controls. Where it will be replaced by an actual path?
Is it possible to use the tilde in an anchor tag? If so what does it mean?
When I'm at the root, the link works
www.myserver.com/default.aspx, click the link, ok!
www.myserver.com/otherpart/default.aspx, click the link, not ok!
The link generated by ASP.NET is:
www.myserver.com/otherpart/~BusinessOrderInfo/page.aspx
Is this by design?
You are correct, it only works in server controls. You've got these basic options:
Change to HyperLink to run as a Web Control:
<asp:HyperLink NavigateUrl="~/BusinessOrderInfo/page.aspx" Text="Whatever" runat="server" />
Or, run the anchor on the server side as an HTML Control:
<a href="~/BusinessOrderInfo/page.aspx" runat="server" >
Or, use Page.ResolveUrl:
...
HTML controls can be turned into server controls by adding the runat="server" attribute.
<a href="~/BusinessOrderInfo/page.aspx" runat="server">
The tilde refers to the application root directory, and will be translated correctly in control properties such as NavigateUrl.
My understanding is that if you use it in plain-HTML tags, it will not be translated by ASP.Net.
This function can also be used to resolve paths for non server elements
VirtualPathUtility.ToAbsolute($"~/App_Themes/Default/Icons/myimage.gif")
If you remove tilde and use forward slash only you will achieve the same result, i.e. pointing to the root folder on the current domain:
<a href="/BusinessOrderInfo/page.aspx" >
Using Web Paths and Tilde "~" in ASP.NET
~/ is not part of HTML, CSS, or JavaScript path systems.
~/ is an artificial path resolution character only ASP.NET or 3rd party products use.
~/ is a Web Server only path that gets translated to a new path by the code running on the server.
~/ is a character that tells ASP.NET on the IIs Windows
Server to find the "application root" of your website.
~/ resolves as a "Virtual Path" as it tells the server to find virtual or application root of a ASP.NET Web Application controlled by a given AppDomain on the server and resolve it from that new virtual root.
~/ in most cases resolves to the web root of any website right right after the domain, no matter what page or subfolder you are in when the path is called. In almost all cases this resolves to /. So the two are the same in MOST cases unless you set up a Virtual Application on the server.
~/ is really only useful when your website uses one or more Virtual Applications in a web server like IIs. These are artificial sub-applications under your web domain that add a new folder or path under a web root that do not truly exist but represent separate applications and processes managed by the server. This often creates one or more virtual application folders under your domain in IIs which ASP.NET and IIs manage when running separate instances of your ASP.NET website under one domain. See below...
Microsoft .NET is now using ~/ in Routing Attribute paths. When used they start the path back at the web root as an absolute path, but also override all controller or other attribute paths.
VIRTUAL WEB APPLICATIONS
In the old days, we used to create Virtual Applications in IIs Web Server to create two more web paths in order to isolate one or more web 'experiences' using the same domain. Each Virtual Path might be a "ghost" path that points back to the web root but creates an additional ghost folder under the web root. In many cases, that new virtual path pointed to a physical folder separate from the normal web path or even to computer hard drive path or mapping. ASP.NET with the right permission then ran web site code from there. The new virtual path shown to visitors of your web domain would then appear as part of the main site but run a second instance of your web application using a separate process run by ASP.NET (a separate AppPool or worker process).
~/ was then very useful in those cases. It was used in path resolution and easily mapped to the root of these new virtual application roots or paths created by the server, allowing you run multiple application under one website with no change to your paths in your ASP.NET code. The server-side code would then resolve the paths for you inside each virtual application with no changes to the code base.
~/ in those situations was extremely valuable as you no longer needed to manage multiple paths in your web app for each application if it ran in multiple virtual web applications under one website with different web roots. It could always find the new root in each application using ~/ rather than the true web root which was always http://example.com/
EXAMPLES
Most paths in ASP.NET using ~/ resolve to / in a normal website without virtual applications, and point all paths to the web root of the URL below. In most cases that is why ASP.NET ~/ is redundant. Just use /. Both point to the web root:
https://example.com/
However, if you added virtual directories to your domain, as this example below shows, ~/ inside each separate web application would resolve to two different web roots:
https://example.com/virtualapplication1/
https://example.com/virtualapplication2/
In the early days of ASP.NET, I always grabbed the application path using this code below stored in a global variable. This allowed me to fully control all paths from a relative application web root off the domain root or a virtual root no matter where my web application was moved to. But this path is what the ~/ replaced long ago. However, it still might be better as you can build paths from it dynamically on the server:
var myWebRoot = HttpContext.Current.Request.ApplicationPath;
My opinion is virtual applications like this are rarely used today as domains are cheap and subdomains are often used instead, like so:
https://app1.example.com/
https://app2.example.com/
All web paths should use absolute paths in every case possible /. The exception is CSS paths which are relative to the page source page or code calling them internally. Many say that means those absolute web paths break if you move them. But I argue, why would you need to reference the root for your website then suddenly change that? If you do, that should be managed on the server side and injected into your HTML and JavaScript, not the other way around.
Second of all, many Open Source, UNIX-based vendors are creating JavaScript API libraries that stumble around with dot paths which HTML and CSS do not support, like ./ or .
These are UNIX conventions that just mean to point to the local folder or the same folder the calling code is in. It's the same as NO PATH, so why use it? There are cases for their use, but the end result has zero affect on Web Paths. So I would avoid their use. The ONLY place they work in JavaScript reliably is in the new JavaScript Module in ECMAScript. But in proprietary API's like Google Angular, they are required.
For example these two image paths using UNIX local path conventions using ./ or . both fail in HTML and create missing image errors:
// These return broken image icons in browsers when using
// these unconventional UNIX local dot path conventions on the Web:
<img id="image1" src="./images/image1.png" />
<img id="image2" src="/images/.image2.png" />
So avoid all these deviant path system and stick with / absolute HTML paths and your code will always work for decades to come!
EDIT!! I should add that this site runs perfectly locally. It's only when deployed that there's this issue
ORIGINAL POST:
I have a site I just put up http://splattonet0.web704.discountasp.net/
Which loads the Index view of the Home controller just fine. However, when one clicks the links to the left, the webserver is looking for the relative paths (ie E:\web\splattonet0\htdocs\Home\AboutMe) which is incorrect, since Home folder is of course under a folder called "Views"
I've made MVC sites before and have never had this problem. I can't see any difference between this or any other site I've done.
My code in my master template for the link section is as follows:
<div id="navContainer">
<ul id="mainNav">
<li>Home</li>
<li>About Me</li>
<li>Skills</li>
<li>Resume</li>
<li>Experience</li>
<li>My Websites</li>
<li>References</li>
<li>Projects</li>
<li>Hobbies</li>
....etc
</ul>
</div>
I have the same problem with and without the preceeding foreslash in the href property. I've decided to keep it there since that is how my other sites (that work!) are styled.
Can anyone shed some light on this for me? Thanks!
FURTHER EDIT:
I have been asked to provide code from an MVC site on this server I have written and that works fine. The link code in the other site (YorkCentre) is the same style: <li>text</li>
The code:
<li>Archived News</li>
<li>Board Of Directors</li>
<li>In The Media
...
</ul>
/Home/Index should be calling the "Index" action of the "Home" controller, assuming you're using default routes. The fact that "Home" is under the "Views" folder is irrelevant for MVC.
If the code is the same in both locations, and the issue only happens in one, perhaps the answer lies not within the code. The following are some troubleshooting tips which may help, as I don't know exactly what the issue is without more information about the two environments.
What are the web server platforms for your local environment and the server environment? Are you using Visual Studio and Cassini locally, and IIS remotely? If so, which version of IIS? If not, what is the platform? In any event, is the target server configured correctly?
Check to make sure your routes are set up correctly on the target server. This is especially true if your target server runs IIS6 -- IIRC, IIS 6 needs some special configuration help to deal with the standard routing in ASP.NET MVC.
If all of the above don't help you trace this out, try to replicate it locally by creating a new MVC site and merely dropping your existing files into it. See if that succeeds or fails.
Do you have other successfully-executing ASP.NET MVC apps on that server? Check their configurations against your new site's.
I have resolved the problem! In DiscountASP I have changed the Application Pool Pipeline Mode from Classic to Integrated and that results in my views being properly rendered.