Monday, 19 July 2010

Developing on SharePoint 2010 (Day 2)

a) SharePoint Server Architecture

server

b) SharePoint Object Hierarchy

object

So as you can see the SharePoint Object model is relatively straightforward. Here we have a very simple slip of code which start from reaching all services of the Farm and navigate through to the item and file level objects.

   1:  foreach (SPService svc in SPFarm.Local.Services)
   2:  {
   3:      if (svc is SPWebService)
   4:      {
   5:          foreach (SPWebApplication webApp in ((SPWebService)svc).WebApplications)
   6:          {
   7:              foreach (SPSite site in webApp.Sites)
   8:              {
   9:                  foreach (SPWeb web in site.AllWebs)
  10:                  {
  11:                      foreach (SPList list in web.Lists)
  12:                      {
  13:                          foreach (SPListItem i in list.Items)
  14:                          {
  15:                              // do something
  16:                          }
  17:                      }
  18:   
  19:                      foreach (SPFile f in web.Files)
  20:                      {
  21:                          // do something
  22:                      }
  23:                  }
  24:              }
  25:          }
  26:      }
  27:  }

Friday, 9 July 2010

Oracle Procedures (version 11.1)

General
Related Data Dictionary Objects
error$ source$  
DBA ALL USER
dba_arguments all_arguments user_arguments
dba_errors all_errors user_errors
dba_object_size all_object_size user_object_size
dba_procedures all_procedures user_procedures
dba_source all_source user_source
System Privileges Related To Procedures
create procedure alter any procedure
  create any procedure
  debug any procedure
  drop any procedure
  execute any procedure
Object Privileges GRANT execute ON <procedure_name>;

Privileges to tables and views granted through roles may not be valid within a procedure. See the section on AUTHID.
GRANT execute ON testproc TO uwclass;
 
Stored Procedure

No Parameters
CREATE OR REPLACE PROCEDURE <procedure_name> IS

BEGIN
  <code here>
END <procedure_name>;
/
CREATE OR REPLACE PROCEDURE no_param IS
BEGIN
  dbms_output.put_line('No Params');
END no_param;
/

set serveroutput on

exec no_param;

Single IN Parameter
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> IN <data_type>)
IS

BEGIN
  <code here>
END <procedure_name>;
/
CREATE OR REPLACE PROCEDURE in_param (mesg VARCHAR2) IS
BEGIN
  dbms_output.put_line(mesg);
END in_param;
/

set serveroutput on

exec in_param('Single IN Parameter');

OUT Parameter
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> OUT <data_type>)
IS

BEGIN
  <code here>
END <procedure_name>;
/
CREATE OR REPLACE PROCEDURE out_param(mesg OUT VARCHAR2) IS
BEGIN
  mesg := 'Single OUT Parameter';
END out_param;
/

set serveroutput on

DECLARE
s VARCHAR2(50);
BEGIN
  out_param(s);
  dbms_output.put_line(s);
END;
/
CREATE OR REPLACE PROCEDURE out_param (mesg OUT VARCHAR2) IS
BEGIN
  mesg := 'Single OUT Parameter';
END out_param;
/

SQL> var x VARCHAR2(30)
SQL> exec out_param(:x)
SQL> print x

IN OUT Parameter
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> IN OUT <data_type>)
IS

BEGIN
  <code here>
END <procedure_name>;
/
CREATE OR REPLACE PROCEDURE inout_param (mesg IN OUT VARCHAR2) IS
BEGIN
  mesg := mesg || ' an IN OUT Parameter';
END inout_param;
/

set serveroutput on

DECLARE
s VARCHAR2(50) := 'This procedure uses';
BEGIN
  inout_param(s);
  dbms_output.put_line(s);
END;
/

Multiple Parameters
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> IN <data_type>,
<parameter_name> OUT <data_type>,
<parameter_name> IN OUT <data_type>)
IS

BEGIN
  <code here>
END <procedure_name>;
/
CREATE OR REPLACE PROCEDURE many_params (
mesg1 IN     VARCHAR2,
mesg2 OUT   VARCHAR2,
mesg3 IN OUT VARCHAR2) IS
BEGIN
  mesg2 := mesg1 || 'Parameter As The OUT';
  mesg3 := mesg3 || 'Returned';
END many_params;
/

set serveroutput on

DECLARE
iparm  VARCHAR2(50) := 'This is the IN ';
oparm  VARCHAR2(50);
ioparm VARCHAR2(50) := 'And This is the IN OUT ';
BEGIN
  many_params(iparm, oparm, ioparm);
  dbms_output.put_line(oparm || ' ' || ioparm);
END;
/
 
Parameter DEFAULT

Procedure Without Default
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> <data_type> <default_value>) IS

BEGIN
  <code>
END;
/
CREATE OR REPLACE PROCEDURE no_default(num_rows PLS_INTEGER) IS

BEGIN
  FOR r IN (SELECT object_name FROM all_objects
            WHERE rownum < num_rows+1)
  LOOP
    dbms_output.put_line(r.object_name);
  END LOOP;
END no_default;
/

set serveroutput on

exec no_default

exec no_default(5);

Procedure With Default
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> <data_type> DEFAULT <default_value>) IS

BEGIN
  <code>
END;
/
CREATE OR REPLACE PROCEDURE with_default (
num_rows PLS_INTEGER DEFAULT 20) IS
BEGIN
  FOR r IN (SELECT object_name FROM all_objects
            WHERE rownum < num_rows+1)
  LOOP
    dbms_output.put_line(r.object_name);
  END LOOP;
END with_default;
/

set serveroutput on

exec with_default

exec with_default(5);
 
Parameter Notations

Positional Notation
exec <procedure_name> (<parameter>,<parameter>);
CREATE OR REPLACE PROCEDURE positional (
min_nr PLS_INTEGER DEFAULT 100,
max_nr PLS_INTEGER DEFAULT 1000) IS
BEGIN
  FOR r IN (SELECT table_name FROM user_tables
            WHERE num_rows BETWEEN min_nr AND max_nr)
  LOOP
    dbms_output.put_line(r.table_name);
  END LOOP;
END positional;
/

set serveroutput on

exec positional;

exec positional(1);

exec positional(1000, 500000);

Named Notation
exec <procedure_name> (<parameter_name> => <parameter>);
exec positional;

exec positional(min_nr => 1);

exec positional(max_nr => 500);

exec positional(max_nr => 5000);

exec positional(max_nr => 10000);

exec positional(max_nr => 50000);

exec positional(max_nr => 999999);
Mixed Notation exec <procedure_name> (<parameter>, <parameter_name> => <parameter>);
exec positional(10, max_nr => 1000);

exec dbms_stats(USER, cascade=>TRUE);
 
Parameter NOCOPY
Note: NOCOPY is a hint ... not a directive ... and may be ignored.

NOCOPY Performance Demo
CREATE OR REPLACE PROCEDURE <procedure_name> (
<parameter_name> NOCOPY <data_type> <default_value>) IS

BEGIN
  <code>
END;
/
-- Note: This first demo shows an example of NOCOPY not working

conn / as sysdba

GRANT execute ON dbms_crypto TO uwclass;

conn uwclass/uwclass

CREATE OR REPLACE PROCEDURE default_out (retval OUT VARCHAR2) AS
BEGIN
  retval := dbms_crypto.randombytes(32);
END default_out;
/

CREATE OR REPLACE PROCEDURE nocopy_out (retval OUT NOCOPY VARCHAR2) AS
BEGIN
  retval := dbms_crypto.randombytes(32);
END nocopy_out;
/

CREATE OR REPLACE PROCEDURE nocopy_test (reps IN PLS_INTEGER) AS
bt1 TIMESTAMP(9);
et1 TIMESTAMP(9);

bt2 TIMESTAMP(9);
et2 TIMESTAMP(9);

outval VARCHAR2(64);
BEGIN
  bt1 := SYSTIMESTAMP;
  FOR i IN 1..reps LOOP
    default_out(outval);
  END LOOP;
  et1 := SYSTIMESTAMP;

  bt2 := SYSTIMESTAMP;
  FOR i IN 1..reps LOOP
    nocopy_out(outval);
  END LOOP;
  et2 := SYSTIMESTAMP;

  dbms_output.put_line('Default: ' || TO_CHAR(et1-bt1));
  dbms_output.put_line('No Copy: ' || TO_CHAR(et2-bt2));
END nocopy_test;
/

-- Note: Tried this with REF CURSORS returning 40K rows with, again, 
-- no measurable difference. But now watch what happens when used in a 
-- demo received from Tom Kyte on 2/9/2007.

CREATE OR REPLACE PROCEDURE p3(x IN OUT dbms_sql.varchar2s) AS
BEGIN
  FOR i IN 1 .. 2000000 LOOP
    x(i) := RPAD('*', 255, '*');
  END LOOP;
  RAISE PROGRAM_ERROR;
END;
/

CREATE OR REPLACE PROCEDURE p4(x IN OUT NOCOPY dbms_sql.varchar2s) AS
BEGIN
  FOR i IN 1 .. 2000000 LOOP
    x(i) := RPAD( '*', 255, '*' );
  END LOOP;
  RAISE PROGRAM_ERROR;
END;
/

set serveroutput on
set timing on

DECLARE
l_x dbms_sql.varchar2s;
BEGIN
  FOR i IN 1 .. 1000000 LOOP
    l_x(i) := RPAD('*', 250, '*');
  END LOOP;
  p3(l_x);
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('count = ' || l_x.count);
END;
/

DECLARE
  l_x dbms_sql.varchar2s;
BEGIN
  FOR i IN 1 .. 1000000 LOOP
    l_x(i) := RPAD( '*', 250, '*' );
  END LOOP;
  p4(l_x);
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('count = ' || l_x.count);
END;
/

Note: If a subprogram exists with an unhandled exception, the value assigned to its OUT and IN OUT formal parameters are not copied into the corresponding actual parameters, the changes appear to roll back. However, when you specify NOCOPY, assignments to the formal parameters immediately affect the actual parameters. So, if the subprogram exits with an unhandled exception, the (possibly unfinished) changes are not "rolled back."

Error Handling With NOCOPY
CREATE OR REPLACE PROCEDURE raise_error (
p_Raise BOOLEAN,
p_ParameterA OUT NOCOPY NUMBER) AS
BEGIN
  p_ParameterA := 7;
  IF p_Raise THEN
    RAISE DUP_VAL_ON_INDEX;
  ELSE
    RETURN;
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    RETURN;
END raise_error;
/

set serveroutput on

DECLARE
p_B BOOLEAN := TRUE;
n NUMBER;
BEGIN
  raise_error(p_B, n);
  dbms_output.put_line(n);
END;
/

CREATE OR REPLACE PROCEDURE raise_error (
p_Raise      BOOLEAN,
p_ParameterA IN OUT NOCOPY NUMBER) AS
BEGIN
  IF p_Raise THEN
    RAISE DUP_VAL_ON_INDEX;
  ELSE
    p_ParameterA := 999;
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    NULL;
END raise_error;
/

DECLARE
p_B BOOLEAN := FALSE;
n NUMBER := 100;
BEGIN
  raise_error(p_B, n);
  dbms_output.put_line(n);
END;
/

DECLARE
  p_B BOOLEAN := TRUE;
  n NUMBER := 100;
BEGIN
  raise_error(p_B, n);
  dbms_output.put_line(n);
END;
/
 
AUTHID
Note: For DEFINER RIGHTS objects execute privileges must be granted directly to the user; not to a role. With CURRENT USER rights can be granted to a role. AUTHID DEFINER (default) stored procedures are executed in environment equivalent to the one you get after SET ROLE NONE. In other words, roles are disabled for PL/SQL and any privileges granted via roles do not apply unless you created the procedure with AUTHID CURRENT_USER, in which case role privileges do apply (but executing such procedures is a bit more expensive because Oracle has to evaluate the privileges on every call).

AUTHID Demo
AUTHID DEFINER (the default)
run the procedure with the rights of the procedure's owner.

AUTHID CURRENT_USER
run the procedure with the rights of the executing schema.
conn / as sysdba

CREATE USER abc
IDENTIFIED BY abc
DEFAULT TABLESPACE uwdata
TEMPORARY TABLESPACE temp
QUOTA 10M ON uwdata;

GRANT create session, create table, create procedure to abc;

conn abc/abc

CREATE TABLE t1 (
mycol VARCHAR2(20));

CREATE TABLE t2 (
yourcol NUMBER(10,2));

CREATE TABLE t3 (
ourcol DATE);

conn uwclass/uwclass

CREATE OR REPLACE PROCEDURE definer_test AUTHID DEFINER IS
BEGIN
  FOR rec IN (SELECT table_name FROM user_tables)
  LOOP
    dbms_output.put_line(rec.table_name);
  END LOOP;
END definer_test;
/

CREATE OR REPLACE PROCEDURE cu_test AUTHID CURRENT_USER IS
BEGIN
  FOR rec IN (SELECT table_name FROM user_tables)
  LOOP
    dbms_output.put_line(rec.table_name);
  END LOOP;
END cu_test;
/

set serveroutput on

exec definer_test;

exec cu_test;

GRANT execute on definer_test TO abc;
GRANT execute on cu_test TO abc;

conn abc/abc

set serveroutput on

exec uwclass.definer_test;

exec uwclass.cu_test;

--======================================

conn abc/abc

CREATE OR REPLACE PROCEDURE definer_test AUTHID DEFINER IS

BEGIN
  FOR rec IN (SELECT srvr_id FROM servers)
  LOOP
    dbms_output.put_line(rec.srvr_id);
  END LOOP;
END definer_test;
/

CREATE OR REPLACE PROCEDURE cu_test AUTHID CURRENT_USER IS

BEGIN
  FOR rec IN (SELECT srvr_id FROM servers)
  LOOP
    dbms_output.put_line(rec.srvr_id);
  END LOOP;
END cu_test;
/

set serveroutput on

exec definer_test;

exec cu_test;

GRANT execute on definer_test TO uwclass;
GRANT execute on cu_test TO uwclass;

conn uwclass/uwclass

set serveroutput on

exec abc.definer_test;

exec abc.cu_test;
 
Procedure Demos

Calculate Business Days
CREATE TABLE daterange (
beg_date DATE,
end_date DATE,
biz_days NUMBER(5));

INSERT INTO daterange VALUES (SYSDATE-10, SYSDATE+10, NULL);
INSERT INTO daterange VALUES (SYSDATE-17, SYSDATE+10, NULL);
INSERT INTO daterange VALUES (SYSDATE-22, SYSDATE+12, NULL);

CREATE OR REPLACE PROCEDURE bizdays AUTHID CURRENT_USER IS

CURSOR bd_cur IS
SELECT beg_date, end_date, 0
FROM daterange;

TYPE bDate_tab IS TABLE OF DATE
INDEX BY BINARY_INTEGER;
bdate bDate_tab;

TYPE eDate_tab IS TABLE OF DATE
INDEX BY BINARY_INTEGER;
edate eDate_tab;

TYPE bDay_tab IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
bDays bDay_tab;

NumDays PLS_INTEGER;
TestDate DATE;

BEGIN
  OPEN bd_cur;
  LOOP
    FETCH bd_cur BULK COLLECT INTO bDate, eDate, bDays LIMIT 100;
    EXIT WHEN bd_cur%NOTFOUND;


    FOR i IN bdate.FIRST .. bdate.LAST LOOP
      TestDate := bdate(i);
      NumDays := 0;

      FOR j IN 1 .. (edate(i) - bdate(i) + 1) LOOP
        IF TO_CHAR(TestDate, 'D') BETWEEN '2' AND '6' THEN
          NumDays := NumDays+1;
        END IF;

        TestDate := TestDate + 1;
      END LOOP;


      bDays(i) := NumDays;

      UPDATE daterange
      SET biz_days = bDays(i)
      WHERE beg_date = bDate(i)
      AND end_date = eDate(i);
    END LOOP;

  END LOOP;
  COMMIT;
  CLOSE bd_cur;
END bizdays;
/

Temporary Tables vs. Table Variables

  Temp Table Table Variable
record transaction logs? Yes No
inside transaction scope? Yes No
cross execution batch? Global temp table No way
support index? Yes No
where to store? Tempdb Memory

Thursday, 8 July 2010

Developing on SharePoint 2010 (Day 1)

This article is talking about developing web parts for SharePoint 2010 using Visual Studio 2010. If you are looking for articles for older version of SharePoint or Visual Studio I recommend this URL: http://www.aspfree.com/c/a/Windows-Scripting/Beginning-SharePoint-Web-Part-Development/

First of all, there are two types of web parts VS 2010 supports: Standard Web Part (which in VS 2010 Item Template list named Web Part) and Visual Web Part.

A standard web part is just a class inherited from abstract class WebPart. Below is the Inheritance Hierarchy of WebPart class.

   1:  WebControl
   2:  |---Panel
   3:      |---Part
   4:          |---WebPart

To add contents into standard web part we need override the CreateChildControls method and inside put code logic to create sub controls manually and add them into the Controls collection. See the code below:

   1:  protected override void CreateChildControls()
   2:  {
   3:      LiteralControl msg = new LiteralControl("test");
   4:      this.Controls.Add(msg);
   5:  }

The visual web part, in the other hand, give you a visual design UI to drag existed web control in. But if you check the source code, a visual web part is just a standard web part plus a Web.UI.UserControl. And in the overrided CreateChildControls method used a trick like this:

this.Controls.Add(Page.LoadControl(_controlPath));

One more thing for visual web part: the value _controlPath is the physical URL of the user control and the value of it is maintained by VS 2010.

Monday, 10 May 2010

How to convert UTF-8 to urlencoded string

As you know, System.Web.HttpUtility.UrlEncode can easily convert UTF-8 string into the format of %xx%xx so it can be used in a URL string. Now imagine you are not working on a ASP.NET project and you don’t want to add reference of System.Web.dll in your project, then how can you do the same thing? Below is one solution I found:

   1: private static string GetEncodedString(string username)
   2: {
   3:     StringBuilder sb = new StringBuilder();
   4:     byte[] btyes = System.Text.Encoding.Default.GetBytes(username);
   5:     for (int i = 0; i < btyes.Length; i++)
   6:     {
   7:         sb.Append(@"%" + Convert.ToString(btyes[i], 16));
   8:     }
   9:  
  10:     return sb.ToString();
  11: }

Now if you pass in chinese string 你好 it will turn out %c4%e3%ba%c3, which is exactly what I want. The reason I create this method is because I am trying to use HttpWebRequest component to directly post data to a web page and I need a way to submit UTF-8 string.

BTW, the only difference between my method and UrlEncode is my method will convert all characters in the passed in string to %xx format even it is ASCII but UrlEncode won’t do that.

Monday, 12 April 2010

Star Schema, Snowflake Schema and others

The star/snowflake schema is a way to implement multi-dimensional database (MDDB) functionality using a mainstream relational database.

Star schema resembles a star, one or more fact tables are surrounded by single level dimension tables (one completely de-normalized table per relationship). Dimension tables aren't normalized - that means even if you have repeating fields such as name or category no extra table is added to remove the redundancy.

Snowflake schema resembles a snowflake because comparing with Star Schema the dimension tables are further normalized or have parent tables.

Either way the fact tables are usually designed in third normal form because all data depends on either one dimension or all of them, not on combinations of a few dimensions.

Star Schema vs. Snowflake Schema

The reason for using a star schema is its simplicity from the users' point of view: queries are never complex because the only joins and conditions involve a fact table and a single level of dimension tables, without the indirect dependencies to other tables that are possible in a better normalized snowflake schema.

Snowflake schema generates more joins than a star schema during, which translates into longer queries. Therefore it is normally recommended to choose the star schema design over the snowflake schema for optimal performance.

Snowflake schema does have an advantage of providing more flexibility.

Disadvantage of Star Schema

A well designed database has to be in 3NF whereas the star schema's dimensions are de-normalized. Normally a huge number of redundant data existed in dimension tables.

For improving query performance many pre-processes (sum, grouping, resort etc) have been done on the dimension’s purpose and saved in the dimension table. When business logic changed to modify the related pre-processes are always hard.

When create new dimension table and build relationship with fact table, it can cause geometrically fact table size increasing.

How to Index Star/Snowflake Schema Data
Declare a primary key in each dimension table.
For star dimensions, declare foreign key (FK) relationships between each dimension table and the corresponding fact table. Additionally, for snowflake dimensions, declare FK relationships between each secondary dimension table and the primary dimension table that it augments.
Make sure that there is a primary key associated with the fact table(s), even if you have to use an IDENTITY field.
Declare indexes on each of the primary keys in the dimension tables and in the fact table(s).
Declare indexes on each of the foreign keys in the fact table(s).

Sunday, 14 March 2010

WTF: UAC and rsAccessDenied error in Windows 2008 R2 (x64)

Here is today’s WTF, imaging you spend whole day installed SSRS and finally start creating your first report service, but when you are trying to deploy it you keep receiving error message regarding denied accessing, it is really confused me.

This is not the worst part yet, if you google the error type [rsAccessDenied] you can find the solution is accessing http://localhost/reports/ and assign proper user roles to the report service login user. But when login http://localhost/reports/ in Windows 2008 R2, you can see only a blank home page without any settings you can work with. This is because UAC blocked the dynamic content in this page. Even I added the URL to trusted site list, you can still only see a blank page, which really piss me off.

To overcome this issue, you have to turn off UAC and restart the computer, and then access http://localhost/reports/ you can see all the functionality you need.

Followed are some tips installing SSRS 2008 x64 on Windows 2008 R2 x64

First thing first I strongly suggest installing VS2008, SQL SERVER 2008 in the default path, otherwise you will suffer installation failure soon or later, especially for the Business Intelligence Development Studio.

Another thing you need know is Report Service is no longer relying on IIS. Even you stopped IIS service you can still access Report Service from URL http://localhost/Reports and http://localhost/ReportService.

Assuming you have already installed SSRS 2008 with SQLSERVER 2008, next step is configure database connection. To do this go to Microsoft SQL Server 2008/Configuration Tools/Reporting Service Configuration Manager, then click database page and connect the database server you want. The reporting service manager will create two databases ReportServer and ReportServerTempDB for itself.

Another thing you may need to know is the SSRS report web service asmx URLs are:
http://localhost/ReportServer/ReportService2005.asmx (to manage the service)
http://localhost/ReportServer/ReportExecution2005.asmx (to create reports)
Even you installed MSSQL2008 the services are still named 2005, isn't it kind of WTF. :)

Monday, 8 March 2010

SILVER - An easy way to remember asp.net lifecycle

S – Start
I – Initialize
L – Load
V – Validate
E – Event Handling
R – Render

Haha,really easy to remember.

Wednesday, 24 February 2010

TransactionScopeOption.Suppress

As you may know, Suppress scope will suppress the current ambient transaction, and if there is no ambient transaction present, it will not create any transaction at all.

But there is one thing you may not know, which is, if there is another TransactionScope further down the stack it will react as if there was no ambient transaction (and create one if necessary).

So if you have 3 scopes as follows: .Required -> .Suppress -> .Required: Then 2 transactions will be created. The innermost TransactionScope with .Required will see that there is no ambient transaction and will creates one for itself.

One thing to remember, to keep the code consistence, always call scope.Complete() at the end of your suppress TransactionScope even you know logically there will be no transaction created. There will be no any overhead caused by doing that.

Friday, 19 February 2010

101 LINQ Samples

No extra words, see the link below from Microsoft which covered all the knowledge you need to create any complicated Linq to SQL query.

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

Diagrams of determining the dimensions of elements

offsetWidth/offsetClient and clientWidth/clientHeight from Mozilla



offsetWidth/offsetClient and clientWidth/clientHeight from Microsoft


Sunday, 31 January 2010

ViewData vs. TempData

ViewData and TempData are both used to pass data from Controller into View in ASP.NET MVC model. This article is trying to point out their's difference.

ViewData is only available in current request but TempData, which stored in user session, whose life will be around current and the right next requests. In the other word, if you are trying to share data between two continued request or during a redirection then TempData will be your choice.

BTW, to ensure you get the data by either ViewData or TempData you can use the code
<%=ViewData["name"] ?? TempData["name"]%> 

Tuesday, 26 January 2010

List<T> working with DataGridView

As you all know you can bind a List<T> into a DataGridView in .net 3.5. The DataGridView even automatically allows you to edit the bound List<T> data. But there are still some tips when working with DataGridView. This article is a quick guide to let you know how to make this kind of generic binding working properly even when you programmatically changing the source data.

Case 1: when you edited the data in a bound List<T>, simply call DataGridView.Refresh() to allow you changes be shown. Or you can set the DataSource of the DataGridView to null and reset the DataSource to the List<T>.

Case 2: when you added or removed records from the List<T> then you cannot refresh the DataGridView to see your changes, in this case you have to re-bind the DataSource (by re-bind I mean set the DataSource to null and then set it back to the List<T> otherwise the re-bind will not happen since the DataGridView will think the datasource didn't change)

Case 3: When you directly bind a List<T> to a DataGridView you will find it doesn't allow you adding or deleting record from the UI even you set the AllowUserToAddRows and AllowUserToDeleteRows. To allow you do these things in DataGridView UI we are going to use another Type BindingSource which implemented related interface to allow DataGridView add/edit/delete data from its data source. The sample code:

List<T> data = new List<T>();
BindingSource binding = new BindingSource();
inding.DataSource = data;
DataGridView.DataSource = binding;


Go back to Case 1 and 2, when you are using BindingSource instead of directly use List<T> now you have another way to refresh your DataGridView, BindingSource.ResetBindings(bool) which forces the DataGridView to reread all the items from the List<T> and refresh their displayed values.

Wednesday, 20 January 2010

How to add a Form into Tab control

Sometimes for reusing your old code you may want to add a form instead of a user control into a tab. To do so you need modify some properties of your form otherwise your form may not be showing properly.

The properties are:
FormBorderStyle = None; //remove the form border and title area, make it like a flat piece
TopLevel = false; //TopLevel control cannot be embeded
WindowState = Normal; //If you are going to set the Dock value, WindowState cannot be Maximized

The last thing is do not forget call form.Show(), otherwise the form is not going to render itself.

Tuesday, 12 January 2010

How to set K2 login model for Joomla 1.5

If you are not a patient man just like me then this article gonna help you.

Step1, download K2 full package and install it
Step2, enable K2 login model
Step3, assign existed user to K2 user group
Step4, to let the user publish new items, you have to change the related K2 user group to allow item editing, add items, editing level (All or Own), and publish items

You can ignore all the other settings and log in as the user, and then you can see a link Add New Item below your login user name now.

In case you want to know more about implement K2: A quick step-by-step guide on installing and setting up K2.

Monday, 25 May 2009

SQL Server Date Time Functions

GETDATE()
Returns the current system date and time in the SQL Server standard internal format for datetime values.

DATEPART(datepart, date)
Returns an integer that represents the specified datepart of the specified date.

DATENAME(datepart, date)
Returns a character string representing the specified datepart of the specified date.

DATEADD(datepart, diffNum, date)
Returns a new datetime value based on adding an interval to the specified date.

DATEDIFF(datepart, date1, date2)
Returns the number of date and time boundaries crossed between two specified dates.

Year(date), Month(date), Day(date) are working exactly same with DATENAME(year/month/day, date)

The param datepart is the parameter that specifies on which part of the date to calculate the difference.

Saturday, 16 May 2009

ASP.NET page event ordering

  • Master page child controls initialization: All server controls contained within the master page are first initialized.
  • Content page child controls initialization: All server controls contained in the content page are initialized.
  • Master page initialization: The master page itself is initialized.
  • Content page initialization: The content page is initialized.
  • Content page load: The content page is loaded (this is the Page_Load event followed by the Page_LoadComplete event).
  • Master page load: The master page is loaded (this is also the Page_Load event followed by the Page_LoadComplete event).
  • Master page child controls load: The server controls on the master page are loaded onto the page.
  • Content page child controls load: The server controls on the content page are loaded onto the page.

UML class diagram notation

Untitledxx

Monday, 11 May 2009

Easy AJAX Callback Using ASP.NET ClientScriptManager

What I am going to show you is a fast, safe, easy way to create an AJAX callback process without manually write any JavaScript code regarding creating and handling XMLHTTPRequest object. The key is to use ASP.NET ClientScriptManager.

I will show you the sever side code first and explain to you what these code will do.

   1:  // Code behind
   2:  protected void Page_Load(object sender, EventArgs e)
   3:  {
   4:      string js = Page.ClientScript.GetCallbackEventReference(
   5:          this, 
   6:          "arg", 
   7:          "ClientCallbackFunction", 
   8:          "ctx", 
   9:          true);
  10:   
  11:      StringBuilder sb = new StringBuilder(); 
  12:      sb.Append("function DoTheCallback(arg, ctx) {"); 
  13:      sb.Append(js); 
  14:      sb.Append("}"); 
  15:      
  16:      Page.ClientScript.RegisterClientScriptBlock(
  17:          this.GetType(), 
  18:          "callbackkey", 
  19:          sb.ToString(), 
  20:          true); 
  21:  }

The first part in the code (line 4 to 9) is creating the JavaScript code which will try to invode ASP.NET AJAX engine, which will maintain a XMLHTTPRequest object for us. In line 7 we specify the callback JavaScript function name is “ClientCallBackFunction”. In line 9 we specify the AJAX calling is asynchronous. In line 6 and 8 we specify the return variable name and context variable name (I will explain this later).

In the 2nd part (line 11 to 20) we are creating the JavaScript code string which is the entry of our client side AJAX call. Line 11 to 14 are building the JavaScript code including function name, parameters, and join the code we created in the 1st part as the content of our new function.

From line 12 you can see our AJAX method has two parameters: arg and ctx. The names have to be the same string we used in line 6 and 8. I will show you the created html code and you will know why.

   1:  <script type="text/javascript"> 
   2:  //<![CDATA[
   3:  function DoTheCallback(arg, ctx) {
   4:      WebForm_DoCallback('__Page',arg,ClientCallbackFunction,ctx,null,true)}//]]>
   5:  </script>

By doing above things we have finished the hardest part. Now it is time to make our aspx page support client call back. To do so we need the Page class implement ICallBackEventHandler interface.

   1:  public partial class Ajax : System.Web.UI.Page, ICallbackEventHandler
   2:  {
   3:      private string returnValue = string.Empty;
   4:   
   5:      #region ICallbackEventHandler Members
   6:   
   7:      public string GetCallbackResult()
   8:      {
   9:          return "the result you want to pass to client";
  10:      }
  11:   
  12:      public void RaiseCallbackEvent(string eventArgument)
  13:      {
  14:          // handle the eventArgument value to different things
  15:      }
  16:   
  17:      #endregion
  18:  }

ICallBackEventHandler has two methods, the RaiseCallbackEvent method will fire first when client-side calls the AJAX method we created and inside this method we have a chance to handle different call based on the different eventArgument values.

Then the GetCallbakcResult method will be called at here you can return any string value you want. Since RaiseCallbackEvent and GetCallbakcResult are separate we have to find a way to share data between them that is why I declared a private string variable returnValue at line 3. By using so I can set the value by a proper value in RaiseCallbackEvent and return the value in GetCallbakcResult.

Note: the client side DoTheCallback method’s 2nd parameter will never be used in server side, the AJAX call will return exactly the same value to the callback method “ClientCallBackFunction”.

The last thing to do is create a callback function we declared at part one which will handle the AJAX callback call.

   1:      function ClientCallbackFunction(arg, ctx, a, b, c, d, e) {
   2:          //do your client stuff here
   3:      }

The callback method will receive only two parameters, the first one always the return value and the second one always the context string which we passed in when we begin the AJAX call. You can check the values for parameters a to c and they are always null.

ALL DONE. :)

Tuesday, 21 April 2009

Creating Tableless Sites - Why and Some Basics by Nicole Hernandez

In a time of web developers who just like to say that ‘Tables are Evil’ and can’t (or won’t) explain why, this article will attempt to give you some solid reasons that people create tableless designs. Included are six major benefits of creating tableless sites, and how to sell your desire to alter your website to a resistant manager.

Let’s begin with the benefits of a tableless layout. These are only in the order that I feel they should go in, some things are more important to other people, so rank them as you will.

Forces You To Write Well-Formed Code

You cannot have a properly made tableless layout, and use improper and non-standard code. Well, let me correct that - you can (technically you can do it) but it defeats the whole purpose. When you are creating a tableless design, you should be using standards compliant code. I think that anything that makes you get into the habit of always writing clean code is a good thing.

Faster Loading Time

This is absolutely a benfit of a tableless layout, and for several reasons. First, on a fundamental level - tables load slowly. For the most part, unless you set the height and width of your table elements, all the text has to be loaded and rendered BEFORE the table sizes itself to the page. Of course, this is what so many people loved about tables isn’t it? The fact that they were so easily sizeable. The downside is how much more time they take to load.

Okay, so the solution to that loading time is to set all the values explicitly, right? So now we see another downside. Code clutter that increases loading time. First of all, just by themselves, tables take alot of code. How many td open and close tags does your average table based layout have? Tons. Having to set all the values explicitly only adds to the page size and loading time. There are many experiments that have been done on this topic, I’ll point you toward this one that StopDesign did on a remake of the Microsoft website from a tablebased site to a tableless layout. That remake showed a 62% file size reduction of the site, and using their average hits per month for the Microsoft site, calculated that Microsoft would be saving 924 GIGS in bandwidth per day, and 329 Terabytes of bandwidth per year. For any company that pays for bandwidth, these things are important.

Easier to Read Code

If you are using standard code, semantic document conventions, and a tableless layout, your code can be so clean that it looks practically like just regular text with a few extra symbols.

That is a great benefit because it not only makes it easier for you to update, but it makes it easier for a non-technical user to make small alterations to. Additionally, if you work as a web developer in a more freelance capacity, it is common for there to be a full-time web developer who has to maintain that site. Clean and simple to read code makes that a easy transition. We like it when people leave us easy to understand code, right? Let’s return the favor.

Print Alternate Views

When you create a page using a table-layout, you are rather unfortunately locked into a certain layout. Developers who have created table-based websites, as most of us have at some point - particularly if you were in the the industry before the big tableless movement, know that you often have to create a separate printable version of your pages. This can be, needless to say, quite tiresome.

Ease of printing style control is a huge benefit with a tableless layout. You can easily create a single new printing style that applies to all your pages, instead of making them individually. That alone is a huge time saver, but there is more.

While you can control all elements with this approach, the biggest key is organization of information within the page itself. Using the example, let’s assume that the display order we want all our pages to print using the following order: The page header first, the content next, the special news after that, then the link list, and then the footer. However! We still want it to display as it would normally when viewing (meaning the header at the top, the links on the left, content in the middle, news on the right, and footer at the bottom). With a table-based layout, you would have to create a new page to do that special printing organization because the print style will read your columns left to right. With a table-less layout, you are not bound by this. You can order the content in your page however you like, and still control the way it looks… all by using the CSS only!

Additionally, because we can put the content in whatever order we want in the HTML, and then move the content blocks around for website viewing using CSS - we can have ultimate control over presentation.

That is very important because the clean code, and ability to alter presentation, means that your site can be viewable by someone on a small mobile phone screen, a PDA, in all text format can be perfect for someone using a text-to-speech reader, or a braille device, and since the code is clean, it is both backward compatible (with older browsers seeing mostly just the text) and forward compatible with new technologies to come. The flexibilty and organization leads to being able to create a powerful website that takes advantage of some of the possibilities with XHTML, and adding in support in your pages for microformats, or taking advantage of using RSS / ATOM feeds from your site to develop a base of regular readers.

Search Engine Optimization

Due to the fact that you can organize your most important content at the top of your page, without affecting the layout, your page can be better optimized for search engines. For instance, say that I have a navigation bar on the left side of the page that lists tons of parts of the site that are actually great keywords. I could move that navigation bar code higher up in my actual HTML, without changing the layout, because I’m using the CSS to position the navigation where I want it.

Those search engines can also more clearly find common words throughout your document without having to filter through code. Search engines prioritize websites that have a higher content to code ratio, so putting all your style elements into your external CSS stylesheet makes your site highly content based to a search engine. Tableless layouts, as previously mentioned, decrease page size and loading time - another bonus to search engines.

Additionally, being able to take advantage of the RSS/ATOM feeds (see the section directly above) will aid you in some new technology for site indexing as used by all search engines called ROR. (ROR is an XML format summary of your website, like a sitemap, that search engines can access for additional information about your website.)

Presentation Flexibility

Making changes to a CSS based Tableless layout is simple. You can alter the CSS file only, changing as many styles and graphics as you want. The affects cascade through all the pages on your website, and eliminate the need for manually updating many pages.

For one of the best known examples of how powerful presentation can be, you can visit the CSS Zen Garden and navigate through the ‘Select a Design’ links to see the differences. Each of the different designs uses exactly the same HTML file content. The only thing that changes is the CSS file for each one.

Selling Yourself On Standards

Sometimes knowing how to code for standards, and create flexible tableless layouts is not enough. There are some web designers who meet with difficulties from their management. Most often those difficulties are rooted in the management being unaware of the benefits of using tableless content and CSS driven layout.

If you want to design for standards, but you work for a company that is not very forward-thinking in allowing you the time to work on the changes — try this: Make them think about their pocket-book. Point out the cost saving benefits.

For instance, try grabbing a single page of existing code. Clean it up to standards. Compare the page size to before (including image optimization), and count the difference in bytes saved. Multiply that across the number of site pages, and the number of days per month. Then explain to them the amount of bandwidth cost saved monthly if this was done across the whole site. If that isn’t enough, show them how quickly you can make changes to a website once it is CSS driven, and push the idea that you will be able to change the site more rapidly when there are needed updates, and you will have more time to focus on adding in new functionality to the site - instead of spending your time doing maintenance.

Summary Hopefully, this little article will serve as a way to get you started on understanding why to use a tableless layout, what the benefits are, and you can easily take a look at Layout Gala and download just 1, or all 40 of the tableless layout examples to get you started. However, the best step toward moving to a tableless design is to slowly move your website toward a standard compliant version first, before you get rid of the tables. To get to that point, study as much on CSS as you can, read through the articles here and elsewhere on the web, and moving from table layouts to tableless will be just a matter of time.