ASP.NET MVC 4: Different appearance locally vs deployed to Azure - asp.net-mvc-4

I am using a jQuery datepicker for editing DateTime values in an ASP.NET MVC 4 application.
It works as expected when running locally.
When deployed to Azure, it looks like the .css is missing.
In the image below, the local behavior is on the left, the Azure behavior on the right.
Any ideas on what is going wrong, and how to fix it, would be appreciated....
I have an EditorTemplate for DateTime datatypes:
#model DateTime
#Html.TextBox("", Model.ToString("MM/dd/yyyy"), new { #class = "date" })
The javascript to hook up the datepicker:
/// <reference path="jquery-1.10.2.js" />
/// <reference path="jquery-ui.js" />
$(document).ready(function () {
function getDateYymmdd(value) {
if (value == null)
return null;
return $.datepicker.parseDate("yy/mm/dd", value);
}
$('.date').each(function () {
var minDate = getDateYymmdd($(this).data("val-rangedate-min"));
var maxDate = getDateYymmdd($(this).data("val-rangedate-max"));
$(this).datepicker({
dateFormat: "mm/dd/yy",
minDate: minDate,
maxDate: maxDate
});
});
});
And in the Edit.cshtml:
#section Scripts {
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/jqueryui")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/EditorHookup.js")
}
UPDATE:
I:\work\App
--- Content
------ themes
--------- base
------------ images
------------ minified
The jquery*.css files are in App\Content\themes\base.
When I copy them to App\Content, the datepicker works.
The bundling code:
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/themes/base/jquery.ui.all.css",
"~/Content/bootstrap.css",
"~/Content/site.css"));

You are missing a CSS for jqueryUI, please make sure the path to CSS is correct and if its part of Bundle which it looks like it is, make sure that u're referencing correct version in the bundle

I don't know how did you define the bundles, but if you have two definitions, say:
bundles.Add(new StyleBundle("~/Styles/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
"~/Content/themes/base/jquery.ui.all.css",
"~/Content/themes/base/jquery.ui.core.css",
"~/Content/themes/base/jquery.ui.theme.css",
"~/Content/themes/base/jquery.ui.datepicker.css"));
Then in the layout you have to render both of them, and try moving the code to the top in _Layout
<title>#ViewBag.Title - My ASP.NET Application</title>
#Styles.Render("~/Styles/css", "~/Content/themes/base/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
This code runs fine and you'll see the datepicker properly, take a look in the bundle code if you're missing any reference. I'm using the same folder structure
Regards

Related

How to add different CSS files to different layouts in blazor?

Hi every blazor lover!
I have 2 different layouts and, I want to load different CSS file on each layout.
The first one is MainLayout.razor and the other is AdminLayout.razor.
I want to load my admin menu CSS file in the AdminLayout, without using "css isolation", because the CSS files for this layout maybe more files in future.
ASP.NET Core 3.1 or .NET 5.0
Thanks in advance.
You can use the HTML <link> tag anywhere in the <head> or <body> to include CSS, so drop the appropriate <link rel="stylesheet" href="..." /> into MainLayout.razor and AdminLayout.razor, respectively.
Eventually, adding content to the <head> directly from a razor component may be supported, as tracked here.
Solution for .Net 3.1 or .Net 5.0
use this java script to add css file to page or layout directly:
function loadCss(cssPath) {
var ss = document.styleSheets;
for (var i = 0, max = ss.length; i < max; i++) {
if (ss[i].href.includes(cssPath.substr(2)))
return;
}
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = cssPath;
document.getElementsByTagName("head")[0].appendChild(link);
}
I create a js function "loadCss", you have to call this function on OnAfterRenderAsync event:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JsRuntime.InvokeVoidAsync("loadCss", "css/FILENAME.min.css");
}

Howto debug JavaScript inside ASP .Net Core 3.1 MVC applications (Razor view - *.cshtml)?

I have latest Visual Studio 2019 16.5.4 Enterprise.
I've just created an ASP .Net Core 3.1 MVC application from a template (with default settings).
And I've added some JavaScript code to a Home Page's Index.cshtml:
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
</div>
#section Scripts {
<script>
function GetJSON_Simple() {
var resp = [];
return resp;
}
debugger;
var simpleData = GetJSON_Simple();
</script>
}
And I'm not able to debug JavaScript code (breakpoints inside GetJSON_Simple function body or on var simpleData = GetJSON_Simple() is never hit). I've tried both Chrome and MS Edge (Chromium).
According to this article (Debug JavaScript in dynamic files using Razor (ASP.NET) section):
Place the debugger; statement where you want to break: This causes the
dynamic script to stop execution and start debugging immediately while
it is being created.
P.S. I've already have Tools->Options->Debugging->General with turned on Enable JavaScript Debugging for ASP.NET (Chrome and IE) checkbox and of course I'm compiling in Debug.
My test project is attached
Howto debug JavaScript inside ASP .Net Core 3.1 MVC applications
(Razor view - *.cshtml)?
In fact, it is already a well-known issue. We can not debug the js code under Net Core razor page but only for code in separate js or ts files. See this link.
Solution
To solve it, I suggest you could create a new single js file called test.js and then reference it in razor page and then you can hit into js code when you debug it.
1) create a file called test.js and migrate your js code into it:
function GetJSON_Simple() {
var resp = [];
return resp;
}
debugger;
var simpleData = GetJSON_Simple();
2) change to use this in your cshtml file:
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
</div>
#section Scripts {
<script scr="xxx/test.js">
</script>
}
3) clean your project, then rebuild your project and debug it and you will hit into Js code.
Another way is to explicitly define the source mapping name for the script directly in your javascript code via a sourceURL comment.
<script>
...your script code
//# sourceURL=blah
</script>
The script in that block will show up in Chrome with the value you specified. You can then view and debug just like a normal .js file.
This is especially useful if you don't want to refactor an existing codebase that has embedded javascript in the cshtml files or really ANY codebase that has javascript loaded on the fly.
Live Example
You can actually see an example with the built-in javascript runner here. Just click 'Run Snippet' and then search for "blahblah" in your Page sources. You should see this:
alert("test");
//# sourceURL=blahblah

MVC 4 Bundling causes missing image in Kendo UI

I have created a new MVC 4 application and am trying to migrate an existing MVC 3 application over. Everything works fine until I try to use the new Bundling feature and when I bundle Kendo css files the arrow on dropdowns and numeric textboxes disappear. They function ok, just missing the images. The files seem to bundle just fine. I have researched extensively and have tried renaming the files to remove the "min" and still have the same issue.
Here are the files I am trying to bundle:
<link href="#Url.Content("~/Content/kendo/kendo.common.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/kendo.default.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/kendo.blueopal.min.css")" rel="stylesheet" type="text/css" />
When I bundle them like so the issues appear :
bundles.Add(new StyleBundle("~/Content/cssBundle").Include(
"~/Content/kendo/kendo.common.min.css",
"~/Content/kendo/kendo.default.min.css",
"~/Content/kendo/kendo.blueopal.min.css"
));
I faced the same problem.
CssRewriteUrlTransform should do the trick:
.Include("~/Content/kendo/2014.1.318/kendo.common.min.css", new CssRewriteUrlTransform())
First off, there is no need to minify files that have already been minified. The StyleBundle class will try to minify the Kendo .min files again, which is unnecessary. Use the Bundle class instead.
Secondly, the .Include() method takes a second parameter of params IItemTransform[] transforms. You can pass new CssRewriteUrlTransform() as that parameter, so your CSS will have the right paths.
Example:
bundles.Add(new Bundle("~/Content/cssBundle")
.Include("~/Content/kendo/kendo.common.min.css", new CssRewriteUrlTransform()),
.Include("~/Content/kendo/kendo.default.min.css", new CssRewriteUrlTransform()),
.Include("~/Content/kendo/kendo.blueopal.min.css", new CssRewriteUrlTransform())
);
I know it's a pain, but I usually just modify the .css files and do a find/replace to get the correct paths.
Otherwise, you can set the bundle to be the same directory that Kendo is in, like this:
bundles.Add(new StyleBundle("~/Content/kendo").Include(
"~/Content/kendo/kendo.common.min.css",
"~/Content/kendo/kendo.default.min.css",
"~/Content/kendo/kendo.blueopal.min.css"
));
I was able to correct this problem by configuring routes in my application for the problem locations.
// Route for bundles problem.
routes.MapRoute("ResourcesFix", "bundles/{folder}/{path}",
new { controller = "Redirect", action = "Index" });
// Redirect for requests.
public class RedirectController : Controller
{
public ActionResult Index(String folder, String path)
{
return Redirect("~/Content/kendo/" +
WebConfigurationManager.AppSettings["KendoVersion"] + "/" + folder + "/" + path);
}
}
Add the following class extension,
public static class BundleConfigExt
{
public static Bundle CustomCssInclude(this Bundle bundle, params string[] virtualPaths)
{
foreach (var virtualPath in virtualPaths)
{
if (virtualPath.IndexOf("~/Content/kendo/") > -1) //OR
//// if (virtualPath.IndexOf("~/Content/kendo/") > -1 || virtualPath.IndexOf("~/Content/ExternalCss/") > -1)
{
bundle.Include(virtualPath, new CssRewriteUrlTransform());
}
else
{
bundle.Include(virtualPath);
}
}
return bundle;
}
}
Call .CustomCssInclude() extension method instead of .Include(),
bundles.Add(new StyleBundle("~/Bundles/AllArabicCss").CustomCssInclude(
"~/Content/bootstrap.min.css",
"~/Content/kendo/kendo.common.*",
"~/Content/kendo/kendo.default.min.css",
//...
"~/Content/kendo/kendo.bootstrap.min.css",
"~/Content/ExternalCss/custom.css",
"~/Content/ExternalCss/tab-responsive.css",
"~/Content/ExternalCss/mobile-responsive.css"));

jQuery not defined + MVC4

Im creating the below MVC view that has got some jquery script in it.
However this script is not getting executed. Getting jQuery undefined error.
I want to write including script directly in view instead of using layout page.
Can somebody advise what am I doing wrong here?
#{
ViewBag.Title = "FileUpload";
}
<html lang="en">
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title - What up boyeez!</title>
<meta name="viewport" content="width=device-width" />
<script src="~/Scripts/jquery-ui-1.10.0.min.js"></script>
<h2>FileUpload</h2>
#using (Html.BeginForm("UploadFile", "FileUpload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary();
<ol>
<li class="lifile">
<input type="file" id="fileToUpload" name="file" />
<span class="field-validation-error" id="spanfile"></span>
</li>
</ol>
<input type="submit" id="btnSubmit" value="Upload" />
}
</body>
</html>
<script type="text/jscript">
(function ($) {
function GetFileSize(fileid) {
try {
var fileSize = 0;
if ($.browser.msie) {
var objFSO = new ActiveXObject("Scripting.FileSystemObject");
var filePath = $("#" + fileid)[0].value;
var objFile = objFSO.getFile(filePath);
var fileSize = objFile.size;
fileSize = fileSize / 1048576;
}
else {
fileSize = $("#", fileid)[0].files[0].size
fileSize = file / 1048576;
}
return fileSize;
}
catch (e) {
alter("Error is: " + e);
}
}
function getNameFromPath(strFilepath) {
debugger;
var objRE = new RegExp(/([^\/\\]+)$/);
var strName = objRE.exec(strFilepath);
if (strName == null) {
return null;
}
else {
return strName[0];
}
}
$("#btnSubmit").live("click", function () {
debugger;
if ($('#fileToUpload').val == "") {
$("#spanfile").html("Please upload file");
return false;
}
else {
return checkfile();
}
});
function checkfile() {
var file = getNameFromPath($("#fileToUpload").val());
if (file != null) {
var extension = file.subst((file.last('.') + 1));
switch (extension) {
case 'jpg':
case 'png':
case 'gif':
case 'pdf':
flag = true;
break;
default:
flag = false;
}
}
if (flag == false) {
$("#spanfile").text("You can upload only jpg, png, gif, pdf extension file");
return false;
}
else {
var size = GetFileSize('fileToUpload');
if (size > 3) {
$("#spanfile").text("You can upload file up to 3 MB");
return false;
}
else {
$("#spanfile").text("");
}
}
}
$(function () {
debugger;
$("#fileToUpload").change(function () {
checkfile();
});
});
})(jQuery);
You are missing a reference to jquery itself. You probably also want a css file for jquery ui:
<link rel="stylesheet" href="css/themename/jquery-ui.custom.css" />
<script src="js/jquery.min.js"></script>
<script src="js/jquery-ui.custom.min.js"></script>
See the "Basic Overview: Using jQuery UI on a Web Page" section on the jquery-ui learning docs for full details of how to use and customise jquery ui.
Razor techniques for jquery files
To make your life easier in your view template, you could use the scripts render function:
#Scripts.Render("~/Scripts/jquery-1.9.1.min.js")
#Scripts.Render("~/Scripts/jquery-ui-1.10.0.min.js")
In itself, not too impressive: the syntax is slightly more expressive and 5 characters shorter, that's all.
But it leads you into bundles (references at the end), which are really what you should be using.
Bundles are awesome
Bundles allow you to:
Group dependent files: grouping js and/or css files together reduces the chances of this happening, and also means you can "modularise" your own scripts into multiple files in one folder.
Increase performance: Send out everything inside a single Bundle in a single file - speeding up load times for clients by reducing the number of http requests from the browser
Help development: Use non-minified javascripts (and css) for debugging during development
Publish without changes to code: Use the minified scripts for live deployment
Use in-built minifying for your own scripts
Optimise client experience: Use CDNs for standard scripts like jquery (which is better for your users)
Upgrade easily: Not have to change code when you update your version numbers for things like jquery through NuGet by use of the {version} wildcard (as below)
Example:
// This is usually in your MVC 4 App_Start folder at App_Start\BundleConfig
public class BundleConfig {
public static void RegisterBundles(BundleCollection bundles) {
// Example with full use of CDNs in release builds
var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery", jqueryCdnPath).Include("~/Scripts/jquery-{version}.js"));
And in your razor file you only need a tiny change:
#Scripts.Render("~/bundles/jquery");
This will:
send out the full jquery script during debugging
send out the minified script for a release build
even minify your own bundles such as #Scripts.Render("~/bundles/myScripts"); for live builds
Bundle details
Under the hood bundles will use the CDNs, or minify your own scripts as well, or send already minified files (like jquery-1.9.1.min.js) during release builds, but you can control this by using bundles.UseCdn and BundleTable.EnableOptimizations inside your RegisterBundles method. By using this along with AppSettings in your web.config you can have very close control so that you could even send out debugging scripts for certain users on a live site.
Also note the use of {version} in the bundle configuration.
You can include multiple scripts in a bundle as well:
bundles.Add(new ScriptBundle("~/bundles/jqueryWithUi")
.Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery-ui-{version}.js"
));
This razor command will now send out both files for you:
#Scripts.Render("~/bundles/jquery");
And you can use bundles for css:
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
"~/Content/themes/base/jquery.ui.core.css",
"~/Content/themes/base/jquery.ui.resizable.css",
"~/Content/themes/base/jquery.ui.selectable.css",
"~/Content/themes/base/jquery.ui.accordion.css",
"~/Content/themes/base/jquery.ui.autocomplete.css",
"~/Content/themes/base/jquery.ui.button.css",
"~/Content/themes/base/jquery.ui.dialog.css",
"~/Content/themes/base/jquery.ui.slider.css",
"~/Content/themes/base/jquery.ui.tabs.css",
"~/Content/themes/base/jquery.ui.datepicker.css",
"~/Content/themes/base/jquery.ui.progressbar.css",
"~/Content/themes/base/jquery.ui.theme.css"));
References:
www.asp.net - Bundling and Minification
You're loading the jQuery UI library without loading the jQuery library.
<script src="~/Scripts/path/to/jquery"></script
<script src="~/Scripts/jquery-ui-1.10.0.min.js"></script
I was having the same problem of client side validation not working. I brought up the JavaScript console in Chrome and saw I was receiving an error stating "JQuery was not defined.".
Turns out I had some code in my View that was causing problems with jQuery not loading.
Recommendation to others who come across this, check your JS console in your browser to ensure you are not getting a JQuery error.

ASP.NET MVC 4 - Add Bundle from Controller?

I have some pages on my site that use certain CSS and JS resources - but they are the only page(s) to use that css or js file - so I don't want to include that CSS and JS reference in every page. Rather than modify each View to reference the CSS/JS it needs, I thought I could create a bundle in the Controller and add it to the Bundles that are already registered, and then it would be included in the bundle references, but this does not appear to be possible, or maybe I'm just going about it the wrong way.
In my Controller for a registration page for example, I thought I could write this:
Bundle styleBundle = new Bundle("~/bundles/registrationStyleBundle");
styleBundle.Include("~/Content/Themes/Default/registration.css");
BundleTable.Bundles.Add(styleBundle);
And then have this in my /Views/Shared/_Layout.cshtml:
#foreach(Bundle b in BundleTable.Bundles)
{
if (b is StyleBundle)
{
<link href="#BundleTable.Bundles.ResolveBundleUrl(b.Path)" rel="stylesheet" type="text/css" />
}
else if (b is ScriptBundle)
{
<script src="#BundleTable.Bundles.ResolveBundleUrl(b.Path)" type="text/javascript"></script>
}
}
But this does not work - the only bundles to get rendered to my page end up being the ones I specified in RegisterBundles (in /App_Start/BundleConfig.cs)
Any idea how to achieve this kind of "dynamic" or "runtime" bundling?
EDIT: Following Jasen's advice, what I ended up doing was taking the bundle creation/registration code out of the controller and adding it to RegisterBundles() in /App_Start/BundleConfig.cs. This way, the bundle is already available and the contents get minified. So:
bundles.Add(
new StyleBundle("~/bundles/registrationStyleBundle")
.Include("~/Content/Themes/default/registration.css"));
Then, in my view, I added this:
#section viewStyles{
<link href="#BundleTable.Bundles.ResolveBundleUrl("~/bundles/registrationStyleBundle")." rel="stylesheet" type="text/css" />
}
Then, in /Views/Shared/_Layout.cshtml, I added this:
#RenderSection("viewStyles", required: false)
Use the #section Scripts { } block to conditionally add bundles.
_Layout.cshtml
<body>
...
#RenderSection("Scripts", required: false)
</body>
FooView.cshtml
#section Scripts {
#Scripts.Render("~/bundles/foo")
}
KungFooView.cshtml
#section Scripts {
#Scripts.Render("~/bundles/kungfoo")
}
In my BundleConfig I typically group resources
bundles.Add(new ScriptBundle("~/bundles/Areas/Admin/js").Include(...);
bundles.Add(new StyleBundle("~/bundles/Areas/Admin/css").Include(...);
bundles.Add(new ScriptBundle("~/bundles/Areas/Home/js").Include(...);
bundles.Add(new StyleBundle("~/bundles/Areas/Home/css").Include(...);
Now I can either define multiple layout files or just selectively add bundles to the views.