about |
download |
install |
reference |
faq |
tips&tricks |
about security
- what is xxm
- xxm is an interface written with and based on Delphi that compiles
HTML with embedded Delphi code into a library, ready to use either locally,
in the xxm ISAPI extension or other configurations.
- what does xxm stand for
- extensible expandable modules... or transportable transformation modules... anyway something fancy like that.
- how do I get started
- Use xxmProject.exe to start a new project in a directory. Register the project with xxm.json for xxmHttpDev.exe to host it. Use a browser to open
http://localost/<your project's name>
. Add pages by creating extra .xxm
(and .xxmi
) files to the directory.
There is also a step-by-step tutorial with screenshots that shows how it's done.
- I'm using Delphi Community Edition that does not include the command line compiler
- Use this tiny tool instead, that calls BDS.exe with the command line parameters to compile the project, and transfers the output in the same format xxm expects it. It's advised to disable the "Show compiler progress" option, or the IDE might remain open in the background when the project has a compile error.
- does an xxl module need to be an ActiveX/COM/OLE library
- no, an xxl library doesn't have to contain a Type Library and
export the default procedures that a ActiveX/COM/OLE library would.
- has CoInitialize been called for the thread the page is built in
- yes
- why does Context.SessionID generate an EXxmResponseHeaderAlreadySent exception
- Context.SessionID was inteded to use in XxmProject.LoadPage,
when a new session is started, a session cookie is set. When you don't use
Context.SessionID from LoadPage, and use it later on, the SetCookie can't
add to the response headers.
- why do I get this error:
Error: ',' or ';' expected but identifier 'xxmFReg' found
- You need to end the list of units in a
[[@Unit1,Unit2,]]
section with a comma. This is because in proto/xxm.pas
and proto/xxmi.pas
templates, this section is inserted here:
uses SysUtils, [[UsesClause]] xxmFReg;
syntax requires a comma after each unit, so of you provide one or more units, you have to provide the closing comma.
- is it better/faster/... to use Context.SendHTML whereever possible?
- No. HTML is parsed into Context.SendHTML calls for you, and doesn't take as much time extra as it would take you to type the HTML in Delphi string syntax. By far. The compile time of both is virtually equal. The execution time is equal.
- can I use SaveToStream on object to write to the Context directly
- Not directly, but the
public
folder that holds the xxm.pas
file defining the main xxm interfaces, also holds a file xxmStream.pas
that defines a TxxmOutputStream
object, that inherits from TStream and takes a IxxmContext pointer.
- does xxm work with jQuery and prototype?
- Yes. These are javascript libraries, and javascript is able to resolve relative URL's, even with an XmlHttpRequest. Prototype may need a minor tweak to work with the xxmLocal handler in InternetExplorer, since as a security measure the responseDocument property is undefined on non-http protocol handlers.
- when using an AutoBuild handler, pascal compile errors get shown with the line-number of the parsed source file, not the xxm source file, how do I map between the two?
- as of version 1.0.2.260, the xxm parser keeps line-number maps for each file, and AutoBuild handlers use these to replace the line number of the compiler output (shown between parentheses "
()
") with the corresponding line-number(s) of the xxm source file (shown between square brackets "[]
"). Since several tags from different places in the xxm-sourcefile could end up on the same line (e.g. all [[@someunit,]]
tags are added to the implementation uses clause) more than one xxm source line-number could be displayed.
- why would I use
Context.Include
, when I can create a fragment and call its Build(Context,Self,[],[]);
myself?
- I'll give three good reasons:
Exception handling: xxm handlers keeps track of which fragment is building, and adapts the default exception display to display information about the fragment the exception occurred in.
Include depth checking: xxm handlers keep a count of 'include depth' and disallows includes beyond a certain depth, this protects you from 'include loops', a scenario that just might pop up when which fragment to include is getting a but elaborate.
Fragment registry: xxm handlers use the fragment registry (actually IxxmProject.LoadFragment
) to get hold of a fragment object, and doing so allows the fragment registry to handle object-pooling and object-reuse (if you'd like, in fact you're free to choose the fragment registry implementation for an xxm project).
Then again, if you really don't care about the above, you're totally free to call TxxmFragment.Build
yourself.
- why does the Redirect method have a
Relative:boolean
parameter?-
- short story: to make you think.
Long story: though it is theoretically possible to infer from a URL if it's relative or absolute,
in most cases, whether it is or not, is fixed by design.
For example a page posted to by a form, uses something like Context.Redirect('Product.xxm?id='+IntToStr(id),true);
to display the result,
or a website that forwards to sites with absolute URL's from websites should use Context.Redirect(WebsiteUrlFromDB,false);
.
Also, there's always this thing called security. Providing a page that redirects to a URL posted over a request parameter, is considered a vulnerability, so prevent writing code like Context.Redirect(x,false)
where x
is taken from the request data.
- why is there no
IXxmParameter.AsBool
or IXxmParameter.AsDate
?
- I couldn't decide on a default encoding for dates and booleans. For booleans I generally use
b:=Context['b'].AsInteger<>0;
and dates I pass either as an integer or double cast to and from a TDateTime
- why does my website show a build failed error message on one page when I'm browsing to another page?
- it's a side-effect of using a compiled library to run the website for you. If the auto-build fails (auto-build is triggered by any page-refresh to the site, even AJAX-calls and image-loads), the library isn't loaded and the build failed page is shown, for every request to the site. It's strongly advised to use a single instance of the website source-files to work on for each developer. If you work on the same set of files with a number of developer's, each build failed error caused by one developer will interrupt the testing of the other developers. (It's also strongly advised to use a version control system on the source-files between multiple developers. e.g. SVN or Git)
- can I keep sending when a client disconnects
- no. If
Context.BufferSize
is 0, Context.Send
may throw an exception depending on which handler is used.
Most handlers will throw an exception from deep within the underlying data transport system.
If Context.BufferSize
is set to something more than 0, this exception will get thrown
when the buffer is full, or when Context.Flush
is called, and an attempt is made to transmit data.
If you want to maintain a long-running process with the client disconnected, check Context.Connected
whether it is safe to send data.
(Though this will keep one of the threads in the thread-pool occupied and unavailable to process incoming requests.
For long-running processes please use threads you manage yourself, or use another server process with IPC like COM, named pipes or network connections.)
- why do I get this error:
There is no overloaded version of 'Send' that can be called with these arguments
?
IXxmContext
has a few overloads of Send
and SendHTML
so that in most cases you can use the [[=x]]
syntax without much thinking about type, but some types are unclear or ambiguous between the available overloads. In this case use an explicit type cast or an extra local variable
- can I start background threads from the
XxmProjectLoad
function call (i.e. when my xxm project starts) to do background work and/or scheduled tasks?
- you could but you shouldn't. The threads would run from within the web-server context and may impact performance. It's advisable to use COM or other IPC to outside processes running on the web-server (or another server) to have the work done.
If you do though, be sure to also implement the IXxmProjectEvents1
interface on your IXxmProject
implementation (see your project's xxmp.pas
unit) and shut down any worker threads from the ReleasingContexts
method.
- how do I debug an xxm project
- an xxm project is still a Delphi project, so you can open the project's dpr in Delphi, just remember to edit the xxm and xxmi files, and not the pas files directly (unless for temporary debugging behaviour).
When you're using xxmLocal (or xxmLocalDev), set the host application to Internet Explorer (typically C:\Program Files\Internet Explorer\iexplore.exe
), optionally with an "xxm://" URL to open your project. (Update: to force IE8 to run in a single process, see TabProcGrowth)
When you're using xxmIsapiEx (or xxmIsapiDev) on your local IIS, switch IIS into stand-alone mode and use inetinfo.exe as host application, or create a virtual directory with high isolation (IIS 7: in an application pool of it's own), and use %SystemRoot%\system32\dllhost.exe /ProcessID:{AppID}
with the AppID you can pick up from the properties of the COM+ application in the 'Component Services' administrative tool
- how do I support passing extra parameters with the directory delimiter?
(e.g.: http://localhost/xxm/test/test.xxm/a/1/b/2
)
- The URL is parsed to get a project name and a fragment address.
no forward directory checking is done, since xxm files and directories may not be present,
it's up to the project to provide a fragment or not for a fragment address. (xxmp.pas'
TxxmProject.LoadFragment
and the default xxmFReg.pas, see the 'URL Routing' demo in xxm_demo.zip available for download)
- why can't IE download files directly? I get this error:
Internet Explorer cannot download somefile.ext from site.
Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.
- the registry is used to determine which MIME-type to declare for the file. Look under HKEY_CLASSES_ROOT for a ContentType value under the key with the extension (e.g.: [HKEY_CLASSES_ROOT\.txt] @ContentType="text/plain")
- is it possible to update an xxm project without taking the webserver/webservice down?
- yes. When setting up an xxm environment, select one of the auto-update options (xxm*AU.*). These check the directory of the xxm project if a
.xxu
file is provided, then queues new requests until all current requests are completed, unloads the .xxl
library, replaces it with the .xxu
file, re-loads the library and continues processing requests.
- how do I know if auto-update has updated my xxl?
- you know because the
.xxu
file has been renamed to .xxl
to replace the previous file. It is also recommended to have an internal version number display generated from code, somewhere in the project e.g. on an about page or on the page footer.
- do I always need an xxm handler to run an xxm project?
- while it is strongly advised to use the development handlers for development, and the auto-update handlers for the live environment, once you have an xxm project that is stable, you can make a 'skip the handler' build
using
xxmConv.exe
and one of the alternative templates from the conv\proto_*
folders.
These combine xxm source with the generated source of the xxm project into a dedicated dll or exe.
- why did you make another website development platform? think you could do better than the tried and tested ones out there?
- *sigh* please read this: why