Tips and Tricks

Labels
AJAX(112) App Studio(7) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(183) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
Tips and Tricks
Monday, June 27, 2011PrintSubscribe
Globalization and Localization

Code On Time web application generator creates standard ASP.NET web projects and web sites, which take full advantage of ASP.NET globalization infrastructure. Globalization in ASP.NET has been perfected by Microsoft to allow creation of web applications that work with all cultures and languages. The building blocks are there and our web application generator puts them together to offer a great solution for your globalization and localization needs.

image

Globalization

Code On Time applications offer full support for world cultures, including date and time, calendar, numeric, and currency formats. Your application code may use one culture for the server side business logic and a different culture for presentation.

Globalization settings are configured in the project wizard on the page titled Globalization and Localization. The screen shot below shows this page in a new project.

image

Culture and UI Culture drop down lists are automatically configured to match the locale of your computer. The screen shot above shows both inputs set to en-US, English (United States) .

The selections in these drop downs are the primary culture set of your application where Culture is governing the culture used in the code executed on the server and UI Culture is controlling the user interface culture aspects of the application.

If you are not planning to create applications for other locales then do not make any changes and simply click Next to continue project configuration.

If you are developing an application for a locale that is different then the one selected in Culture and UI Culture then make sure to change the selections accordingly.

Unlimited edition of web application generator allows specifying multiple culture sets.

You can define multiple culture sets by selecting  combinations in Culture / UI Culture drop downs and pressing Add Cultures button.

For example, if you are developing a line-of-business application that is expected to have users primarily in United States then you may anticipate that users from two neighbor countries Canada and Mexico may need to be supported as well. In this age of glo,bal commerce it should not be surprising that the business users of your web application may need to interact with partners from a far away country such as Taiwan.

Given the example above your application must support English, French, Spanish, and Traditional Chinese. The screen shot below shows the configuration of the corresponding supported culture sets.

image

You can also enter the support culture sets directly into the textbox as follows:

en-US, en-US; es-MX, es-MX; en-CA, en-CA; fr-CA, fr-CA; zh-TW, zh-TW;

Multiple culture sets are separated by semicolon or line breaks. Culture is separated from UI Culture by a comma within each culture set definition. If both Culture and UI Culture are the same then enter just one culture. UI Culture may be non-specific and defined by two letters of the language (fr, es, en).

This particular example assumes that users in different locales do not share the server culture.

This is all that is necessary to ensure that your application will correctly present and process date, time, calendars, numbers, and currency values in one or more locales.

Localization

Code On Time web application generator performs automatic localization of all standard application resources in the languages matched to the UI cultures. Our elegant localization system makes supporting multiple localized resources exceptionally simple and accessible.

Localization is one of the most complex aspects of application development. Various text fragments are typically dispersed in static application files such as pages, menus, reports, help system. Text messages are also emitted by business rules to report all sorts of errors and instructions to the end users of a web application.

ASP.NET does provide standard means of externalizing application resources and creating localized versions of each resource file. A developer must maintain all resource files in sync and embed references to specific resources whenever a fragment of text needs to be referenced.  In fact a developer has to translate their entire application in the language of resource IDs that are subsequently translated into actual text written in the natural language. If your application is AJAX-based then you need to employ additional resource DLLs to ensure that localized text resources are available to the client scripts, which makes the localization process even more complex. Resource files in ASP.NET web applications have XML format, which requires users to exercise great care when changing them.

We have decided to eliminate the complexity from this necessity.

Every generated Code On Time application includes several kinds of files commonly found in many hand-coded ASP.NET web applications:

  • Ajax Client Library resources (*.js files)
  • Data Controller Descriptors (*.xml files)
  • Web Pages (*.aspx files)
  • User Controls (*.ascx files)
  • Site Maps (*.sitemap files) B
  • Core Library and Business Logic (*.cs or*.vb files)

We use a refreshingly simple and consistent method of localizing the application source code. If you open the generated application source code in Visual Studio or Windows Explorer then you will find a collection of text files that include the names of UI cultures supported in your web application.

The screen shot shows the partial contents of the root folder of a generated application that supports cultures listed in the discussion of a globalization example above.

image

The screen shot shows ClientLibrary.*.txt, Resources.*.txt, and Web.Sitemap.*.txt groups of text files.

The first group defines the localized Client Library resources for all supported locales.

The second group defines localized resources used in the business rules and core library of the generated application.

The third group defines a collection of localized resources found in the Web.Sitemap, the file that describes the navigation hierarchy of the application.

You will find a few other clusters of localized resources if you browse the contents of the project. Notice that all of these clusters are associated with a specific static source file of your project much like Web.Sitemap and its satellite resources.

Let’s take a look inside.

Here is the first three lines from ClientLibrary.en-US.txt.

^About^About^About^

^ActionBarActionsHeaderText^Actions^ActionBarActionsHeaderText^

^ActionBarCancelActionHeaderText^Cancel^ActionBarCancelActionHeaderText^

Next example shows the first three lines from ClientLibrary.fr-CA.txt.

^About^À propos^About^

^ActionBarActionsHeaderText^Actions^ActionBarActionsHeaderText^

^ActionBarCancelActionHeaderText^Annuler^ActionBarCancelActionHeaderText^

This snippet shows the first three lines from ClientLibrary.zh-TW.txt.

^About^關於^About^

^ActionBarActionsHeaderText^動作^ActionBarActionsHeaderText^

^ActionBarCancelActionHeaderText^取消^ActionBarCancelActionHeaderText^

You have probably noticed the pattern that includes localization brackets on both sides of a localized resource. A localization bracket must start and end with “^” and may contain any combination of alphanumeric characters, such as ^About^, ^Label1^, and ^23^. We call the combination of matching brackets and text between them a localization token.

Here is an example of localization tokens SiteHome, HomePath, and HomeDesc found in Web.Sitemap.

  <siteMapNode url="~/Default.aspx" title="^SiteHome^Home^SiteHome^" description="">
    <siteMapNode title="^HomePath^Home^HomePath^" 
description="^HomeDesc^Application home page^HomeDesc^"
url="~/Pages/Home.aspx" />

Sample code using localization token RecordChangedByAnotherUser is shown next. Method Replace of class Localizer automatically adds “^” to the localization token name and wraps it around the text fragment. This class is the core class of your application. You may find yourself using Localizer.Replace if you need to write a custom business logic in a multi-lingual web application.

if (result.RowsAffected == 0)
{
    result.RowNotFound = true;
    result.Errors.Add(Localizer.Replace("RecordChangedByAnotherUser", 
"The record has been changed by another user.")); }

You can see that the localization token name is present along with the default text fragment in both use cases. This makes it much easier to understand the intended result. Your web application will remove the localization token at runtime and try to find the resource associated with the token in a file matched to the current web request UI culture. If the localized resource is found then it is used in place of the default value. If the exact match of a specific culture such as “fr-CA” is not found then the localizer will try to see if there is a file that matches a non-specific culture “fr”.

All resource text fragments of the core server and client libraries are written in English. Your can replace them if you change the localization files with the corresponding culture. For example, if your culture is en-US then change the files that end with *.en-US.txt to replace the default English fragments. Do not change the corresponding source code files directly.

If you change the value between localization brackets and save the file then you have effectively changed the localized text representation of the corresponding physical resource of your web application. Simply run your application and observe your changes to resource files in action.

If you application is based on a Visual Studio solution file (if you are developing a Web App Factory, Azure Factory, or SharePoint Factory project) then you will need to compile your application.

Files ClientLibrary.*.txt are not a part of your application. The web application generator will use the contents of these files to customize the JavaScript library of your application. If you change any definitions in ClientLibrary.*.txt file set then make sure to re-generate your project for the changes to take effect. Make sure to hit Refresh button of your browser to ensure that the most current version of localized resources is loaded in the web browser window.

Other localization file sets found in your project must be deployed along with the application.

Localization files found in the class libraries of your project (applies to Web App Factory, Azure Factory, SharePoint Factory) will have the culture component in the file name using “_” instead of “-“.

Here is a brief description of all standard localization files sets.

File Set Folder Description
ClientLibrary.*.txt ~/ JavaScript Client Library resources.
Resources.*.txt ~/ Resources used in the core application classes and business rules of application.
Web.Sitemap.*.txt ~/ Text and description of navigation nodes presented in application menu.
aspnet_Membership.xml.*.txt ~/Controllers Membership manager resources.
aspnet_Roles.xml.*.txt ~/Controllers Role manager resources.
TableOfContents.ascx.*.txt ~/Controls Text fragments used in the standard table of contents that presents the site map as a tree.
Welcome.ascx.*.txt ~/Controls Text fragments used in the welcome message.
Home.aspx.*.txt ~/Pages Resources definitions found in the home page.
Membership.aspx.*.txt ~/Pages Resource definitions found in the membership manager page.
Template.xslt.*.txt ~/Reports Resource definitions used in RDLC report template.

Modified localization files are preserved by web application generator. If a new localization token is introduced in the core library and you have an existing application that does not have such a token then the code generator will insert the token in the file with value equal to the default text fragment from the code generation library.

Multiple Cultures / Languages

Your application may support any number of user interface languages with the same code base. The application framework offers easy-to-use localization of static resources and simple API to render localized messages produced by your custom business rules.  We have shown examples of localized static resources and business rules in the previous topic.

This capability is available in the Unlimited edition of Code On Time.

Automatic Translation

Wrap localization brackets around any text. Web application code generator will perform full translation in all languages supported by your application.

For example, the screen shot below shows the list of fields in Customers data controller. You can see that the field labels in the third column from the right have been changed to include localization brackets. Numerical and named tokens such as ^ContName^ and ^3^ are being used for localization.

image

We have also changed various text properties of Customers page in designer.

image

The following versions of Customers screen are presented if we generate our application and select languages corresponding to fr-CA and zh-TW cultures.

image

image

If you inspect the generated application then you will notice the following new culture sets that were created by Code On Time web application generator.

Localization files for ~/Pages/Customers.aspx

image
Localization files for ~/Controllers/Customers.xml

image

Feel free to open any of these text files to refine the localized text fragments. Generated applications monitor localization files and will start using the fresh content when you save the changes.

Language Detection

Code On Time web applications will automatically detect the supported culture. If the client browser culture is supported by your  app then the appropriate localized resources are utilized to render the pages without any user involvement.

Web browsers send language preferences to web servers with each request. Culture manager of the generated web application will automatically match a supported culture set with the languages accepted by the user’s browser. If a match is found then the culture set is automatically selected.

If the matching culture is not found then the application will use the default culture set of your application that was selected on Globalization and Localization page of project wizard.

Language Selector

Membership bar offers a list of languages supported in your application with native names presented to application users. Language selection is automatically memorized and maintained with a sliding expiration.

Language selector complements automatic language detection.

We Need Your Help

Automatic translation of localized resources is performed via Google Translate. The result of translation may not meet your expectations and we apologize for that.

We need your help with creating high quality localized standard resources. If you do make changes to any of the localized files listed below then please contribute your translations to benefit the developer community. You will find additional instructions in ClientLibrary.*.txt files in the root of your applications.

We are looking for assistance with the following files:

  • ClientLibrary.*.txt
  • Resources.*.txt
  • Web.Sitemap.*.txt
  • aspnet_Membership.xml.*.txt
  • aspnet_Roles.xml.*.txt
  • TableOfContents.ascx.*.txt
  • Welcome.ascx.*.txt
  • Home.aspx.*.txt
  • Membership.aspx.*.txt
  • Template.xslt.*.txt

Your contribution will be included in the general distribution of the code generation library. We will post the names of contributors on our blog with a link to contributor’s website if requested.

Tuesday, May 17, 2011PrintSubscribe
File Upload / Download

Code On Time applications support direct uploading of external files into the database.

Basics

Consider the following database schema based on the Northwind sample available with Microsoft SQL Server. Table Categories features Picture field of type image. This data type allows capturing binary content. The purpose of this particular field is to capture a picture representing a category as suggested by the field name.

image

Generate a Web Site Factory web application with this three tables and navigate to Categories page. The screen shot below shows an automatically created page of categories stored in the database. Field Picture is provided with an automatic preview thumbnail.

image

Users can create new categories and upload category pictures as shown next.

Create a new category record in createForm1 view by selecting New Categories button on action bar.

image

Save and edit the new category and indicate that you want to upload a file.

image

Click Browse button and select the image file. File uploading will start immediately.

image

The file is being uploaded in editForm1.

image

The file has been uploaded as indicated by the message at the top of the page.

image

Note that file uploading works only with existing records. The Picture field is available only in editForm1 and grid1 view.

Uploading of binary content is executed asynchronously. If a record does not exist yet then it is not possible to save a file to the database.  Create a new record first, save it, and only at that time upload any files that must be associated with a record.

Code On Time applications will be offering a delayed uploading option that will work with new records by postponing operation until a new record is successfully stored in the database. Creation of  a new record and file uploading will become one smooth operation.

Capturing Extended File Properties

Generated applications do not limit the type of content submitted by end users. If an Adobe PDF file or Microsoft Word document is uploaded instead of an image then the file content will be saved in the database. The thumbnail will not display a preview in that case. If you were to download the file from the application to your hard drive by right-clicking on the thumbnail and selecting Save Target As option then you will notice the following message.

image

The name of the file is represented as generic CategoriesPicture_27, the file type is unknown, the content type is octet-stream.

The binary file stores the file contents only. The file name and content type are not known.

You can easily remedy the situation by introducing utility fields to capture the file name, content type, and length of the uploaded file. The latter is not strictly needed since the application can determine the size of the file by inspecting the database. File length can be useful if you users need to known the file size prior to downloading the file on their computer.

Change Categories table as shown below. Three new columns complement field Picture in table Categories. We have added columns PictureFileName, PictureContentType, and PictureLength. Make sure to allocate enough space for Content Type field to accommodate very long content types introduced in the latest versions of Microsoft Office.

image

Refresh the meta data of your project and regenerate the application.

Create a new category, select the category in the grid view and start editing category properties. New utility fields are displayed right under the Picture field.

image

Upload any document or image.

Notice that the thumbnail of the uploaded file shows the file extension. The utility fields have captured their corresponding properties.

image

Right-click  the thumbnail, select Save Target As and observe the prompt that may look as follows.

image

The name of the file is correctly suggested in “Save As” dialog. The type of the file is also correct.

If you click on the thumbnail directly then the file will open in the application associated with the file type on your computer.

We suggest that your further customize the data controller in the project Designer as shown in the next screen shot. 

image

All utility fields are marked as hidden in createForm1.

Field PictureContentType is “hidden” in editForm1 and grid1.

Field PictureFileName has its Text Mode property set to Static in editForm1 and grid1.

Field PictureLength is “hidden” in editForm1 and Static in view grid1.

These changes will ensure that utility information is captured and only the file name and file size are displayed as read-only values.

Implementing Virtual Fields to Store BLOB/ FILE Content

The new architecture of the framework in Code On Time applications allows full control of the upload / download processing of binary fields with the data controller business rules.

Let’s create a virtual “Picture” field in Products data controller and store the uploaded files in the external file system folder. Such approach may help to reduce the size of the database and provides developers with total control of the process.

To be continued.

Wednesday, March 23, 2011PrintSubscribe
Using $external() Function in Filter Expressions

Code On Time applications support custom functions in view filter expressions. The new function $external() has been introduced in the latest web application generator update. You can use this function to access values in the URLs of the pages and values of fields listed in Context Fields property of lookup fields.

Consider the EmployeeTerritories table from the Northwind sample database.

Any territory can be associated with an employee only once due to the primary key constraint.

image

Here is the screen shot of the form that allows creating new EmployeeTerritories records.

image

The employee last name is already selected. If a user clicks on (select) link in Territory Description field then an entire set of 53 territories will be presented.

image

Let’s make sure the the territories that are already assigned to a selected employee are not available in the list. For example, if we assign a new territory to employee Davolio then the last territory on the first page  in the list of territories in the screen shot above, Wilton from Eastern region, is not listed along with a couple of other territories.

Start the code generator, click on the project name, click Design button, and select EmployeeTerritories data controller, click Edit, and enter EmployeeID in the input labeled Context Fields under Dynamic Properties section. Save changes.

From now on, the application will pass the value of the selected EmployeeID to the lookup view Territories.grid1 attached to field TerritoryID. If the lookup view has the field EmployeeID then the rows of Territories will be automatically filtered to match the value of EmployeeID selected in the new record.

Well, there is no field named EmployeeID in the table Territories.

Let’s create a filter expression for grid1 view in data controller Territories. Click on Home link in the bread crumbs of the Designer at the top of the page. Select Territories data controller. Activate Views tab and choose grid1. Click Edit button.

Enter the following in Filter Expression property:

$external('EmployeeID') is null or not TerritoryID in (
   select "TerritoryID" from "EmployeeTerritories"
   where "EmployeeID" = $external('EmployeeID')
)

image

Save changes, exit Designer and generate the application, navigate to Employee Territories page, select Davolio in the Employee Last Name field, and click (select) in Territory Description input. You will see a lookup window with 50 records in it. The three records that are already assigned to Ms. Davolio are not presented in the list.

image

Navigate to dedicated Territories page and observe that 53 records are still available there. If you enter a URL parameter EmployeeID with value of “1” in the address bar of your browser and hit Enter key then 50 records will be displayed as well. Your URL may look as the one below.

http://localhost:36745/Pages/Territories.aspx?EmployeeID=1

The filter expression assigned to grid1 view does not work if there is no external filter passed in the page URL or in the Context Fields of the lookup view. This is guaranteed by the first comparison in the expression.

$external('EmployeeID') is null or . . .

The second part of the filter expression will test the TerritoryID to ensure that it is not matched to any territories that are already present in EmployeeTerritories and uses $external(‘EmployeeID’) to further limit the scope of test.

Notice the use of double quotations around field and table names. Please use the appropriate symbol that works with your database server to ensure that application will not be trying to resolve the name against the dictionary of fields of the data controller.

Here is physical SQL statement executed by your application. Note that parameters @p0 and @p1 will be replaced with the value of the EmployeeID passed in a URL or as a context field.

with page_cte__ as (
select
row_number() over (order by "Territories"."TerritoryID") as row_number__
,"Territories"."TerritoryID" "TerritoryID"
,"Territories"."TerritoryDescription" "TerritoryDescription"
,"Territories"."RegionID" "RegionID"
,"Region"."RegionDescription" "RegionRegionDescription"
from
"dbo"."Territories" "Territories"
    left join "dbo"."Region" "Region" on "Territories"."RegionID" = "Region"."RegionID"

where
(
(((@p0) is null or not "Territories"."TerritoryID" in (
   select "TerritoryID" from "EmployeeTerritories"
   where "EmployeeID" = (@p1)
))))
)
select * from page_cte__ where row_number__ > @PageRangeFirstRowNumber and row_number__ <= @PageRangeLastRowNumber