Serializing .NET Resources (.resx) as JSON (part 2)

So after playing with my own code after a while I realized that there was a slight flaw in my thinking.  Since every application is slightly different in the way it determines what culture to use, and that each request is technically a different Thread, I need a more generic way to capture that information.

I decided to use a querystring value.  Here is my updated code in regards to reading the querystring culture, setting it and fired up the appropriate ResourceManager..

 

ResourceManager rm = new ResourceManager(ConfigurationManager.AppSettings["JSResourcesAssemblyType"].ToString(),
                Assembly.LoadFile(ConfigurationManager.AppSettings["JSResourcesAssemblyPath"].ToString()));
            if (context.Request.QueryString["CultureCode"] == null) return;
            var culture = context.Request.QueryString["CultureCode"].ToString();            
            ResourceSet rs = rm.GetResourceSet(new CultureInfo(culture), true, true);            
            var sbInitial = "var rm = {";
            var sb = new StringBuilder(sbInitial);            
            var resEnum = rs.GetEnumerator();
            while (resEnum.MoveNext())
            {
                if (sb.ToString() != sbInitial) sb.Append(",");
                sb.Append("\"" + resEnum.Key + "\":\"" + 
                    resEnum.Value.ToString().Replace("\r\n", "").Replace("\"", "\\\"") + "\"");
            }
 
            sb.Append("}");
            sb.ToString();
 
            context.Response.ContentType = "text/javascript";
            context.Response.Write(sb.ToString());
06.09.2011 09:36 by Danny Gershman | Comments (0) | Permalink

Serializing .NET Resources (.resx) as JSON

This is actually quite a useful solution.  The goal here is to use the same resource file for client and server side coding, while also utilizing the “Culture” awareness of .NET that might be built into your application.

Be sure to create your Resources as a separate satellite assembly. 

We are going to create an HttpHandler.  Basically create a class and implement the IHttpHandler interface.

Look at the sample code below.

    public class ResourceJS : IHttpHandler
    {
 
 
        public bool IsReusable
        {
            get { return true; }
        }
 
        public void ProcessRequest(HttpContext context)
        {
            ResourceManager rm = new ResourceManager(ConfigurationManager.AppSettings["JSResourcesAssemblyType"].ToString(),
                Assembly.LoadFile(ConfigurationManager.AppSettings["JSResourcesAssemblyPath"].ToString()));
            rm.GetString("");
            ResourceSet rs = rm.GetResourceSet(Thread.CurrentThread.CurrentCulture, false, false);              
            var sbInitial = "var rm = {";
            var sb = new StringBuilder(sbInitial);
            var resEnum = rs.GetEnumerator();
            while (resEnum.MoveNext())
            {
                if (sb.ToString() != sbInitial) sb.Append(",");
                sb.Append("\"" + resEnum.Key + "\":\"" + 
                    resEnum.Value.ToString().Replace("\r\n", "").Replace("\"", "\\\"") + "\"");
            }
 
            sb.Append("}");
            sb.ToString();
 
            context.Response.ContentType = "text/javascript";
            context.Response.Write(sb.ToString());
        }
    }

You can see here that there are two Web.config values that have specified here.  JSResourcesAssemblyType is the full Namespace and root class name of the Resource files.  JSResourcesAssemblyPath is the location of satellite assembly.  This uses reflection to load up the metadata of the assembly.

Once this compiled, you need to add this to the web.config.  Here is a sample for IIS7.

 

<handlers>
            <remove name="WebServiceHandlerFactory-Integrated" />
            <remove name="ScriptHandlerFactory" />
            <remove name="ScriptHandlerFactoryAppServices" />
            <remove name="ScriptResource" />            
            <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add name="ResourceJS" path="ResourceJS.axd" verb="GET" type="ResourceJS" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode" />
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>

You can see the ResourceJS is being extended to the url ResourceJS.axd.  Below is my sample page.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ResourceJSTest.aspx.cs" Inherits="ResourceJSTest" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="js/2.1.0.0-debug/jquery-1.4.4.min.js"></script>
    <script type="text/javascript" src="/ResourceJS.axd"></script>
    <script type="text/javascript">
        $(function () {
            $("#target").html(rm.FAQ_Q8_TEXT);
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div id="target"></div>
    </form>
</body>
</html>
The rm object in javascript has all the “keys” that were defined in the original RESX file for that culture.  You can call any of these as a property of rm.   Very re-usable.
06.08.2011 14:19 by Danny Gershman | Comments (0) | Permalink

Decoupling CSS Files (Skinning)

It can be very useful to decouple CSS files from each other without reusing classes.  In some cases you might want a designer to focus on handling the coloring items and not have control over positioning.  This can be very painful especially if most of your CSS classes have already been defined.

This methodology allows you to dynamically create some “Skin” classes based off predefined ones.  I have created two simple helper functions.  This tutorial requires that you use jQuery.

function applySkin() {
    _skinObjs($("body"));    
    _skinObjs($("div"));
    _skinObjs($("span"));    
    _skinObjs($("a"));
}
 
function _skinObjs(objs) {
    for (var i = 0; i < objs.length; i++) $(objs[i]).addClass($(objs[i]).attr("class") + "-Skin");    
}

This will essentially, add a “–Skin” class to every body, div, span, and anchor tag on your page (feel free to add additional tags as necessary). 

Now you can remove what information you want repeated.  So let’s say that you have a Site.css stylesheet and you want to remove some stylistic definitions to a separate file (coloring for example).  To continue on that example, take this sample html code.

<html>
<head>
<title>Sample Page</title>
<link href="Site.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
</head>
<body>
<div class="MainTitle">Hello World!</div>
</body>
</html>

 

Take a look at the Site.css, notice how the color information is in the same file.

.MainTitle 
{
    font-size: 32pt;
    position: absolute;
    top: 100px;
    left: 100px;
    background-color: #fea130;
}

So what I need to do now is to create a separate file.  Let’s call it Site-Skin.css.  I will append to my class “-Skin” as seen earlier.  I also need to remove it from my Site.css file.

Updated Site.css

.MainTitle
{
    font-size: 32pt;
    position: absolute;
    top: 100px;
    left: 100px;
}

 

Site-Skin.css

.MainTitle-Skin
{
    background-color: #fea130;
}

Now I need to specify in my HTML code the link to the particular “-Skin” I want to use.  Let’s say that I’m using a scripting language like ASP.NET, I could put the skins in different folders and dynamically change the decoupled CSS file.

<%@ Page Language="C#" %>
<html>
<head>
<title>Sample Page</title>
<link href="Site.css" rel="stylesheet" type="text/css" />
<link href="<%=Skin_Folder%>/Site-Skin.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
</head>
<body>
<div class="MainTitle">Hello World!</div>
</body>
</html>

 

Now if you look below you can see my folder structure has multiple Site-Skin.css files.

image

This is very powerful as your designer can very easily work on the Skin while you work / or someone else works on positioning and other features of the styling process.

Technorati Tags: ,,,
12.14.2010 13:58 by Danny Gershman | Comments (0) | Permalink

Mission: delegates

Wanted to do a refresher on delegates before learning more about LINQ

 

delegate void Callback();
 
void Main()
{
    MakeRequest(AfterRequest2);
}
 
private void MakeRequest(Callback callback)
{
    "Request Made".Dump();
    callback();
}
 
private void AfterRequest()
{
    "Stuff done after request".Dump();    
}
 
private void AfterRequest2()
{
    "Different stuff done after request".Dump();    
}

 

Here is another sample I played with. This one uses anonymous delegates and outer variables.

  delegate bool GreaterThanHandler (int first, int second);
 
  void BubbleSort(int[] items, GreaterThanHandler greaterThan)
  {
        int i;
      int j;
      int temp;
 
      for (i = items.Length - 1; i >= 0; i--)
      {
          for (j = 1; j <= i; j++)
          {
              if (greaterThan(items[j - 1], items[j]))
              {
                  temp = items[j - 1];
                  items[j - 1] = items[j];
                  items[j] = temp;
              }
           }
        }
 
  }
  
  bool GreaterThan(int first, int second)                     
  {
      return (first > second);
  }
  
  bool LessThan(int first, int second)
  {
        return (first < second);  
  }
 
  void Main()
  {  
      int i;
      int[] items = new int[] { 1,2,3,4,5 };
      int swapCount = 0;
      
      BubbleSort(items, delegate(int first, int second) 
      {
           bool swap = (first > second % 2);
         if (swap) swapCount++;
         return swap;      
      });                           
 
      for (i = 0; i < items.Length; i++)
      {
          items[i].Dump();          
      }
      
      
      "Number of swaps: ".Dump();
      swapCount.Dump();
  }
 
Technorati Tags: ,
09.04.2010 05:59 by Danny Gershman | Comments (0) | Permalink

BlogEngine.NET custom captcha

One of the biggest flaws with my blog was that there was no CAPTCHA  ("Completely Automated Public Turing test to tell Computers and Humans Apart.)  Wikipedia article here.

I was getting comment spammed.  This I hope will reduce if not eliminate BOTS from putting false comments into my blog.  BOTS do this to increase their ranking on search engines in order to get more hits to their sites, when a keyword is entered.

Upon looking at the code for BlogEngine.NET, I did notice that there looked like there was some DEV in the area of the CAPTCHA, but it wasn’t fully implemented.

There is still one minor security flaw in my CAPTCHA design.  Once it’s fixed I will reveal what it was and how I fixed it.  In the meantime, I’ve gone ahead and deleted all fake comments and uploaded the new code.

If you try to comment on my blog now, you’ll see a little picture with some number on it.  The picture is of one of my cats “Sneakers”.  If the number is typed incorrectly, you won’t be able to post the comment.  Some of the messaging needs fixing as well.  This is definitely a good feeling project for me.

image

12.24.2009 12:36 by Danny Gershman | Comments (3) | Permalink

Run ASP.NET Development Server without Visual Studio

Ever want to run ASP.NET development server without having to fire up Visual Studio Debugger.

You can create your own scripts or commands by being able to access this.

%WINDOWS PATH%\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe

Here is the command line options as shown without setting any parameters.  Enjoy!

image

08.05.2009 07:11 by Danny Gershman | Comments (3) | Permalink

URL Rewrites in WCF

I had posted an entry to StackOverflow earlier today.  But I was able to resolve before I got an answer.  When handling URL rewrites in WCF, it’s important to include the trailing forward slash in the URL.  You can this in my example below.

 

public class FormatModule : IHttpModule
{    
#region IHttpModule Members    
 
     public void Dispose()    
     {       
          throw new NotImplementedException();   
     }   
    
     public void Init(HttpApplication application)    
     {        
          application.BeginRequest += new EventHandler(application_BeginRequest);   
     }    
 
     void application_BeginRequest(object sender, EventArgs e)   
     {       
          HttpContext context = HttpContext.Current;       
          if (context.Request.RawUrl.Contains(".pox"))             
               context.RewritePath("~/Lab1Service.svc?format=pox", false);        
          else if (context.Request.RawUrl.Contains(".json"))             
               context.RewritePath("~/Lab1Service.svc?format=json", false);   
      }    
#endregion
}
 
What I needed to do was to include the trailing slash as seen below.

 

context.RewritePath("~/Lab1Service.svc/?format=pox", false);
Technorati Tags: ,,
05.12.2009 10:31 by Danny Gershman | Comments (0) | Permalink

ReBind ASPX.VB/CS (Codebehind) to ASPX

Something has happened to a solution file that I’m working with and the codebehind has been unbinded from it’s ASPX page.  Use the following technique to rebind in VS2003

image

Right-click an ASPX page and select “View Code” (You can highlight multiple ASPX pages, by using Ctrl+Click)

image

The code will now be rebinded, as see below.

image

03.23.2009 16:57 by Danny Gershman | Comments (2) | Permalink