Wednesday, April 30, 2008

How to create a Web Server Control in ASP.Net with Delphi 2007

We were presented with the challenge of creating our own server controls. After some research on the web, we found very few examples regarding how to do this, even less if they are specifically targeted to Delphi.Net 2007.

So, in order to help the next fellow Delphi developer that is presented with similar situations, it is our objective to publish small articles on every new item that we face in our development process as a contribution to the new Spirit of Delphi that is growing in the community.

Special thanks to Feryal Badili for putting this article together. :)

Here is the step-by-step instruction on how to create a simple server control in Delphi 2007.

Well, there are two ways to create web components in Delphi:
1) You can go to 'File-New-Other-Delphi for .NET Projects' and choose 'Web Control Library'.
2) OR, you can go to 'File-New-Other-Delphi for .NET Projects' and choose 'Package'. Then in project manager panel, right click on 'Contains' folder and select 'Add new-Other-Delphi for .NET Projects-New ASP.NET Files' and select 'Web Custom Control'. You may want to use this approach if you would like to have multiple controls in the same package.

The general recommendation is to use the first method to create a web custom control for the first time, it is a lot easier in the long run, believe me.

Delphi will generate the source code for a very simple web control. Let's just try to understand it:

The default name for the file is 'WebControl1.pas' . It is a Delphi unit file and the unit name is really your namespace. You need to remember that because you're going to need it later when you are using the control in your web page!

Under 'Type' section of the code, you will see the following lines:

[DefaultProperty('Text'), ToolboxData('<{0}:MyWebControl1 runat=server>')] MyWebControl1 = class(System.Web.UI.WebControls.WebControl)

Well, what does it mean?
Your class MyWebControl1 is derived from System.Web.UI.WebControls.WebControl.

If your control renders a user interface (UI) element or any other visible element on the client, you should derive your control from System.Web.UI.WebControls.WebControl (or a derived class).

If your control renders an element that is not visible in the client browser, such as a hidden element or a meta element, derive your control from System.Web.UI.Control. The WebControl class derives from Control and adds style-related properties such as Font, Forecolor, and BackColor.

In addition, a control that derives from WebControl participates in the themes features of ASP.NET without any extra work on your part. If your control extends the functionality of an existing control, such as the Button, Label, or Image controls, you can derive from that control.
If you are going to have multiple visual controls in your server component and you wish to inherit the basic functionality of the parent controls, you need to derive your class from CompositeControl class:
MyWebControl1 = class(System.Web.UI.WebControls.CompositeControl)
To learn more about composite controls, see:
http://msdn2.microsoft.com/en-us/library/3257x3ea(VS.80).aspx

The code inside brackets that is generated on top of your class definition is attributes that apply to your class. To learn more about these attributes, see the following link:
http://msdn2.microsoft.com/en-us/library/ms178658(VS.80).aspx

The code generated by Delphi adds a property called 'Text' to your component . Since this property is published, you will be able to see it in the "IntelliSense" or "Code Completion" and object inspector when you use this component in a web page.

As you can see, this property also has some attributes:
Bindable: set it to true if your property can be data bound.
Category: In object inspector, this property will appear under the category(group) that you define.
DefaultValue: Obviously, this is the default value of your property.

You need to define these attributes for each and every property that you want to publish for your component. Also pay attention to the field definition for your property.

Next step is to add your own child controls and render the server control. In order to do that, you need to implement the following procedures:

procedure CreateChildControls(); override; procedure RenderContents(Output: HtmlTextWriter); override;

Here is an example of simple server control that includes only one control (TextBox) and adds one property named 'ShowTime' to the control.

You can use this component in both Visual studio or Delphi .NET.

unit WebControl1;
// To create a more advanced Web Control that supports live data at
// design time, see instructions in the readme file located in the
// 'BDS\5.0\Source\DotNet\dbwebcontrols' directory
//

interface

uses
system.web,
System.Web.UI,
System.Web.UI.WebControls,
System.ComponentModel,
system.Drawing,
System.Data,
system.security.Permissions;

type
///
/// Summary description for the component
///


[
AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level=AspNetHostingPermissionLevel.Minimal),
DefaultProperty('ShowTime'),
ToolboxData('<{0}:OpenItems runat=server>')
]
OpenItems = class(System.Web.UI.WebControls.CompositeControl)
strict private
IsError : boolean;

msgBox : textBox;
FShowTime: boolean;

strict protected
procedure RecreateChildControls(); override;
protected
procedure RenderContents(Output: HtmlTextWriter); override;
procedure CreateChildControls(); override;
public
constructor Create;
published
[Bindable(false),
Category('Behavior'),
DefaultValue(false),
Description('Show the Date and Time')
]
property ShowTime : boolean read FShowTime write FShowTime;
end;

implementation
uses SysUtils;

///
/// Define a public parameterless constructor needed by web controls.
///

constructor OpenItems.Create;
begin
inherited;
isError := false;
end;

procedure OpenItems.RecreateChildControls();
begin
try
EnsureChildControls();
except
IsError := false;
end;
end;

procedure OpenItems.CreateChildControls();

begin
try

Controls.Clear();

// Create a text box
msgBox := TextBox.Create;

if ShowTime then
msgBox.Text := DateTimeToStr(Now)
else
msgBox.Text := DateToStr(Now);

msgBox.BorderStyle := System.Web.UI.WebControls.BorderStyle(1); // Sets border style to 'None'
msgBox.ForeColor := System.Drawing.Color.get_Red;
msgBox.Style.Item['position'] := 'reletive';
self.Controls.Add(msgBox);
except
IsError := false;
end;

end;

///
/// Render this control to the output parameter specified, preserving
/// cosmetic attribute output generation inherited from standard
/// WebControl.
///

///


{$REGION 'Render override'}
procedure OpenItems.RenderContents(Output: HtmlTextWriter);
begin

if not IsError then
begin
// There was no error so far, render all components
try
AddAttributesToRender(output);

Output.AddAttribute(HtmlTextWriterAttribute.Cellpadding,'1', false);

Output.RenderBeginTag(HtmlTextWriterTag.Table);
// The table will be very useful when you have multiple visual controls
// included in your component

Output.RenderBeginTag(HtmlTextWriterTag.Tr);
Output.RenderBeginTag(HtmlTextWriterTag.Td);
msgBox.RenderControl(output);
Output.RenderEndTag(); // end td
Output.RenderEndTag(); // end tr

Output.RenderEndTag();

except
// An error happened, just show a message
Output.Write(' '+ 'Unable to create the components');
end;

end else begin
// An error happened, just show a message
Output.Write(' '+ 'Unable to create the components');
end;

end;

{$ENDREGION}

end.


4 comments:

Bob Swart said...

More examples of ASP.NET custom controls (and user controls) that do something, were given in my article in The Delphi Magazine (example source code available for free), as well as in my ASP.NET and Component Development courseware manuals.
See http://www.drbob42.com/aspnet/

Anonymous said...

excelling article, really useful

Anonymous said...

Nice Tutorial...
But how can I install this Component into the Tool-Palette to use ist in other projects?

Steve J. Laye said...

Very clear informations to create a simple server in Delphi 2007. Symtex are an expert database consultancy and development provider. We live, breath and eat Microsoft SQL Server and .Net programming day and night; really we love it and it's that passion which keeps us at the top.

A painless self-hosted Git service

Remember how a part of my NAS setup was to host my own Git server? Well that forced me to review options and I stumble into Gitea .  A extr...