Jun 20, 2013

.NET Culture, Localization - bits & pieces

Two settings rule culture settings:

The UICulture property is used to specify which resource files are loaded for the page. The
resource files can contain all the text content of your pages translated into a particular
language. You can set this property to any standard culture name. This property is
discussed in detail during the discussion of using local and global resources later in this
chapter.
The Culture property, on the other hand, determines how strings such as dates, numerals,
and currency amounts are formatted
. It also determines how values are compared and
sorted. For example, by modifying the Culture property, you can display dates with
language-specific month names such as January (English), Januar (German), or Enero
(Spanish).
Make distinction between neutral & specific culture:

Notice that each culture name consists of two parts. The first part represents the language
code and the second part represents the country/region code. If you specify a culture
name and do not provide a country/region code—for example, en—then you have specified
something called a neutral culture. If you provide both a language code and a
country/region code—for example, en-US—then you have specified something called a
specific culture.

Set explicitly culture on current thread (no matter Desktop or Website app).
Watch out if you run multithreaded app upon instancing of thread do this:

System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("de-DE");

Although above will work in most cases proper way in WebForms website is to override InitializeCulture() like this:

 protected override void InitializeCulture()
        {
            Culture = "en-US";
        }

Set culture for complete website in web.config:

<system.web>
     <globalization culture="de" uiCulture="DE"/> 
Alternatively use granular approach and assign explicitly to each value its own culture:

var deCulture = new CultureInfo("de-DE");
labCurrency.Text = (2323.23m).ToString("c",deCulture);
If you work on multi-language app you should take special care on comparing string values of different language. Use string.Compare :

if (String.Compare(“Hello”, “Hello”, true, new CultureInfo(“de-DE”)) == 0)
lblResult.Text = “The strings are the same!”; 

Resources file in website

Create App_LocalResources under root of ASPX web pages you want localized.
Place in it resource file named :
MyWebPage.aspx.resx
This is neutral culture default resource file.
To support different languages add Culture id in name like this:

MyWebPage.aspx.de-DE.resx

You can write it neutral culture also:

MyWebPage.aspx.de.resx

Then  in html markup explicitly address resource file member like this:

<asp:Literal ID="literal" runat="server"  Text="<%$ Resources:CURRENCY %>"></asp:Literal>
Above is explicit retrieving of resource value.

There is more intuitive implicit localization using meta tag in server controls:

<asp:Label meta:resourceKey="labCurrency2" id="labCurrency2" runat="server" ToolTip="Funny" ></asp:Label>

labCurrency2.Text de_currency2Text labCurrency2.Tooltip de_currency2Tooltip
If needed you can access content of resource file even outside context of web page.
But still you need to have access to HttpContext:

return (string)HttpContext.GetLocalResourceObject(“~/LocalizablePage.aspx”,
“ClickHere”);

Global resource

When localization is addressing frequent same text it is best to put it in global resource file.
Just create App_GlobalResources folder and place in resource file named what ever you like.
For example:
/_App_GlobalResources
                    site.resx
You obtain value on same ways as explained for localized resources. Here is meta tag example:

<%$ Resources:Site,Copyright %>

Alternative from code is:
(string)GetGlobalResourceObject(“Site”, “Title”);
Since global  resource files get compiled immediately upon change they can  be accessed directly through their namespace:
labName = Resources.Site.Copyright;

How to convert language code page (e.g. 1033) to .NET country ISO code (e.g. DE):


var twoLetterLangugageISO = (new CultureInfo(languageId)).TwoLetterISOLanguageName;

Jun 19, 2013

Simple reusable javascript object - basics

You need to create javascript to handle multiple instances of same type of functionality with ability to input standardized arguments.
We need to model Javascript object. Javascript does not support objects in OOP sense and this creates a lot of confusion. On top of it its dynamic language. Comparing it to .NET classes where mostly you deal with static members of class is not possible.
So here is example of simple Javascript object to implement creating and configuring simplest div container.
I'm using JQuery.

Declaring:
counterPanel = function (pnlId, argsParam) {
    var args = $.extend({
        title: "title",
        color: "rgb(255,250,250)",
        execute: null
        },argsParam
        );
    this.Show = function Show() {
         
        if (!DoesContainerExists(pnlId)) {      
            $('#countersContainer').append('<div id="'+pnlId+'"><h1 style="color:'+args.color+'">'+args.title+'</h1></div>');
        }
       
    }
    this.Hide = function Hide() {
        if (DoesContainerExists(pnlId)) {
            $('div#' + pnlId).Hide();
        }
    }
    if (typeof(args.execute) == 'function') args.execute();
    function DoesContainerExists(pnlId) {
        return ($('#countersContainer div#' + pnlId + ':First').attr('id') != undefined);
    }
}
Instancing with various input params including function injection.

var dlgFirst = new counterPanel("dlgFirst", {title:"something special", color:"rgb(0,0,100)"});
        dlgFirst.Show();
        var dlgSecond = new counterPanel("dlgSecond", { title: "special", color: "rgb(110,0,100)", execute: function () { alert('2');} });
        dlgSecond.Show();

Jun 17, 2013

ASP.NET Running recurring background threads inside IIS

You have time consuming tasks that happen on time regular basis.
For example contacting web service or long db process.
They should run in background to free front website of locking into long task.

There is proper way of easily doing this inside legacy ASP.NET website.

There are even open source framework for this.

The challenge resides in fact that IIS & ASP.NET own app domain and destroy it when they determine that website lifespan is finished or app pool gets recycled.

Read more:

http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx
https://github.com/NuGet/WebBackgrounder
http://fluentscheduler.codeplex.com/workitem/list/basic

Jun 13, 2013

IIS bits & pieces

Type of Pipeline on application pool?
Always use default Integrated.
Classic pipeline is backward compatibility for IIS6.0

Read more:
http://stackoverflow.com/questions/716049/what-is-the-difference-between-classic-and-integrated-pipeline-mode-in-iis7
http://www.iis.net/learn/application-frameworks/building-and-running-aspnet-applications/aspnet-integration-with-iis

I've always asked myself why can't you mix different .NET versions on one application pool.
So here is explanation:

Unfortunately, due to the limitation of the ability to load only one CLR version into a single worker process, you must make sure that two applications that use different versions of ASP.NET are never configured to exist within the same application pool. When this common mistake is made, the first request loads the CLR of the corresponding aspnet_isapi.dll, and subsequent requests to the other version within the same application pool will fail.

When you open global.asax.cs you can see various empty event handlers. These are simply mappers to above explained integrated pipeline events:


In Integrated mode, the ASP.NET request-processing stages that are exposed to modules are directly connected to the corresponding stages of the IIS pipeline. The complete pipeline contains the following stages, which are exposed as HttpApplication events in ASP.NET:
So the HttpApplication class corespondes to pipeline.

Nice step by step of practical use of integrated pipeline and plugging into IIS request pipeline.
On any medium or large scale website you will encounter such extensions so its good to know what a heck it is.

http://www.iis.net/learn/develop/runtime-extensibility/developing-iis-modules-and-handlers-with-the-net-framework

For above, in a nutshell : you develop module when need to address all request from pipeline and use handler for targeting exact url, extension etc.

This guy was former PM of IIS 7.0 and ASP.NET

http://mvolo.com/

Jun 4, 2013

ASP.NET security - authentication- revisited

UPDATE 14.09.15

Must read: http://www.codeproject.com/Articles/689801/Understanding-and-Using-Simple-Membership-Provider
http://www.codeproject.com/Articles/408306/Understanding-and-Implementing-ASP-NET-Custom-Form
http://www.codeproject.com/Articles/578374/AplusBeginner-27splusTutorialplusonplusCustomplusF

--------------------------
I'm exploring simplest way to employ web security with legacy ASP.NET components.
Basic and most often type of web site authentication is forms authentication.

Forms


It is very straightforward and simple:

1. Add in web.config:

<authentication mode="Forms">
      <forms defaultUrl="default.aspx" loginUrl="login.aspx" name=".ASPXAUTH">
      </forms>
    </authentication>
    <authorization>
      <deny users="?"/>
    </authorization>   

2. Create your own Login.aspx and use:

System.Web.Security.FormsAuthentication

;for redirecting from and to login.
Whole idea is that after you issue redirect command cookie is created and persisted.
Don't use param strCookiePath in RedirectFromLoginPage. It seems that it prevents SignOut() to destroy cookie!
There is also SignOut which destroys cookie and you'r back to square one.
Authenticated user are obtained from:

Context.User.Identity.Name

Simple and works like a charm if you wish to create completely manually handling of user creation, managment and etc.

Not sure is this required:

FormsAuthentication.SetAuthCookie(userName, persistent);

Membership

There is tone of stuff about ASP.NET membership component.
But what is the simplest scenario to use it?
I want to integrate Forms & Membership in most simplest scenario.
So here it is.

1. Open "Developer Command Prompt for Visual Studio"  and execute "aspnet_regsql.exe"
    Select your database and you'll end up with bunch of aspnet_xxx tables & stored procs used by membership.
2. Configure custom Membership provider in your web.config and make sure it points to correct connection string. Example:

<configuration>
  <connectionStrings>
    <add name="AdventureSQLConnection" connectionString="Data Source=DB_SERVER;Initial Catalog=AdventureWorksLT2008;Persist Security Info=True;User ID=XXXX;Password=XXXXXXX;"/>
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
 
    <authentication mode="Forms">
      <forms defaultUrl="default.aspx" loginUrl="login.aspx" name=".ASPXAUTH">
      </forms>
    </authentication>
    <authorization>
      <deny users="?"/>
    </authorization>      
    <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add
          name="SqlProvider"
          type="System.Web.Security.SqlMembershipProvider"
          connectionStringName="AdventureSQLConnection"
          applicationName="MyApplication"
          enablePasswordRetrieval="false"
          enablePasswordReset="true"
          requiresQuestionAndAnswer="true"
          requiresUniqueEmail="true"
          passwordFormat="Hashed" />
      </providers>
    </membership>
  </system.web>
</configuration>
 Two remarks, first be sure to use <clear/> so default aspnetSQLprovider gets destroyed. This one is registered in MACHINE.CONFIG. And second be sure to use correct connection string.

3. Use infamous ASP.NET website configuration to test whether you did above work correctly and optionally set initial set of users, roles whatever.

4. In your login.aspx use combination of Membership methods and above mentioned FormsAuthentication  to query and manage your users, roles, whatever. For example, here is the simplest one-liner of validating user:

if (Membership.ValidateUser("sinisa", "demo1234x!"))
     FormsAuthentication.RedirectFromLoginPage("sinisa", true);

http://msdn.microsoft.com/en-us/library/xdt4thhy(v=vs.100).aspx