- Client and Server-Side Browser Detection
Determining the client's browser and its version can be crucial for ensuring compatibility or delivering specific user experiences. EXT.NET applications can implement browser detection on both the server and client sides.
Server-Side Browser Analysis
On the server, you can inspect the incoming request's browser capabilities to identify the client's browser type and version. This information can then be used to conditionally inject targeted ExtJS scripts into the page, for instance, to display warnings for outdated browsers.
using System;
using System.Web;
using Ext.Net;
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
HttpBrowserCapabilities userBrowser = Request.Browser;
// Check if the browser is Internet Explorer and its major version
if (userBrowser.IsBrowser("IE"))
{
if (userBrowser.MajorVersion < 8) // For IE versions older than 8
{
string updatePromptScript = @"
Ext.onReady(function() {
Ext.MessageBox.confirm('Browser Update Recommended',
'<p style=""color:red;""><strong>Your Internet Explorer version is outdated, which may pose security risks and limit application functionality.</strong></p>' +
'<p>Would you like to upgrade your browser for an enhanced and more secure experience?</p>' +
'<p>If you have recently installed a newer version of IE, please restart your computer.</p>',
function(buttonResponse) {
if (buttonResponse === 'yes') {
window.location.href = '/BrowserSupport/UpgradePage.aspx?action=download';
}
}
);
});";
Page.ClientScript.RegisterClientScriptBlock(GetType(), "OldIeWarning", updatePromptScript, true);
}
}
else // For non-IE browsers, a general informational message might be shown
{
string infoScript = "Ext.onReady(function(){ Ext.MessageBox.alert('Browser Information', 'You are using a non-IE browser. While supported, some legacy features might behave differently.'); });";
Page.ClientScript.RegisterClientScriptBlock(GetType(), "NonIeInfo", infoScript, true);
}
}
}
}
Client-Side Browser Detection with ExtJS
ExtJS provides straightforward boolean properties on the global Ext object for direct client-side browser detection. This method is often preferred for dynamic UI adjustments based on the detected browser.
<script type="text/javascript">
Ext.onReady(function () {
let detectedBrowser = 'Unknown Browser';
if (Ext.isChrome) {
detectedBrowser = 'Chrome';
} else if (Ext.isIE) {
detectedBrowser = 'Internet Explorer';
if (Ext.isIE6) detectedBrowser += ' 6';
else if (Ext.isIE7) detectedBrowser += ' 7';
else if (Ext.isIE8) detectedBrowser += ' 8';
} else if (Ext.isOpera) {
detectedBrowser = 'Opera';
} else if (Ext.isGecko3) { // Specific to Firefox 3.x
detectedBrowser = 'Mozilla Firefox (Gecko 3.x)';
} else if (Ext.isSafari) {
detectedBrowser = 'Safari';
}
Ext.Msg.alert("Browser Check", "You are currently using: " + detectedBrowser);
});
</script>
- Detecting Silverlight Runtime Installation
For applications that integrated Silverlight components, verifying the client's Silverlight installation was a standard practice. Although Silverlight is a legacy technology, this detection method remains applicable for maintaining existing systems.
<script type="text/javascript">
function isSilverlightRuntimePresent() {
let silverlightFound = false;
try {
// Check for Internet Explorer using ActiveX control
try {
new ActiveXObject('AgControl.AgControl');
silverlightFound = true;
} catch (e) {
// Check for other browsers by inspecting navigator.plugins
if (navigator.plugins["Silverlight Plug-In"]) {
silverlightFound = true;
}
}
} catch (e) {
// Any error during detection implies Silverlight is not installed
}
return silverlightFound;
}
if (!isSilverlightRuntimePresent()) {
Ext.onReady(function() {
Ext.MessageBox.confirm('Required Software Missing',
'<p style=""color:red;""><strong>Silverlight 4.0 (approx. 5MB) is not detected on your system.</strong></p>' +
'<p>Key functionalities such as advanced file uploads and interactive charts require Silverlight 4.0 support.</p>' +
'<p>Would you like to download and install it now?</p>',
function(buttonAction) {
if (buttonAction === 'yes') {
window.location.href = '/RequiredSoftware/DownloadSilverlight.aspx?version=4.0';
}
}
);
});
}
</script>
- Implementing File Downloads
A frequent challenge in EXT.NET applications, particularly when using DirectEvents, is orchestrating file downloads. DirectEvents rely on AJAX, and directly streaming a file within an AJAX response is generally not supported by web browsers, often leading to corrupted data or unexpected behavior.
Client-Side Initiated Downloads (e.g., from a Grid Row)
The recommended approach for initiating downloads from user interactions (like a grid command or a button click) is to trigger a client-side redirection to a dedicated download handler. This allows the browser to correctly interpret the response as a file download.
Consider an EXT.NET GridPanel with a command column designed for downloading attachments:
<ext:ColumnModel ID="DownloadColumnModel" runat="server">
<Columns>
<ext:RowNumbererColumn />
<ext:Column Header="Document ID" Hidden="true" DataIndex="DocId"></ext:Column>
<ext:Column Header="Document Name" DataIndex="DocumentName" Flex="1"></ext:Column>
<ext:DateColumn Header="Upload Date" DataIndex="UploadTimestamp" Format="yyyy-MM-dd HH:mm" />
<ext:Column Header="Author" DataIndex="AuthorName" Width="100" />
<ext:CommandColumn Header="Actions" Width="80">
<Commands>
<ext:GridCommand Icon="PageWhiteDownload" CommandName="RetrieveDocument" Text="Download" />
</Commands>
<Listeners>
<Command Handler="executeGridRowCommand(command, record);" />
</Listeners>
</ext:CommandColumn>
</Columns>
</ext:ColumnModel>
The client-side JavaScript function executeGridRowCommand would then construct a URL and prompt the browser to navigate to it:
<script type="text/javascript">
function executeGridRowCommand(command, record) {
if (command === 'RetrieveDocument') {
// Ensure filename is URL-encoded to handle special characters correctly
let targetDownloadUrl = "/FileHandlers/DocumentDownload.aspx?docId=" + record.data.DocId + "&docName=" + encodeURIComponent(record.data.DocumentName);
window.location.href = targetDownloadUrl;
}
}
</script>
On the server, DocumentDownload.aspx handles the request and streams the file to the client:
// Inside DocumentDownload.aspx.cs
using System;
using System.IO;
using System.Web;
public partial class DocumentDownload : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
int documentIdentifier;
string requestedFileName = Request.QueryString["docName"] ?? "download";
if (int.TryParse(Request.QueryString["docId"], out documentIdentifier))
{
// In a production application, retrieve the actual file path and name
// from a database or storage based on 'documentIdentifier'.
// For this example, we'll use a placeholder file.
string baseDownloadPath = Server.MapPath("~/App_Data/Documents/");
string actualFilePath = Path.Combine(baseDownloadPath, "SampleReport.xlsx"); // Assume this file exists
if (File.Exists(actualFilePath))
{
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; // Example for .xlsx
Response.AddHeader("Content-Disposition", $"attachment; filename=\"{requestedFileName}\"");
Response.TransmitFile(actualFilePath);
}
else
{
Response.Clear();
Response.StatusCode = 404;
Response.StatusDescription = "Document Not Found";
Response.End();
}
}
else
{
Response.Clear();
Response.StatusCode = 400;
Response.StatusDescription = "Invalid Document ID";
Response.End();
}
}
}
}
Server-Side Initiated Downloads Using X.Redirect
When a download needs to be triggered from a DirectEvent (e.g., after server-side processing like report generation), X.Redirect can be utilized. This method displays a user-friendly masked message while the browser is redirected to the download URL, enhancing the user experience.
// Example within a DirectEvent handler, such as a button click
protected void GenerateAndDownloadReport_Click(object sender, DirectEventArgs e)
{
// Perform server-side operations, e.g., generate a complex report
string generatedReportKey = Guid.NewGuid().ToString();
// Store report path or data in Session/Cache with the key
Session["Report_" + generatedReportKey] = "/temp_reports/GeneratedSalesSummary.pdf";
// Redirect to a specific handler that will serve the file
X.Redirect($"/FileHandlers/ReportServe.aspx?key={generatedReportKey}", "Generating your report, please wait...");
}
The ReportServe.aspx page would then retrieve the report path using the provided key and stream the file.
- Executing JavaScript from the Server-Side
EXT.NET's DirectEvents provide robust capabilities for executing arbitrary JavaScript code on the client after server-side processing. This is a fundamental mechanism for dynamically updating the user interface, triggering client-side functions, or displaying notifications.
// Example code within a C# DirectEvent handler
protected void TriggerClientActions_Click(object sender, DirectEventArgs e)
{
// Display a simple ExtJS alert message
X.Msg.Alert("Server Command", "A message from the server has been received!").Show();
// Inject a direct script block to be executed by the browser
X.AddScript("console.log('Server-injected script executed.');");
// Call a predefined client-side JavaScript function with arguments
X.Call("handleServerMessage", "Operation Complete", DateTime.Now.ToShortTimeString());
// Show an ExtJS confirmation dialog, with client-side callback logic
X.Msg.Confirm("Proceed Confirmation", "Are you sure you want to continue this process?", new JFunction("responseBtn", @"
if (responseBtn === 'yes') {
Ext.toast('Action confirmed by user.');
} else {
Ext.toast('Action cancelled by user.');
}
")).Show();
// For finer control, or when no specific X. method exists, use ResourceManager directly
ResourceManager.GetInstance().AddScript("Ext.Msg.prompt('User Input', 'Please enter your feedback:', function(btn, text){ if(btn === 'ok' && text){ alert('Feedback received: ' + text); } });");
}
On the client-side, you would define the JavaScript functions that the server intends to call:
<script type="text/javascript">
function handleServerMessage(status, time) {
Ext.toast('Client function \'handleServerMessage\' called. Status: ' + status + ', Time: ' + time);
}
// A simple Ext.toast implementation for demonstration (may vary by ExtJS version)
// For older versions, consider using Ext.Msg.alert or a custom notification system.
if (!Ext.toast) {
Ext.toast = function(message) {
Ext.Msg.alert('Notification', message);
};
}
</script>
Upon execution of the TriggerClientActions_Click DirectEvent, EXT.NET serializes these commands and transmits them within the AJAX response for client-side execution.
- User-Friendly Page Redirection
The X.Redirect method offers a streamlined way to redirect the user's browser to a new URL while simultaneously displaying a temporary mask with a custom message. This enhances the user experience during navigations that might involve server-side processing or network delays.
// Example: Redirecting to a confirmation page after a successful data submission
protected void SubmitFormAndRedirect_Click(object sender, DirectEventArgs e)
{
// ... perform data validation, persistence, or other server-side logic ...
// After successful processing, redirect the user to a success page
X.Redirect("/Application/Confirmation.aspx", "Processing your submission and redirecting...");
}
Internally, X.Redirect orchestrates the display of an ExtJS mask with the specified message. Following this, it injects a JavaScript command that modifies window.location.href, thereby executing the browser navigation.
- Accessing EXT.NET Controls on the Server
While dynamic client-side manipulation of ExtJS components using JavaScript is often efficient, there are situations where direct access and modification of EXT.NET controls from your server-side C# code are necessary. This is typically achieved by finding controls within their parent containers.
Locating Controls by Server ID
You can use the FindControl method, available on any ASP.NET server control (including EXT.NET containers like Panel, Window, or the page itself), to locate a child control by its assigned server ID.
// Assume 'mainContentPanel' is an Ext.Net.Panel declared on the page,
// and 'customerNameInput' is an Ext.Net.TextField within that panel.
protected void UpdateControlProperties_Click(object sender, DirectEventArgs e)
{
// Access the parent panel directly (if it's a member) or find it
Panel mainContentPanel = this.FindControl("mainContentPanel") as Panel;
if (mainContentPanel != null)
{
// Find a specific text field within the panel by its ID
TextField customerNameInput = mainContentPanel.FindControl("customerNameInput") as TextField;
if (customerNameInput != null)
{
// Modify properties like Disabled state and current Text value
customerNameInput.Disabled = true;
customerNameInput.Text = "Data Loaded (Read-Only)";
customerNameInput.FieldLabel = "Customer Name (Locked)";
}
// Example: Iterate through child controls to disable all checkboxes within the panel
foreach (System.Web.UI.Control childControl in mainContentPanel.Controls)
{
if (childControl is Checkbox checkboxComponent)
{
checkboxComponent.Disabled = true;
checkboxComponent.BoxLabel += " (Disabled)";
}
else if (childControl is Button actionButton)
{
actionButton.Disabled = true;
}
}
}
}
When control properties are modified on the server, EXT.NET intelligently handles rendering the necsesary client-side updates, which are then transmitted with the AJAX response of the DirectEvent. For straightforward property changes, this server-side approach offers convenience. However, for highly dynamic or performance-critical UI manipulations, directly executing JavaScript on the client remains a very potent and often more immediate method.