Анналы sb output aspx form. Тестирование динамического кода. Выполнение проверки достоверности

Перевод: Влад Мержевич

Посещая Интернет вы увидите ряд сайтов, которые используют калькулятор для расчёта разных вещей, таких как: погашение ссуды, ставки по ипотечным кредитам, налоги, страхование и многое другое. До сегодняшнего дня у вас не было способа семантической разметки результата таких вычислений. Встречайте - элемент ! В этой статье мы расскажем об этом элементе и некоторых связанных с ним трюках JavaScript. Расщёлкнем этот орешек.

Определение

, новый элемент в HTML5, применяется в формах. Спецификации WHATWG HTML описывает очень просто.

Элемент output представляет собой результат вычислений. Спецификация WHATWG HTML .

Как и следовало ожидать, если ввести только одно значение, функция возвращает NaN. Она пытается сложить число и значение undefined, в итоге 1 + undefined = undefined.

Использование атрибута for

Возьмём за основу предыдущий пример и добавим к атрибут for (пример 2). Нам нужно добавить идентификаторы каждого связанного , это аналогично атрибуту for для

Пример 2. Использование атрибута for для элемента

+ =

Свойство valueAsNumber

В HTML5 представлено свойство JavaScript valueAsNumber для полей формы (в частности: number, date, range). Оно возвращает значение в виде числа, а не строки, то есть нам больше не нужно использовать parseInt или parseFloat , и оператор + складывает, а не склеивает.

Пример 3. Использование свойства valueAsNumber для получения числового значения из полей

+ =

Финансовый калькулятор: подробный пример

Для более реалистичного примера сделаем финансовый калькулятор, который умножает количество часов на почасовую ставку и добавляет налог для получения конечного результата (пример 4).

Пример 4. Финансовый калькулятор отображает результат в элементе

Invoice

£

Total: £0

Ничего слишком сложного не происходит. На самом деле скрипты настолько простые, что даже я могу их сделать.

Немного спорный пример с использованием

Пока писалась эта статья я нашёл ряд примеров использования элемента в сочетании с , как показано в примере 5.

Пример. 5. Использование с элементом

0/100

Использование для показа текущего значения пользователю кажется мне вполне разумным применением, но это не результат вычислений как описано в спецификации. Несколько человек на канале IRC согласились со мной, поэтому я подал отчёт об ошибке , где просил внести поправки в определение. С момента написания этой статьи ошибка была решена и определение расширили , так что использование , как показано выше, теперь корректно. Ура!

Поддержка в браузерах

Хорошая новость - все современные браузеры поддерживают в некоторой степени элемент . Плохая новость в том, что есть несколько подводных камней.

Поддержка в браузерах
Браузер Поддержка
Chrome 13+
Safari 5.1+
Firefox 6+
Opera 9.20+
Internet Explorer 10+

Все примеры, которые мы видели до сих пор, должны безупречно работать в Opera 11.5 +, Safari 5.1+ и Chrome 13 +. IE, как и следовало ожидать, несколько отстаёт, поддерживается в IE10 Platform Preview 2, а oninput поддерживается уже в IE9. Чтобы обойти это в наших простых примерах, мы должны вернуться к надёжному и проверенному getElementById и parseFloat (пример 6).

This is the HttpHandler and HttpModule in real scenario article series. In this series we are learning various concepts and uses of HttpHandler and HttpModule. In our previous article we have covered various important concepts, you can read them here.

This is another example where we can measure the time gap between a request and its response. Sinice HttpModule is in the middle of a request and response, we can measure the time taken by a specific HTTP request.

In this example we will measure the time taken by one HTTP request to complete. Have a look at the following example.

using System;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Text;

using System.Web;

using System.Xml.Linq;

using Newtonsoft.Json;

namespace WebApp

public void Dispose()

Context.BeginRequest += new EventHandler (OnBeginRequest);

Context.EndRequest += new EventHandler (OnEndRequest);

// Record the time of the begin request event.

public void OnBeginRequest(Object sender, EventArgs e)

HttpApp.Context.Items[ "beginTime" ] = DateTime .Now;

public void OnEndRequest(Object sender, EventArgs e)

HttpApplication httpApp = (HttpApplication )sender;

// Get the time of the begin request event.

DateTime beginTime = (DateTime )httpApp.Context.Items[ "beginTime" ];

// Evaluate the time between the begin and the end request events.

TimeSpan ts = DateTime .Now - beginTime;

// Write the time span out as a request header.

HttpApp.Context.Response.AppendHeader("TimeSpan" , ts.ToString());

// Get the current user"s Machine Name.

string user = WindowsIdentity .GetCurrent().Name;

// Display the information in the page.

StringBuilder sb = new StringBuilder ();

Sb.AppendLine("

RequestTimeInterval from HttpModule Output

" );

Sb.AppendFormat("Current user: {0}
" , user);

Sb.AppendFormat("Time span between begin-request and end-request events: {0}
"
,

Ts.ToString());

HttpApp.Context.Response.Output.WriteLine(sb.ToString());

The implementation is pretty simple. When a request is coming we are recording the time and when the request finishs we again measure the time and then calculate the time taken by that specific HTTP request to complete.

Add the following code to your web.config file to register the HttpModule.

< system.webServer >

< modules >

< add name = " mymodule1 " type = " WebApp.MyHttpModule1 " />

< system.webServer >

Here is the output of the receding implementation. We see that the HTTP request is taking nearly 2 miliseconds to finish. (Ha..Ha..Pretty fast execution).

Count number of requests by user by Form authentication

This is another real situation where we can implement HttpModule as a solution. Sometimes it’s very useful to count the number of login attemts from a specific user. There might be a business need or other motive behind that (we are not concerned with it).

So, if the requirement is something like. “We need to count the number of logins of a specific user, then we can implement the counting mechanism using HttpModule. I am not demanding that, this is the best and only one solution in this reqirement, but this is also a possible solution among others.

When we want to count the login attempts of a user then we need to count with respect to username and for that we will implement Form Authentication in the application.

Step 1: Create login form with a few controls

Here is the code of the login form. It’s very simple. We just must use two text boxes with one button.

<% @ Page Language ="C#" AutoEventWireup ="true" CodeBehind ="login.aspx.cs" Inherits ="WebApp.login" %>

< html xmlns ="http://www.w3.org/1999/xhtml">

< head runat ="server">

< title >

< body >

< form id ="form1" runat ="server">

< div >

UserName:- < asp : TextBox ID ="TextBox1" runat ="server">< br />

Password:- < asp : TextBox ID ="TextBox2" runat ="server">< br />

< asp : Button ID ="Login" runat ="server" Text ="Button" OnClick ="Login_Click" />

Step 2: Write the following code in code behind of login form

This is the normal form of Authentication code, nothing special in this. We are checking the username and password with a constant string, in reality it might check with some persistence storage. Once both the username and password is “abc” we are setting the form authentication cookies and then redirecting the user to the Home page.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Security;

using System.Web.Security;

namespace WebApp

public partial class login : System.Web.UI. Page

protected void Page_Load(object sender, EventArgs e)

protected void Login_Click(object sender, EventArgs e)

if (this .TextBox1.Text == "abc" && this .TextBox2.Text == "abc" ){

FormsAuthentication .SetAuthCookie(

this .TextBox1.Text.Trim(), true );

Response.Redirect("Home.aspx" );

Step 3: Configure Form Authentication in web.config file

This is necessary when we want to configure Form Authentication in an ASP.NET application.

< authentication mode = " Forms " >

< forms loginUrl = " login.aspx " >

Step 4: Implement HttpModule that will count user

Here is the core part of this example. We will implement one HttpModule that will count the user depending one URL.

Have a look at the following code. Here we will detect the user who will try to browse to the Home.aspx page.

using System;

using System.Collections.Generic;

using System.Drawing;

using System.Drawing.Imaging;

using System.IO;

using System.Linq;

using System.Security.Principal;

using System.Text;

using System.Web;

using System.Xml.Linq;

using Newtonsoft.Json;

namespace WebApp

public class MyHttpModule1 : IHttpModule

public void Dispose()

throw new NotImplementedException ();

public void Init(HttpApplication context)

Context.AuthenticateRequest += new EventHandler (OnAuthentication);

void OnAuthentication(object sender, EventArgs a)

HttpApplication application = (HttpApplication )sender;

HttpContext context = application.Context;

if (context.Request.Url.AbsolutePath.Contains("Home" ))

String user = context.User.Identity.Name;

We are checking the URL, If the URL pattern contains the keyword Home then will check the username as it’s showing in the following example.

And when we are getting the username it’s very simple to implement a counting mechanism depending on username. I have skipped this part to make the example simple. With a little effort, you can implement the rest.

Conclusion

In this article we have learned two important concepts for implementing HttpModule as a solution. I hope you have understood the real example of HttpModule in this article.

Виртуальные пути

Между виртуальными и физическими путями существует стандартное отображение. Виртуальный путь наподобие /Content/RequestReporter.aspx соответствует файлу веб-формы /Content/RequestReporter.aspx. Главное преимущество такого отображения заключается в простоте - достаточно взглянуть на URL и немедленно понять, каким образом виртуальный путь будет применяться для генерации ответа.

Однако прямое отображение между виртуальными и физическими путями не всегда идеально. Например, модернизация приложения может привести к перемещению и переименованию файлов, из-за чего перестанут работать URL, помещенные пользователями в закладки. Может потребоваться согласование приложения Web Forms с более широкой схемой URL, которая не соответствует стандартному подходу. Подобная ситуация распространена в корпоративных приложениях, в которых согласованность URL расценивается как способ помочь пользователям в переходе непосредственно к нужному контенту или функциональности.

Короче говоря, существует множество причин для изменения URL, на которые реагирует приложение, и все они приводят к нарушению работы прямых ссылок между виртуальными и физическими путями. В последующих разделах мы опишем разнообразные подходы, доступные для управления виртуальными путями и позволяющие настраивать схему URL, которую приложение раскрывает внешнему миру.

Вы узнаете, что есть много способов достижения того же самого базового результата. Причина в том, что все эти средства постепенно добавлялись с течением времени. Самое последнее добавление - поддержка маршрутизации URL - является тем средством, с которого следует начинать. Однако мы также рассматриваем ряд удобных старых средств, т.к. часто требуется комбинировать одно из них с маршрутизацией URL, чтобы создавать специфическую функциональность в приложении.

Установка стандартных документов

По соглашению, принятому для приложений Web Forms, начальной веб-форме назначается имя Default.aspx. Это не является требованием, но его нужно придерживаться, поскольку сервер IIS сконфигурирован так, что он ищет стандартные файлы, если никакого файла в URL не указано.

Чтобы продемонстрировать это в действии, мы внесли в метод ProcessRequest(), определенный в файле SimpleModule.cs (который мы создали в предыдущей статье), небольшое изменение, которое обеспечивает вывод значения свойства FilePath и URL в окно Output среды Visual Studio. Изменение показано в примере ниже:

// ... private void ProcessRequest(HttpApplication app) { if (app.Request.FilePath == "/Test.aspx") { app.Server.Transfer("/Content/RequestReporter.aspx"); } WriteMsg("URL запроса: {0} {1}", app.Request.RawUrl, app.Request.FilePath); } // ...

Для тестирования встроенного поведения запустите приложение и запросите корневой URL (у нас он выглядит как http://localhost:32404/, но у вас может быть другой номер порта). Браузер отобразит содержимое файла Default.aspx, а в окне Output будут отображаться следующие сообщения:

Последнее из этих сообщений отражает попытку сервера IIS найти файл, с помощью которого должен быть обслужен запрос. (Первые два сообщения объясняются в следующем разделе.) Сервер IIS имеет возможность отыскать файл Default.aspx для обслуживания запроса корневого URL, т.к. мы соблюдали соглашение об именовании. В противном случае IIS Express потерпел бы неудачу и возвратил браузеру ошибку 404, указывающую на то, что файл найти не удалось.

Сервер IIS ищет следующие стандартные документы: Default.html, Default.asp, index.htm, index.html, iisstart.htm и, наконец, default.aspx. (Мы не знаем, почему имя файла default.aspx представлено символами нижнего регистра, но это не играет роли, потому что имена веб-форм нечувствительны к регистру.)

Переопределить эти стандартные документы можно в файле Web.config. Это стоит делать, если нужно, чтобы по умолчанию использовалась другая стандартная веб-форма, или требуется сократить количество местоположений, в которые сервер IIS просматривает, прежде чем передает веб-форму на обработку среде ASP.NET.

В примере ниже показаны изменения, внесенные в файл Web.config:

... ...

Элемент defaultDocument добавлен в раздел конфигурационного файла. В нем определен атрибут enabled , который по умолчанию установлен в true (значение false предотвратит попытки поиска сервером IIS стандартного документа).

Внутри defaultDocument содержится элемент , представляющий собой коллекцию стандартных документов, которые будет искать IIS. С помощью элемента мы удалили все стандартные документы, а посредством элемента задали специальную политику. В элементе defaultDocument/files/add определен единственный атрибут по имени value, применяемый для указания файла, который IIS должен искать. Мы воспользовались элементом add для установки веб-формы RequestReporter.aspx из папки Content в качестве единственного стандартного документа.

Обратите внимание, что при указании стандартного документа в атрибуте value ведущий символ / отсутствует. Добавление ведущего символа / приводит к отображению сообщения об ошибке.

Чтобы увидеть результат, запустите приложение и запросите URL вида http://localhost:<порт>/, где <порт> это номер порта, прослушиваемого сервером IIS Express на предмет поступления запросов для этого приложения. Новая политика в отношении стандартного документа будет применена, и отобразится вывод, сгенерированный веб-формой RequestReporter.aspx.

Обработка запросов для URL без расширений

При отправке запроса к корневому URL в предыдущем разделе в окне Output среды Visual Studio отображались три сообщения:

URL запроса: / / URL запроса: / / URL запроса: / /default.aspx

Мы объяснили, что последнее сообщение говорит о применении политики IIS, касающейся стандартного документа. Первоначально это был запрос к Default.aspx, но мы изменили политику IIS в отношении стандартного документа. Перед тем, как IIS применяет такую политику, он предоставляет ASP.NET шанс обработать запрос - это причина, по которой отображено первое сообщение.

Среда ASP.NET имеет обработчик для этого запроса, однако по умолчанию он не делает ничего полезного. Таким обработчиком является внутренний класс TransferRequestHandler , отвечающий за обработку URL без расширений, которые позволяют ASP.NET обрабатывать запросы к виртуальным путям, не содержащим файловые расширения, такие как.aspx.

Класс TransferRequestHandler не делает особенно много с запросами для URL без расширений. Он просто указывает серверу IIS на необходимость создания и обработки второго запроса, не используя TransferRequestHandler в качестве обработчика - именно поэтому отображается второе сообщение.

Чтобы делать нечто полезное с запросами для URL без расширений, понадобится создать обработчик и заменить им TransferRequestHandler. Мы добавили в проект новый файл класса по имени ExtensionlessHandler.cs, содержимое которого приведено в примере ниже:

Using System.IO; using System.Web; namespace PathsAndURLs { public class ExtensionlessHandler: IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.Write("

HTTP-обработчик Expressionless

"); string vpath = context.Request.Path; if (vpath == "/") { context.Server.Transfer("/Default.aspx"); } else if (File.Exists(context.Request.MapPath(vpath + ".aspx"))) { context.Server.Transfer(vpath + ".aspx"); } else { context.Response.StatusCode = 404; context.ApplicationInstance.CompleteRequest(); } } public bool IsReusable { get { return false; } } } }

Этот обработчик будет получать запросы для URL без расширений и с помощью метода HttpServerUtility.Transfer() передавать запросы веб-форме. Определение, какой веб-форме должен быть передан запрос, реализуется элементарно. Если запрошенным URL является /, мы направляем его Default.aspx, а для всех других запросов просто добавляем расширение.aspx к запрошенному URL и проверяем, существует ли в приложении файл с таким именем. Если это так, мы передаем ему запрос, а в противном случае возвращаем ответ с ошибкой 404.

Чтобы обработчик смог принимать запросы, его необходимо зарегистрировать. В примере ниже показаны изменения, внесенные в файл Web.config:

...

Для обработки URL без расширений мы устанавливаем атрибут path в "*." (символы звездочки и точки). Обработка URL без расширений выполняется перед применением политики IIS, касающейся стандартного документа, поэтому предыдущая конфигурация была переопределена и корневой URL (/) отображен на Default.aspx. В качестве дополнения мы можем запрашивать любую веб-форму, не указывая файловое расширение. Таким образом, например, запрос для виртуального пути /Content/RequestReporter сгенерирует ответ на основе веб-формы /Content/RequestReporter.aspx.

Переписывание путей

В предыдущем примере использовался метод HttpServerUtility.Transfer(), который нормально работает с веб-формами, но не очень хорошо с другими типами файлов, такими как обобщенные обработчики (файлы ashx). Мы могли бы применить прием с оболочкой для Page, но это грубый трюк, и мы не являемся его сторонниками.

Имея все это в виду, рассматриваемый далее подход может быть реализован более широко, однако это должно делаться внутри модуля. Прием называется переписыванием путей и представляет собой просто процесс изменения пути, связанного с запросом. Чтобы показать пример использования такого подхода, мы создали файл класса по имени PathModule.cs с содержимым, приведенным в примере ниже:

Using System; using System.IO; using System.Web; namespace PathsAndURLs { public class PathModule: IHttpModule { private static readonly string extensions = { ".aspx", ".ashx" }; public void Init(HttpApplication app) { app.BeginRequest += (src, args) => HandleRequest(app); } private void HandleRequest(HttpApplication app) { if (app.Request.CurrentExecutionFilePathExtension == String.Empty) { string target = null; string vpath = app.Request.CurrentExecutionFilePath; if (vpath == "/") { target = "/Default.aspx"; } else { foreach (string ext in extensions) { if (File.Exists(app.Request.MapPath(vpath + ext))) { target = vpath + ext; break; } } } if (target != null) { app.Context.RewritePath(target); } } } public void Dispose() { // Ничего не освобождается } } }

Так как это модуль, его необходимо зарегистрировать в файле Web.config:

... ...

Этот модуль обрабатывает событие BeginRequest и просматривает запросы, которые не имеют файлового расширения. В рассматриваемом примере изменяется способ обработки корневого URL, т.е. для обработки запросов применяется веб-форма Default.aspx, которую можно увидеть, запустив приложение и запросив /.

Главное улучшение по сравнению с предыдущим примером связано с проверкой существования файлов, имеющих расширения aspx или ashx, если запрошенным URL не является /. Это позволяет приложению поддерживать дружественные URL - именно так называются запросы веб-форм и обработчиков без указания файловых расширений. (Происхождение данного названия нам не известно, однако мы его придерживаемся.)

Прием является вариацией обработки URL без расширений и по-прежнему требует сопоставления виртуальных путей с файлами в приложении, но без указания расширений.aspx или.ashx, которые многие разработчики считают непривлекательными.

Ключевым в модуле является метод RewritePath() , который определен в классе HttpContext. Этот метод позволяет изменить путь при условии, что это делается перед событием жизненного цикла MapRequestHandler .

Метод RewritePath() не имеет ограничений, с которыми мы сталкиваемся при использовании методов класса HttpServerUtility, т.е. появляется возможность поддерживать запросы к обобщенным обработчикам, а также файлам веб-форм.

В классе HttpContext определено несколько перегруженных версий метода RewritePath(), которые описаны в таблице ниже:

Две перегруженных версии метода RewritePath() принимают аргумент типа bool по имени rebase, который отвечает за изменение путей, используемых элементами управления для создания URL - процесс, известный как изменение базы клиента .

В Microsoft предлагается загружаемый пакет под названием URL Rewriting Engine (Механизм переписывания URL) , который позволяет выражать правила переписывания в файле Web.config, а не в коде.

Реальный пример переписывания путей

Ранее метод HttpContext.RewritePath() использовался для добавления файлового расширения, т.е. мы могли бы поддерживать URL без расширений и дружественные URL. С помощью средства переписывания путей можно реализовать очень сложные действия, из-за чего мы применяем его в проектах, требующих поддержки необычных схем URL и таких, которые варьируются на основе характеристик запросов, отличных от путей.

В целях иллюстрации мы рассмотрим пример, основанный на одном из реальных проектов, над которым мы работали недавно. Нам необходимо было повторно построить приложение с применением ASP.NET, но старые URL были жестко закодированы в других приложениях и должны были остаться работоспособными.

Одна из проблем, с которой мы столкнулись, заключалась в том, что запросы к URL вида /accounts нужно было направлять двум веб-формам в зависимости от значения данных формы, имеющего имя function. Когда значение function не превышало 100, запрос должен отправляться веб-форме Default.aspx, а для всех других значений - веб-форме /Content/RequestReporter.aspx (разумеется, это не веб-формы из реального проекта; мы просто хотим воспользоваться уже готовыми файлами в примере приложения).

Чтобы продемонстрировать проблему, мы создали новую веб-форму по имени Split.aspx, контент которой представлен в примере ниже. Эта веб-форма будет эмулировать унаследованных клиентов с жестко закодированными URL:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Split.aspx.cs" Inherits="PathsAndURLs.Split" %>

Функция:

Веб-форма содержит простую HTML-форму, которая позволяет ввести значение function и отправить его серверу по щелчку на кнопке "Отправить". Элемент

сконфигурирован так, что данные отправляются по пути /accounts, который не соответствует ни одному из файлов внутри проекта.

В примере ниже приведен модифицированный файл класса SimpleModule.cs, созданного ранее в проекте, в котором можно видеть, как обрабатывается такой запрос:

// ... private void ProcessRequest(HttpApplication app) { if (app.Request.Path == "/accounts") { int functionValue; if (int.TryParse(app.Request.Form["function"], out functionValue)) { if (functionValue < 100) { app.Context.RewritePath("/Default.aspx"); } else { app.Context.RewritePath("/Content/RequestReporter.aspx"); } } } WriteMsg("URL запроса: {0} {1}", app.Request.RawUrl, app.Request.FilePath); } // ...

Вместо того чтобы просто дополнить путь файловым расширением, мы применяем метод RewritePath() для направления запроса на разные веб-формы на основе значения данных формы, поступившего вместе с запросом. Запустите приложение и запросите URL вида /Split. После отправки данных запрос попадает на URL /accounts и затем, в зависимости от значения данных формы, перенаправляется соответствующей веб-форме.

The walkthrough below demonstrates step-by-step how to use them. In the demo, we use date-time to determine whether a page is cached (in the PageLoad event, we write the date-time in a Label control named “ lblResult ”.):

  1. The Duration attribute
  • Add @OutputCache in the ASPX markup and specify the expiration time. In this case, we assign 10s for it. For example: OutputCache Duration="10" VaryByParam="none" .
  • Run the ASP.NET web application and launch this page, and we will see that the date-time on the page won"t change 10s when the page is reloading.
<%@ OutputCache Duration =" 10" VaryByParam =" none" %> < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" > < html xmlns =" http://www.w3.org/1999/xhtml" > < head runat =" server" > < title > OutPutCacheWithDuration< /title > < /head > < body > < form id =" form1" runat =" server" > < div > < asp:Label ID =" lblResult" runat =" server" > < /asp:Label > < br / > < br / > < asp:Button ID =" btnPostBack" runat =" server" Text =" Post Back" / > < p > The page will be cached 10s, and then you can click Button to update datetime. < /p > < /div > < /form > < /body > < /html >
  • The VaryByControl attribute
    • Drag and drop a DropDownList in the page and add three items to it.
    • Add @OutputCache in the ASPX markup and specify the expiration time and VaryByControl attribute. For example: OutputCache Duration="1000" VaryByControl="ddlOption" .
    • Run the ASP.NET web application and launch this page, we can see that the different items have their corresponding cache.
    <%@ OutputCache Duration =" 1000" VaryByControl =" ddlOption" %> < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns =" http://www.w3.org/1999/xhtml" > < head runat =" server" > < title > OutPutCacheWithVaryByControl< /title > < /head > < body > < form id =" form1" runat =" server" > < div > < asp:Label ID =" lblResult" runat =" server" > < /asp:Label > < br / > < br / > < asp:DropDownList ID =" ddlOption" runat =" server" AutoPostBack =" True" OnSelectedIndexChanged =" ddlOption_SelectedIndexChanged" > < asp:ListItem Selected =" True" > Option One< /asp:ListItem > < asp:ListItem > Option Two< /asp:ListItem > < asp:ListItem > Option Three< /asp:ListItem > < /asp:DropDownList > < p > The page will be rendered from cache basing on the selected item of DropDownList. The different item has corresponding cache. < /p > < /div > < /form > < /body > < /html >
  • The VaryByCustom attribute
    • Add @OutputCache in the ASPX markup and specify the expiration time and VaryByControl attribute with the "browser" value. For example: OutputCache Duration="1000"VaryByCustom="browser"VaryByParam="none" .
    • Run the ASP.NET web application and launch this page with IE and Firefox (or a browser with a different name, major version), and we will see that there is different cache versions for different browsers.
    <%@ OutputCache Duration =" 1000" VaryByCustom =" browser" VaryByParam =" none" %> < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns =" http://www.w3.org/1999/xhtml" > < head runat =" server" > < title > OutPutCacheWithVaryByCustom< /title > < /head > < body > < form id =" form1" runat =" server" > < div > < asp:Label ID =" lblResult" runat =" server" > < /asp:Label > < br / > < br / > < asp:Button ID =" btnPostBack" runat =" server" Text =" Post Back" / > < p > The page will be rendered from cache basing on the version of browser, such as IE and FireFox. < /p > < /div > < /form > < /body > < /html >
  • The VaryByParam attribute
    • Add @OutputCache in the ASPX markup and specify the expiration time and VaryByParam attribute with an " id " value. For example: OutputCache Duration="1000" VaryByParam="id" .
    • Run the ASP.NET web application and launch this page, and we can request it using a QueryString " id " with a different value.
    ~/OutputCacheWithParam.aspx?id=1 ~/OutputCacheWithParam.aspx?id=2 > <%@ OutputCache Duration =" 1000" VaryByParam =" id" %> < !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns =" http://www.w3.org/1999/xhtml" > < head runat =" server" > < title > OutPutCacheWithVaryByParam< /title > < /head > < body > < form id =" form1" runat =" server" > < div > < asp:Label ID =" lblResult" runat =" server" > < /asp:Label > < p > The page will be rendered from cache until the value of QueryString named "id" is changed or Duration is expiration. < /p > < /div > < /form > < /body > < /html >

    Points of Interest

    If there is any problem, you can take a look at the ReadMe.txt file in each sample project, which contains a step by step tutorial of how to build the project.

    But there I had a problem.

    I created an asp.net web application project and than copied .aspx files to _layouts folder and installed code-behind .dll into GAC.

    The AssociationForm.aspx source code was this:

    Code Snippet

    @ Page Language ="C#" AutoEventWireup ="true" CodeBehind ="AssociationForm.aspx.cs" ="SimpleCopyFileForms.AssociationForm.AssociationForm, SimpleCopyFileForms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=****************" %> @ Register Tagprefix ="SharePoint" Namespace ="Microsoft.SharePoint.WebControls" Assembly %> @ Register Tagprefix ="Utilities" Namespace ="Microsoft.SharePoint.Utilities" Assembly ="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> @ Import Namespace ="Microsoft.SharePoint" %> @ Register Tagprefix ="WebPartPages" Namespace ="Microsoft.SharePoint.WebPartPages" Assembly ="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> asp : Content ContentPlaceHolderId ="PlaceHolderMain" runat ="server"> < div > < table > < tr >< td > < td > < asp : ListBox ID ="listBoxLibs" runat ="server"> < tr >< td > Select save type < td > < asp : RadioButtonList ID ="radioButtonListSaveType" runat ="server"> < asp : ListItem Selected ="True" Value ="Append"> Append a random number < asp : ListItem > Overwrite < tr >< td > < asp : Button ID ="btnSubmit" runat ="server" Text ="Submit" onclick ="btnSubmit_Click" /> < td > < asp : Button ID ="btnCancel" runat ="server" Text ="Cancel" onclick ="btnCancel_Click" />

    < SharePoint : FormDigest ID ="FormDigest1" runat ="server">

    < input type ="hidden" name ="WorkflowDefinition" value = <% _STSWriteHTML(Request.Form["WorkflowDefinition"]); %> > < input type ="hidden" name ="WorkflowName" value = <% _STSWriteHTML(Request.Form["WorkflowName"]); %> > < input type ="hidden" name ="AddToStatusMenu" value = <% _STSWriteHTML(Request.Form["AddToStatusMenu"]); %> > < input type ="hidden" name ="AllowManual" value = <% _STSWriteHTML(Request.Form["AllowManual"]); %> > < input type ="hidden" name ="RoleSelect" value = <% _STSWriteHTML(Request.Form["RoleSelect"]); %> > < input type ="hidden" name ="AutoStartCreate" value = <% _STSWriteHTML(Request.Form["AutoStartCreate"]); %> > < input type ="hidden" name ="AutoStartChange" value = <% _STSWriteHTML(Request.Form["AutoStartChange"]); %> > < input type ="hidden" name ="GuidAssoc" value = <% _STSWriteHTML(Request.Form["GuidAssoc"]); %> > asp : Content >

    Then I went to sharepoint library, workflow settings, and set all the necessary information on workflow association page. But after I clicked "Next" I received "Unknown Error". I looked in sharepoint logs and there I saw next exception:

    Code Snippet

    Exception Type: System.Web.HttpCompileException Exception Message: c:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\SimpleCopyFileForms\AssociationForm\AssociationForm.aspx(33): error CS0103: The name "_STSWriteHTML" does not exist in the current context

    Code Snippet

    < input type ="hidden" name ="WorkflowDefinition" value = <% _STSWriteHTML(Request.Form["WorkflowDefinition"]); %>>

    < input type ="hidden" name ="WorkflowName" value = <% _STSWriteHTML(Request.Form["WorkflowName"]); %>>

    < input type ="hidden" name ="AddToStatusMenu" value = <% _STSWriteHTML(Request.Form["AddToStatusMenu"]); %>>

    < input type ="hidden" name ="AllowManual" value = <% _STSWriteHTML(Request.Form["AllowManual"]); %>>

    < input type ="hidden" name ="RoleSelect" value = <% _STSWriteHTML(Request.Form["RoleSelect"]); %>>

    < input type ="hidden" name ="AutoStartCreate" value = <% _STSWriteHTML(Request.Form["AutoStartCreate"]); %>>

    < input type ="hidden" name ="AutoStartChange" value = <% _STSWriteHTML(Request.Form["AutoStartChange"]); %>>

    < input type ="hidden" name ="GuidAssoc" value = <% _STSWriteHTML(Request.Form["GuidAssoc"]); %>>

    tags from AssociationForm.aspx page and tried to associate workflow again. After clicking "Next" I finally was redirected to my AssociationForm.aspx page but when I clicked "Submit" it didn"t go to "Submit" button"s handler, instead it started page load again, so all data which was sent to my page from AddWrkfl.aspx page were lost.

    Can someone suggest what I did wrong?



    
    Top