Use ASP.NET Resource strings from within javascript files - asp.net

How would one get resx resource strings into javascript code stored in a .js file?
If your javascript is in a script block in the markup, you can use this syntax:
<%$Resources:Resource, FieldName %>
and it will parse the resource value in as it renders the page... Unfortunately, that will only be parsed if the javascript appears in the body of the page. In an external .js file referenced in a <script> tag, those server tags obviously never get parsed.
I don't want to have to write a ScriptService to return those resources or anything like that, since they don't change after the page is rendered so it's a waste to have something that active.
One possibility could be to write an ashx handler and point the <script> tags to that, but I'm still not sure how I would read in the .js files and parse any server tags like that before streaming the text to the client. Is there a line of code I can run that will do that task similarly to the ASP.NET parser?
Or does anyone have any other suggestions?

Here is my solution for now. I am sure I will need to make it more versatile in the future... but so far this is good.
using System.Collections;
using System.Linq;
using System.Resources;
using System.Web.Mvc;
using System.Web.Script.Serialization;
public class ResourcesController : Controller
{
private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
public ActionResult GetResourcesJavaScript(string resxFileName)
{
var resourceDictionary = new ResXResourceReader(Server.MapPath("~/App_GlobalResources/" + resxFileName + ".resx"))
.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
var json = Serializer.Serialize(resourceDictionary);
var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.{0} = {1};", resxFileName, json);
return JavaScript(javaScript);
}
}
// In the RegisterRoutes method in Global.asax:
routes.MapRoute("Resources", "resources/{resxFileName}.js", new { controller = "Resources", action = "GetResourcesJavaScript" });
So I can do
<script src="/resources/Foo.js"></script>
and then my scripts can reference e.g. window.Resources.Foo.Bar and get a string.

There's no native support for this.
I built a JavaScriptResourceHandler a while ago that can serve Serverside resources into the client page via objects where each property on the object represents a localization resource id and its value. You can check this out and download it from this blog post:
http://www.west-wind.com/Weblog/posts/698097.aspx
I've been using this extensively in a number of apps and it works well. The main win on this is that you can localize your resources in one place (Resx or in my case a custom ResourceProvider using a database) rather than having to have multiple localization schemes.

whereas "Common" is the name of the resource file and Msg1 is the fieldname. This also works for culture changes.
Partial Javascript...:
messages:
{
<%=txtRequiredField.UniqueID %>:{
required: "<%=Resources.Common.Msg1 %>",
maxlength: "Only 50 character allowed in required field."
}
}

In a nutshell, make ASP.NET serve javascript rather than HTML for a specific page. Cleanest if done as a custom IHttpHandler, but in a pinch a page will do, just remember to:
1) Clear out all the ASP.NET stuff and make it look like a JS file.
2) Set the content-type to "text/javascript" in the codebehind.
Once you have a script like this setup, you can then create a client-side copy of your resources that other client-side scripts can reference from your app.

If you have your resources in a separate assembly you can use the ResourceSet instead of the filename. Building on #Domenics great answer:
public class ResourcesController : Controller
{
private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
public ActionResult GetResourcesJavaScript()
{
// This avoids the file path dependency.
ResourceSet resourceSet = MyResource.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
// Create dictionary.
var resourceDictionary = resourceSet
.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
var json = Serializer.Serialize(resourceDictionary);
var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.resources = {1};", json);
return JavaScript(javaScript);
}
}
The downside is that this will not enable more than one resource-file per action. In that way #Domenics answer is more generic and reusable.
You may also consider using OutputCache, since the resource won't change a lot between requests.
[OutputCache(Duration = 3600, Location = OutputCacheLocation.ServerAndClient)]
public ActionResult GetResourcesJavaScript()
{
// Logic here...
}
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs

I usually pass the resource string as a parameter to whatever javascript function I'm calling, that way I can continue to use the expression syntax in the HTML.

I the brown field application I'm working on we have an xslt that transforms the resx file into a javascript file as part of the build process. This works well since this is a web application. I'm not sure if the original question is a web application.

use a hidden field to hold the resource string value and then access the field value in javascript
for example :
" />
var todayString= $("input[name=TodayString][type=hidden]").val();

Add the function in the BasePage class:
protected string GetLanguageText(string _key)
{
System.Resources.ResourceManager _resourceTemp = new System.Resources.ResourceManager("Resources.Language", System.Reflection.Assembly.Load("App_GlobalResources"));
return _resourceTemp.GetString(_key);
}
Javascript:
var _resurceValue = "<%=GetLanguageText("UserName")%>";
or direct use:
var _resurceValue = "<%= Resources.Language.UserName %>";
Note:
The Language is my resouce name. Exam: Language.resx and Language.en-US.resx

Related

ASP.NET CssMinify, HttpContextBase

I have an ASP.NET app which needs to have multiple layouts for the views. There's a normal web layout, and a "static" layout for a self-contained page with no dependencies (to be used as a display template in a doc management system).
It's easy enough to have a view switch its layout.
So the all-in-one-page layout needs to include all of its CSS in a <style> tag inside the page. I found a way to find out what files are in a bundle and wrote a method like so:
#MyCode.IncludeCSS("~/StaticLayout/css")
It reads the CSS files in the bundle and emits their content into the page inside a <style> tag.
But I'd like to minify the CSS.
I haven't been able to find any documentation for System.Web.Optimization.CssMinify. You need to call the Process method, which needs a BundleContext. So... find one, create one? MSDN isn't much use:
public BundleContext(
HttpContextBase context,
BundleCollection collection,
string bundleVirtualPath
)
Parameters
context
Type: System.Web.HttpContextBase
The context.
Well, that's definitely useful. I had no way of knowing that context (of type context) was the context until some bulging-brained colossus of the intellect in Redmond took some time out from his busy nap to push a definite article in front of it with his fat little paws before passing out in a puddle of warm drool.
Nevertheless, I still don't know what it is or where you get one from, and neither does Google. HttpContext.Current is not derived from it and has no properties (that I can find) which are.
This page has some good information about normal bundling, but it assumes that the framework will be doing the bundling and serving the bundle content in the conventional way, as a separately requested resource.
Has anybody done this?
Ed Plunkett,
If you are using this as a HTML helper the HttpContextBase can be grabbed from the ViewContext.HttpContext property. This can be created such as.
public static IHtmlString BundleCss(this HtmlHelper html, string outputPath, params string[] cssFilePaths)
{
var collection = new BundleCollection();
foreach (var cssFilePath in cssFilePaths)
collection.Add(new Bundle(cssFilePath));
var bundler = new BundleContext(html.ViewContext.HttpContext, collection, outputPath);
//... ommitted code
System.Web.Optimization.CssMinify minify = new CssMinify();
minify.Process(bundler, response);
//... TODO: Grab the response content and return
}
Yes this is a basic example using a HTML helper. Let me know if this does't answer your question.
EDIT: After re-reading the question I am clarifying my response. So the above helps find the HttpContextBase property from the question. However I think the question is how you can actually read the content of the files, minify them and out put them into a <style> tag on the page.
I took a stab at writing my own interpretation of your requirement and came up with the following set of classes
My CssOutputBundler class:
public class CssOutputBundler
{
static readonly Dictionary<string, string> cachedOutput = new Dictionary<string, string>();
readonly string tempFileOutputPath;
readonly HtmlHelper helper;
readonly IList<string> virtualFilePaths;
public CssOutputBundler(HtmlHelper helper, string tempFileOutputPath)
{
if (helper == null)
throw new ArgumentNullException("helper null");
if (string.IsNullOrWhiteSpace(tempFileOutputPath))
this.tempFileOutputPath = tempFileOutputPath;
this.helper = helper;
this.virtualFilePaths = new List<string>();
this.tempFileOutputPath = tempFileOutputPath;
}
public CssOutputBundler Add(string cssFilePath)
{
if (!this.virtualFilePaths.Contains(cssFilePath))
this.virtualFilePaths.Add(cssFilePath);
return this;
}
public IHtmlString Minify()
{
if (helper == null)
throw new ArgumentNullException("helper null");
string cache_string = string.Join(",", this.virtualFilePaths);
if(cachedOutput.ContainsKey(cache_string))
return formatResponse(File.ReadAllText(cachedOutput[cache_string]));
var bundle = new StyleBundle(this.tempFileOutputPath).Include(this.virtualFilePaths.ToArray());
var collection = new BundleCollection();
collection.Add(bundle);
var context = new BundleContext(helper.ViewContext.HttpContext, collection, "");
var response = bundle.GenerateBundleResponse(context);
System.Web.Optimization.CssMinify minify = new CssMinify();
minify.Process(context, response);
string serverPath = helper.ViewContext.HttpContext.Server.MapPath(this.tempFileOutputPath);
string outputPath = Guid.NewGuid().ToString() + ".css";
while(File.Exists(Path.Combine(serverPath, outputPath)))
outputPath = Guid.NewGuid().ToString() + ".css";
File.WriteAllText(outputPath, response.Content);
cachedOutput[cache_string] = outputPath;
return formatResponse(response.Content);
}
IHtmlString formatResponse(string responseContent)
{
StringBuilder responseBuilder = new StringBuilder();
responseBuilder.AppendLine("<style type=\"text/css\">");
responseBuilder.Append(responseContent);
responseBuilder.AppendLine("</style>");
return helper.Raw(responseBuilder.ToString());
}
}
Ok the above class looks complex but all it does is creates an internal list of paths for the bundler to to bundle and minify. When the Minify method is called it formats the virtual paths into a string which is used as a cache key. This is how we determine if we have already bundled and minified these scripts.
If we have we read from the temporary bundled script that is stored on the HDD.
Note: I used hard drive storage as opposed to in memory storage. This can be easily changed by stuffing the full content into a static dictionary or other cacheing medium.
If this file set has not been bundled, minified etc then we proceed to bundle and minify the set. Finally we store the file onto the HDD and return the response. So this is pretty easy.
Now to implement the class I just wrote a quick HTML Helper as the Minification class supports chaining for Add files methods can be implemented nicely.
The HTML Helper:
public static CssOutputBundler BundleCss(this HtmlHelper helper, string outputVirtualPath)
{
return new CssOutputBundler(helper, outputVirtualPath);
}
Ok basic implementation for the bundler. Now this helper takes the string outputVirtualPath this is the virtual PATH to store the temporary files. If you do decide to eliminate saving to HDD and use a cache system you could remove this parameter from the helper and the class.
Finally this can be used in your view as...
#Html.BundleCss("~/Content/").Add("~/Content/Site.css").Add("~/Content/themes/base/jquery-ui.css").Minify();
Where the ~/Content/ is the virtual path on the HDD to store the minified files. Then we add two files "~/Content/Site.css" and ~/Content/themes/base/jquery-ui.css. Finally call the minify method which returns the html string. Such as...
<style type="text/css">
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)} ....more css
</style>
Cheers.

Using a Razor #functions in several webpages (.cshtml files)

I have the below function that I would like to be available to several .cshtml views in my asp.net web pages 2 application. How can I make this function available to any view in the application (as opposed to just one).
#functions {
public bool DisplayButton(String startDate, String endDate)
{
return Convert.ToDateTime(startDate) < DateTime.Now && Convert.ToDateTime(endDate) > DateTime.Now;
}
}
Create a file called Functions.cshtml in App_Code and then paste the code you have into the file. Then you can call the DisplayButton method in any .cshtml file by prefixing it with the file name:
var myBool = Functions.DisplayButton(DateTime.Now, DateTime.Now.AddDays(30));
For more on working with functions and helpers in ASP.NET Web Pages, read this: http://www.mikesdotnetting.com/Article/173/The-Difference-Between-#Helpers-and-#Functions-In-WebMatrix
You can define "global" helper functions in a Razor file in the AppCode directory as described here: http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx. However, helpers only render page elements; they cannot return a value (or more correctly, the returned value is the HTML markup to be rendered).
If you need to return a value, your best bet is an extension method.
Don't see why you couldn't have a static class with a static method and just include it at the top of every view and then use it

Convert Results of LINQ to SQL Query to XML/JSON

I wish to populate a JavaScript array with the results of a database query. From what I understand, a good approach is to populate a bunch of directories on my server with serialized XML or JSON files which my JS functions can then read into without having to access the database. Is this true? Should the database write these XML files upon user interaction, or should they be prepopulated?
From the details you have provided:
I Personally would create a Web Service endpoint returning your linq query serialized to JSON using JSON.NET or an equivalent. The endpoint can then be called using ajax within your client page.
You can check this example out on ASP.NET for how to create a asmx (legacy) web service. Also you can look at this example of using the [WebMethod] attribute .
A web method in your code behind files.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetMyQueryResultsAsJson()
{
var results = GetQueryResults();
var jss = new JavaScriptSerializer();
string json = jss.Serialize(results);
return json;
}
A ajax call on your client page:
function loadData() {
var myArray = [];
$.getJSON("<%= ResolveUrl("~/MyPage.aspx/GetMyQueryResultsAsJson") %>", function (data) {
$.each(data, function(obj) {
myArray.push([obj.id, obj.someValue, obj.AnotherValue]);
});
});
}
I used jQuery ajax with generic http handler returing json
I created handler and put my business logic there.
It return me the result in form of json
I iterated the json using jquery.
And created my html form that.
Edit 1
Here are some useful links
http://www.codeproject.com/Articles/203621/Call-HTTPhandler-from-jQuery-Pass-data-and-retriev
http://www.sharepointnutsandbolts.com/2010/11/sp2010-ajax-part-4-returning-json-from.html
Edit 2
You can also take benefit of jtemplate
http://www.joe-stevens.com/2010/01/05/using-the-jtemplate-jquery-plugin-with-ajax-and-asp-net/
http://encosia.com/use-jquery-and-aspnet-ajax-to-build-a-client-side-repeater/

How can we integrate jQuery autocomplete using asp.net, webservice and sql database?

I am trying to implement the code given for "jQuery Autocomplete and ASP.NET",
but unable to integrate it because you are using subsonic to query database.
So can you tell me how to query sqldatabase and bind the query result to the plugin from webservice in asp.net using C#?
This is a pretty easy task, the catch is that the jQuery autocomplete extender expects an array of values. Here is example of how I parse the standard XML results from a ASMX web serivce to use with the jQuery autocomplete extender.
Since ASP.NET likes to rewrite your ID's, you can pass in the ClientID to get the dynamic ID.
$("#<%= TextBox1.ClientID %>").autocomplete("/Demo/WebSvc.asmx/SuggestCustomers", {
parse: function(data) {
var parsed = [];
$(data).find("string").each(function() {
parsed[parsed.length] = {
data: [$(this).text()],
value: $(this).text(),
result: [$(this).text()]
};
});
return parsed;
},
dataType: "xml"
});
Here is what the associated web service would look like, remember to uncomment the [ScriptService] attribute on the web service:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class WebSvc: WebService
{
[WebMethod]
public string[] SuggestedCustomers(string q)
{
// Do Query
// Add items into string array
List<string> items = new List<string>();
while (dr.Read())
{
items.Add(dr[0].ToString());
}
// Return array
return items.ToArray();
}
}
I am not fluent in asp.net but fundamentally like most web coding questions this involves breaking your problem into smaller ones.
From an architectural perspective your components might include the following...
a service layer that potentially uses your db etc to answer or produce a result for your query.
a web component or service entry point that uses the completed service mentioned above to return the data in a format the browesrr can easily understand - eg JSON.
some javascript using jquery which invokes the end point define in the immediate point above.
write unit tests for all the above components - don't forget to test failure cases because as we all know software sometimes fails ...

ASP.net IHttpHandler to execute .aspx file

What is the proper to make an IHttpHandler to have an existing .aspx page process the request? I would like to be able to compile the .aspx file into an IHttpHandler and then have it process the request. There is the PageParser.GetCompiledPageInstance method, however in the documentation it states its not for direct use from code. I know I can have apsx files be automatically directed to, or perform a RewritePath, however I would like to have the object reference to the handler.
Here's one quick-n'-dirty way of doing it:
var virtualPath = "~/foo/bar.aspx"
var output = HttpContext.Current.Response.Output;
// Get the compiled page type (i.e. foo_bar_aspx)
Type controlType = BuildManager.GetCompiledType(virtualPath);
// "new()" it up
var pageInstance = Activator.CreateInstance(controlType);
// Execute it
HttpContext.Current.Server.Execute(pageInstance, output, true);

Resources