Mvc4 bundling, minification and AngularJS services - asp.net-mvc

Is there a way to customize the way Asp.Net MVC4 bundling&minification feature minifies the js files?
Meaning, I don't want to completely turn off minification, but "as is" it just breaks AngularJs.
Since AngularJs uses DI and IoC approach for injecting services in controllers, the following:
function MyController($scope) { }
Once minified, becomes:
function MyController(n) { }
Normally that wouldn't be a problem, but AngularJs uses the parameter names to understand which service to inject. So $scope should remain $scope, as well as any other parameter in angular controllers. Everything else, like local variables, etc, should be minified normally.
I can't find any clear documentation on how to configure Mvc4 minification, and it seems rather dumb for it to be "all or nothing" so I think I'm missing something.
Thanks.

Actually you can (and should!) write AngularJS code so it is "minification safe". Details are described in the "Dependency Annotation" section of http://docs.angularjs.org/guide/di but in short, for globally defined controllers you can write:
MyController.$inject = ['$scope'];
Please note that globally defined controllers are polluting global namespace (see this for more details) and should be avoided. If you declare a controller on a module level you can make it minification-safe as well:
angular.module('mymodule', []).controller('MyController', ['$scope', function($scope){
//controller code goes here
}]);

if you still want to control what to minify and what not (or if you want to include an already minified version by the plugin vendor) just declare two bundles, and only minify one of them on your BundleConfig.cs:
var dontMinify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxx.js");
bundles.Add(dontMinify);
var minify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/yyyyyy.js");
minify.Transforms.Add(new JsMinify());
bundles.Add(minify);

For those of you who don't want/can't be arsed to write the "minification-safe" angular-DI syntax, and don't care about variable names being obfuscated, I used BundleTransfomer along with Yui Js minifier - available via nuget:
Install-Package BundleTransformer.Core
Install-Package BundleTransformer.Yui
Gives VERY fine-grained control over minification/obfuscation. In the angular world, just set the obfuscateJavascript within the yui web.config section to false.

Related

Defining module names with Typescript

I'm trying to use TypeScript with RequireJS but I'm getting the following error:
Mismatched anonymous define() module.
I understand this is because Typescript is not emitting a module name and I'm loading the scripts into the page myself (I'm doing this as they are defined as a pre-defined bundle in the MVC project).
Currently the outputted .js looks like this:
define(["require", "exports", "jquery"], function(require, exports, $) {...
When I need it to emit:
define("MODULE_NAME" ["require", "exports", "jquery"], function(require, exports, $) {...
Is this possible with Typescript or should I look at replacing the bundle for minimization with Require.js's own optimization?
If you are using ASP.NET and the integrated script bundling, you are correct: The problem is that the bundle contains multiple anonymous modules. While it is good, common practice to work with anonymous modules (and let some compressor/optimizer do the naming later), this won't work for ASP.NET bundling because it only concatenates the input JS files. The solution is to make TypeScript create named modules. And this is possible with TS, so the answer to your question
Is this possible with Typescript
is definitely: Yes!
TypeScript 1.4 added the ability to emit AMD named modules to the compiler, like this:
///<amd-module name='NamedModule'/>
export class C {
}
The issue is not in the code generation (which is correct). The issue is that you probably have a script tag loading this JavaScript file. It should only be loaded by RequireJS, using data-main or as a dependency of another module.
See : http://requirejs.org/docs/errors.html#mismatch
Remove the script tag

Using ASP.NET Javascript Bundles from the controller

I realise this breaks the MVC pattern, but there is a viable reason for doing it this way in an application I am currently building :)
What I am trying to do is output a JavaScript bundle directly from the Controller rather than via a link via a View.
So for example I have a bundle called "~/jQueryPlugin" what I'd like to do is something along the lines of
return this.JavaScript(BundleTable.GetBundle("~jQueryPlugin").BundleContent)"
However for the life of me I cannot figure out what the BundleTable.GetBundle("~jQueryPlugin").BundleContent part should be in order to get a string representation of the combined minimized bundle.
Any help would be appreciatedĀ·
In the 1.1-alpha1 release we added a new Optimizer class which should allow you to more easily do this. Its intended to be a standalone class that's useable out of side of ASP.NET hosting, so setting it up will be slightly different.
You can get the bundle contents out via something like this:
OptimizationSettings config = new OptimizationSettings() {
ApplicationPath = "<your physical path to the app>",
BundleSetupMethod = (bundles) => {
bundles.Add(new ScriptBundle("~/bundles/js").Include("~/scripts/jqueryPlugin.js"));
}
};
BundleResponse response = Optimizer.BuildBundle("~/bundles/js", config);
Assert.IsNotNull(response);
Assert.AreEqual("<your bundle js contents>", response.Content);
Assert.AreEqual(JsMinify.JsContentType, response.ContentType);
The next release should be fleshing this scenario out more, as it is needed for build time bundling integration with Visual Studio.

grails - subdomain based projects and links

I am trying to develop a grails application that has "root" content (www.mydomain.com/about for example) but will also support "projects" based upon the subdomain of the request; for example myproject.mydomain.com > www.mydomain.com/myproject. As a first pass, i have the URL configuration below:
"/$controller/$action?/$id?" {
...
}
"/$project/$controller/$action?/$id?" {
constraints {
}
}
The main drawback so far is that the $project variable must be injected manually into every link (tedious and not DRY):
<g:link controller="foo" action="bar" params="${[project: params.project]}">link</g:link>
Is there a way to automatically inject the $project parameter into all links if it is present, or is there a better way to approach this problem?
Basically you can create a grails plugin that will inject into the controller a new project param with a value based on a custom TagLib <g:project bean="myproject"/> (for instance)
It will force you to define this tagLib on each gsp page of your project but it is still DRYer than each link.
Hope it helps,
Fabien.
I can think of a couple of things.
a) You can place a proxy (Apache or something else) in front of your app-server and do some url-rewriting. Bonus: This would also allow you to do some caching of static resources.
b) This solution is a little more technically interesting. You can look up the project based on the http host header (the subdomain part). This will save you from rewriting all urls, all Grails conventions will still apply so you shouldn't run into any problems with third party plugins and so on.

Scaffolding Web Services in Grails

I need to implement a web app, but instead of using relational database I need to use different SOAP Web Services as a back-end. An important part of application only calls web services and displays the result. Since Web Services are clearly defined in form of Operation: In parameters and Return Type it seems to me that basic GUI could be easily constructed just like in the case of scaffolding based on Domain Entities.
For example in case of SearchProducts web service operation I need to enter search parameters as input, so the search page can be constructed. Operation will return a list of products, so I need a page that will display this list in some kind of table.
Is there already some library in grails that let you achieve this. If not, how would you go about creating one?
Probably the easiest approach is to use wsimport on the WSDL files to generate the client-side stubs. Then you can call methods in the stubs from Groovy just as you would have called them from Java.
For example, consider the WSDL file for Microsoft's TerraServer, located at http://terraservice.net/TerraService.asmx?wsdl . Then you run something like
wsimport -d src -keep http://terraservice.net/TerraService.asmx?WSDL
which puts all the compiled stubs in the src directory. Then you can write Groovy code like
import com.terraserver_usa.terraserver.*;
TerraServiceSoap sei = new TerraService().getTerraServiceSoap()
Place home = new Place(city:'Boston',state:'MA',country:'US')
def pt = sei.convertPlaceToLonLatPt(home)
println "$pt.lat, $pt.lon"
assert Math.abs(pt.lat - 42.360000) < 0.001
assert Math.abs(pt.lon - -71.05000) < 0.001
If you want to access a lot of web services, generate the stubs for all of them. Or you can use dynamic proxies instead.
The bottom line, though, is to let Java do what it already does well, and use Groovy where it makes your life easier.
You should be able to use XFire or CXF Plugins. For automatic scaffolding, modify your Controller.groovy template in scaffolding templates so it auto-generates methods you need.

Multiple languages in an ASP.NET MVC application?

What is the best way to support multiple languages for the interface in an ASP.NET MVC application? I've seen people use resource files for other applications. Is this still the best way?
If you're using the default view engines, then local resources work in the views. However, if you need to grab resource strings within a controller action, you can't get local resources, and have to use global resources.
This makes sense when you think about it because local resources are local to an aspx page and in the controller, you haven't even selected your view.
I found this resource to be very helpful
Its a wrapper round the HttpContext.Current.GetGlobalResourceString and HttpContext.Current.GetLocalResourceString that allows you to call the resources like this...
// default global resource
Html.Resource("GlobalResource, ResourceName")
// global resource with optional arguments for formatting
Html.Resource("GlobalResource, ResourceName", "foo", "bar")
// default local resource
Html.Resource("ResourceName")
// local resource with optional arguments for formatting
Html.Resource("ResourceName", "foo", "bar")
The only problem I found is that controllers don't have access to local resouce strings.
Yes resources are still the best way to support multiple languages in the .NET environment. Because they are easy to reference and even easier to add new languages.
Site.resx
Site.en.resx
Site.en-US.resx
Site.fr.resx
etc...
So you are right still use the resource files.
The Orchard project uses a shortcut method called "T" to do all in-page string translations. So you'll see tags with a #T("A String to Translate").
I intend to look at how this is implemented behind the scenes and potentially use it in future projects. The short name keeps the code cleaner since it will be used a lot.
What I like about this approach is the original string (english, in this case) is still easily visible in the code, and doesnt require a lookup in a resource tool or some other location to decode what the actual string should be here.
See http://orchardproject.net for more info.
Some of the other solutions mentioned as answer do not work for the released version of MVC (they worked with previous versions of alpha/beta).
Here is a good article describing a way to implement localization that will be strongly-typed and will not break the unit testing of controllers and views: localization guide for MVC v1
This is another option, and you'll have access to the CurrentUICulture in the controller:
Check MVC3-multi-language

Resources