Reading a AppKey value from web.config in clientside js SPA - javascript

I have Durandal SPA which uses url.config.js file among different views. Bunch of urls to services are stored there.
Code for clarity:
define([], function () {
var serviceBaseUrl = 'http://localhost/Service/api/';
var portalPortalUrl = 'http://localhost/Portal';
});
And whenever I need to deploy my app, or run it with different IIS settings, I need to manually change this urls in code.
What I want:
To store them in Web.config file so I can have different configuration for debug and release modes.
I am using MVC 5 Razor views only for rendering bundles and initial content, all client side logic placed in Durandal folder.
I have only found solutions using ASP.NET ConfigurationManager like so:
function ReadConfigurationSettings()
{
var k = '<%=ConfigurationManager.AppSettings["var1"].ToString() %>'
alert(k);
}
Or, for Razor:
#System.Configuration.ConfigurationManager.AppSettings["myKey"]
It's cool, but not my way.
Maybe it's possible to auto generate my urls.config.js file based on Web.config keys?
Thank you in advance.
If needed, here is my project structure:
- App //Durandal SPA
- Controllers
- Views //Only render initial view
- Web.config

You can use JavaScriptResult
Sends JavaScript content to the response.
Code, Controller Action method
public JavaScriptResult Config()
{
var script = string.Format(#"var configServiceBaseUrl = {0};", ConfigurationManager.AppSettings["var1"]);
return JavaScript(script);
}
In the page header(I would load the file first), You can define:
<script type="text/javascript" src='#Url.Action("Config", "Controller")'></script>
Now configServiceBaseUrl is Global JavaScript variable which you can use anywhere.
So you can use configServiceBaseUrl in url.config.js like
define([], function () {
var serviceBaseUrl = configServiceBaseUrl;
});

Adding to satpal, for SPA application such as angular js
For SPA's, such as angular you can use below code in your index.html as
<script type="text/javascript" src='/Controller/config'></script>

Related

Durandel + Jquery

I worked with two jquery libraries in MVC 4 project which worked fine.
Now i building the same web site using MVC 5 + web api + durandel and knockout.
But i dont know how to insert those libraries:
http://www.3quarks.com/en/SegmentDisplay/
http://brandonlwhite.github.io/sevenSeg.js/
I want to insert them in a table ( foreach)
the JS is in require as define module
and not in the HTML file,
i dont know how to start and need help please.
As per the documentation, include the following libraries :
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<script src="sevenSeg.js"></script>
Either directly in your index.html file, or via the RegisterBundles method in file in your App_Start folder :
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(
new ScriptBundle("~/Scripts/vendor")
.Include("~/Scripts/jquery-2.0.2.js")
.Include("~/Scripts/jquery-ui-1.10.3.js")
.Include("~/Scripts/knockout-3.3.0.debug.js")
.Include("~/Scripts/sevenSeg.js")
);
}
Then include it in your index file :
#Scripts.Render("~/Scripts/vendor")
Then you should be able to use the SevenSeg data binding like this :
<div data-bind="sevenSeg: {digits: 5, value: testValue1}"></div>
If the data binding does not work, you would have to create a custom binding handler in an external file (eg /Scripts/sevenSegCustom.js and load your custom binding in your main.js file like this :
define(['sevenSegCustom'], function(sevenSegCustom) {
composition.addBindingHandler('myCustomSSBinding', sevenSegCustom.sevenSegCustom)
}
Then use it like this :
<div data-bind="myCustomSSBinding: {digits: 5, value: testValue1}"></div>
Hope it helps !

How to load AngularJS controller file on content loaded

I'm new to Angular.JS and i'm trying to load a controller file dinamically when a content loaded from ng-include is requesting it, i do this way because the page i'm building will have multiple controllers and i rather make the initial page to load fast due to it's size, i am not sure to do this and i thought i would achieve it by just doing:
<script type="text/javascript" src="js/controllers/controllerFile.js"></script>
inside the content loaded.
the controller File is like this
app.controller('parseQuery', function()
{
this.object = 'Enter query and parse.';
this.parse = function()
{
this.object = JSON.stringify(window.getParam(this.query), null, '\t');
};
this.getURL = function()
{
this.query = document.URL;
this.parse();
};
});
the html file calls the controller with ng-controller as it should work. But when the content is loaded, javascript returns an error Argument 'parseQuery' is not a, so nothing works, how can i achieve to load a controller file after application is already bootstraped?
To lazy load your scripts, you'll want to check out an AMD or CommonJS loader. These libraries provide the ability to load scripts on demand.
Dan Wahlin has an excellent blog post detailing how to use RequireJS with angular.
In the 1.3.14 AngularJS recieved support for CommonJS. That will be your best bet.

Url Helper ASP.NET MVC in Javascript

I'm writing a js script that read a file JSON that contains all navigation menĂ¹ links of my web application.
the menu tree is something like this:
1 - DASHBOARD - dashboard
2 - SETTINGS
2.1 - GENERAL - settings/general
2.2 - LAYOUT - settings/layout
3 - DATABASE
3.1 - QUERY
3.1.2 - EDITOR - database/query/editor
3.1.3 - TEST - database/query/test
the menĂ¹ is 3 levels nested link.
How can I write links in JSON file to avoid "not found" when e.g. in "DASHBOARD" and want to go to SETTINGS > GENERAL.
I don't want to use absolute path, my webapp will run in a virtual directory.
If you can, I wolud suggest modifying your JSON response to include the base path your app is hosted on.
string basePath = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
For example: basePath + "database/query/editor" instead of database/query/editor.
If you cannot modify the JSON response, you can get the base path your application is hosted on in a JavaScript variable from your MVC.
In your _Layout.cshtml file -- or whatever file that gets loaded every time your application is loaded -- set your base path that your application is running under in a JS variable:
<script type="text/javascript">
window.applicationBaseUrl = #Html.Raw(HttpUtility.JavaScriptStringEncode(Url.Content("~/"), true));
</script>
Now when you receive the JSON containing the URLs, concatenate them with your base path:
var queryEditorUrl = window.applicationBaseUrl + <the path from your JSON>
This way your URLs are independent of the virtual directory it is hosted on.
You should use Url.Content("~/") (see documentation) to get the absolute URL of your application. For example if you run your application in a virtual directory called MyApp and you have a page in About/Me you can use:
string url = Url.Content("~/About/Me"); // this will return '/MyApp/About/Me'

Asp.net MVC 2 Production errors

I have an MVC 2 application hosting on an IIS6 server. I have already done all the routing tweaks so that it can browse in the environment. The problem is however, that I have a dynamic partial view creation aspect, where a partial view is loaded each time an add button is clicked. Using Javascript and a controller, I call the partial vie and add it to a table each time.
Javascript Code
<script type="text/javascript">
$(function() {
$("#btnAdd").click(function (e) {
var itemIndex = $("#container input.iHidden").length;
console.debug("itemIndex : "+itemIndex);
e.preventDefault();
var URL = "/WorkOrder/NewItem/" +itemIndex;
$.get(URL,function(data){
$("#container").append(data);
});
});
});
and the controller is
public ActionResult NewItem(int id)
{
var interest = new ItemModel { index = id };
return View("_NewItem", interest);
}
Quite simple really. The funny thing is that it works when in the test localhost environment, but as soon as i deploy it to production, the btnAdd function does nothing. After using the inspect element Network debugging tool, I discovered that the network is returning a 404 error for the partial view.
Do i have to tweak the routing tables more to make them recognize the routing regime i am trying to implement?
Try using Url.Action method instead of just hard coding the URI and pass the data using data parameter.
Example:
var URL = '<%= Url.Action("WorkOrder", "NewItem")%>';
$.get( URL,
{id: itemIndex}
function(data){
$("#container").append(data);
});

How do I use ASP.NET bundling and minification without recompiling?

Constraints: I'm not using MVC, just regular ol' .aspx files in my web app. Not using master pages either - each page is a different beast, so that solution isn't right for me.
Most examples I've read for bundling and minification require either some special MVC markup or require you to identify the bundled scripts / stylesheets up front and then refer to these bundles. I want to avoid recompiling DLLs every time I add or modify a .js reference in a .aspx page.
I'm a bit stumped from reading the Msft docs.. is there a way (like an ASP.NET control) that I can just wrap a series of script tags (or link tags for CSS) to create and use a bundle dynamically? I don't want to reinvent the wheel, but seriously considering creating my own user control / custom control that handles this. Are there other options?
For example, looking for something like this:
<asp:AdHocScriptBundle id="mypage_bundle" runat="server">
<script type="text/javascript" src="~/scripts/mypage1.js"></script>
<script type="text/javascript" src="~/scripts/mypage2.js"></script>
<script type="text/javascript" src="~/scripts/mypage3.js"></script>
</asp:AdHocScriptBundle>
that, when bundling is enabled, automatically replaces the contents of asp:AdHocScriptBundle with a single script tag that resembles this:
<script type="text/javascript" src="/webappname/bundles/mypage_bundle.js?v=dh120398dh1298dh192d8hd32d"></script>
And when Bundling is disabled, outputs the contents normally like this:
<script type="text/javascript" src="/webappname/scripts/mypage1.js"></script>
<script type="text/javascript" src="/webappname/scripts/mypage2.js"></script>
<script type="text/javascript" src="/webappname/scripts/mypage3.js"></script>
Any thoughts?
About to roll my own anyway, but if there is already a solution for this please share, thanks!
I rolled my own solution and it works great! I created 4 classes that I can use as custom server controls:
ScriptBundle
Script
StyleBundle
Link
These call functions around my custom bundling library which is itself a wrapper for the System.Web.Optimization API.
During Render of ScriptBundle and StyleBundle I then check an internal setting (the same one that I use to set EnableOptimizations in the System.Web.Optimization API) that tells the page to either use bundling, or simply write out the normal script / link tags. If Bundling is enabled it calls this function from my custom bundling library (for Scripts, similar code for Styles tho. Bundler in code below is the class for my custom bundling library - just in case Microsoft changes the System.Web.Optimization API I wanted a layer in-between so that I wouldn't have to change my code as much):
public static void AddScriptBundle(string virtualTargetPath, params string[] virtualSourcePaths)
{
var scriptBundle = new System.Web.Optimization.ScriptBundle(virtualTargetPath);
scriptBundle.Include(virtualSourcePaths);
System.Web.Optimization.BundleTable.Bundles.Add(scriptBundle);
}
To make sure that I only create the Bundle if it does not already exist, I first check for the Bundle using this method (before using the above method):
public static bool BundleExists(string virtualTargetPath)
{
return System.Web.Optimization.BundleTable.Bundles.GetBundleFor(virtualTargetPath) != null;
}
Then I use this function to spit out the URL to the bundle by using System.Web.Optimization:
public static System.Web.IHtmlString GetScriptBundleHTML(string virtualTargetPath)
{
return System.Web.Optimization.Scripts.Render(virtualTargetPath);
}
Within my .aspx files, I do this:
<%# Register TagPrefix="cc1" Namespace="AdHocBundler" Assembly="AdHocBundler" %>
...
<cc1:ScriptBundle name="MyBundle" runat="Server">
<cc1:script src='~/js/script1.js'/>
<cc1:script src='~/js/utils/script2.js'/>
</cc1:ScriptBundle>
The trick for me was figuring out that I had to convert script and link tags to be work as list items within the ScriptBundle and StyleBundle controls, but after that it works great AND it let me use the tilde operator for easy references relative to app root (using Page.ResolveClientUrl(), which is helpful for creating module content).
Thanks go to this SO answer for helping me figure out how to create a custom collection control: How do you build an ASP.NET custom control with a collection property?
UPDATE: In the interest of full disclosure, I got permission to share the code for ScriptBundle (StyleBundle is almost identical, so did not include it):
[DefaultProperty("Name")]
[ParseChildren(true, DefaultProperty = "Scripts")]
public class ScriptBundle : Control
{
public ScriptBundle()
{
this.Enabled = true;
this.Scripts = new List<Script>();
}
[PersistenceMode(PersistenceMode.Attribute)]
public String Name { get; set; }
[PersistenceMode(PersistenceMode.Attribute)]
[DefaultValue(true)]
public Boolean Enabled { get; set; }
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public List<Script> Scripts { get; set; }
protected override void Render(HtmlTextWriter writer)
{
if (String.IsNullOrEmpty(this.Name))
{
// Name is used to generate the bundle; tell dev if he forgot it
throw new Exception("ScriptBundle Name is not defined.");
}
writer.BeginRender();
if (this.Enabled && Bundler.EnableOptimizations)
{
if (this.Scripts.Count > 0)
{
string bundleName = String.Format("~/bundles{0}/{1}.js",
HttpContext.Current.Request.FilePath,
this.Name).ToLower();
// create a bundle if not exists
if (!Bundler.BundleExists(bundleName))
{
string[] scriptPaths = new string[this.Scripts.Count];
int len = scriptPaths.Length;
for (int i = 0; i < len; i++)
{
if (!string.IsNullOrEmpty(this.Scripts[i].Src))
{
// no need for resolve client URL here - bundler already does it for us, so paths like "~/scripts" will already be expanded
scriptPaths[i] = this.Scripts[i].Src;
}
}
Bundler.AddScriptBundle(bundleName, scriptPaths);
}
// spit out a reference to bundle
writer.Write(Bundler.GetScriptBundleHTML(bundleName));
}
}
else
{
// do not use bundling. generate normal script tags for each Script
foreach (Script s in this.Scripts)
{
if (!string.IsNullOrEmpty(s.Src))
{
// render <script type='<type>' src='<src'>/> ... and resolve URL to expand tilde, which lets us use paths relative to app root
// calling writer.Write() directly since it has less overhead than using RenderBeginTag(), etc., assumption is no special/weird chars in the cc1:script attrs
writer.Write(String.Format(Script.TAG_FORMAT_DEFAULT,
s.Type,
Page.ResolveClientUrl(s.Src)));
}
}
}
writer.EndRender();
}
}
public class Script
{
public const String ATTR_TYPE_DEFAULT = "text/javascript";
public const String TAG_FORMAT_DEFAULT = "<script type=\"{0}\" src=\"{1}\"></script>";
public Script()
{
this.Type = ATTR_TYPE_DEFAULT;
this.Src = null;
}
public String Type { get; set; }
public String Src { get; set; }
public String Language { get; set; }
}
This isn't possible with the default Bundling/Minification in ASP.NET. The entire point of bundling is to create one single to file to reduce the number of browser requests to load static files such as .JS and .CSS files.
Rolling your own is your only option. However, please note that each <script> line will result in a browser request. Since most browsers can only handle 6 requests concurrently, you can have wait times just to load these static files.
And FYI, you don't have to recompile DLLs every time you update your .JS files with built-in bundling. You can simply reset the application pool the app is running on. If you're running with an external session persistence model, your users won't notice when this happens.
Your problem here is that you aren't really thinking this problem through. If you were, you would realize that what you are asking for can't work.
Why? Because the script tag ahs to generate an external link reference to a different url. So anything you place in the header of the current file will have no affect on your other URL that actually contains your bundles. As such, there is no way to dynamically change your bundles in the page itself because bundles have to, by definition, be defined in an external resource.
Now, there's nothing that says those bundles have to be compiled into DLL's in your own solution, but they cannot be embedded in the page that's currently being rendered.
You might want to investigate some of the javascript based minification tools out there, since they are typically not compiled.

Categories