Visual Studio


Hi reader

We have developed a BCS service which takes data from a SQL server data base using web services, we have created an external list in SharePoint which is connected to the BCS service anad displays data, everything was workig fine but client raised a requirement to have some custom control on the external list form, for example client want to see a dropdown for status of an order, by defalut external list displays data in text boxes, just like below screenshot

After spending almost 2 days, I have got the solution which might save ur 2 days J

Idea is that we will create a custom control that will render a dropdown with all possible values, in the sample application I have included some dummy values. We will configure our BDC modal to use our custom control for displaying field on forms.

This is my class which defines creat child control method pf my custom control which renders a dropdown with fixed entries.

Following class uses above class for rendering

Before moving forward, create a simple list and create a column with your custom field, and perform all CRUD operations to make sure custom control is working well.

My BDC modal class with 2 methods

Read list and read item modal configuration, this is the most important part.

Where “EmailField” is class name of my custom control

So final screen look like

That’s it very simple, let me know if you get confused anywhere.

Advertisements

With the integration of Visual Studio 2010 and SharePoint 2010, creating features are now much easier than with previous versions of either tool. To begin creating a feature to modify the Site Action menu, create a SharePoint 2010 empty project in Visual Studio 2010, making sure to chose a Farm solution rather than Sandbox. After the project has been created, you will see the below structure.

Now add a new module in the project, I am naming it “SiteActionMenue”

You will see following files added in the project

You can delete sample.txt file

Remove module section and replace with this site action script

<CustomAction


Id=toolPaneWebpart


Description=Toolpane Webpart


Title=ToolPane Web part Action


GroupId=SiteActions


Location=Microsoft.SharePoint.StandardMenu


ImageUrl=”/_layouts/images/settingsIcon.png”


Sequence=10001>

<UrlAction
Url=_layouts/WebpartConfiguration/MyPage.aspx />

</CustomAction>

Note : We have specified a url to the page, we will add that page later.

Set default site for this application when creating the new project, otherwise you can set in projects properties, see the following screenshot


Save the project and press F5

Go to site action and you will see a context menu.


Now go to project and add a new content page.


Press add and this will add a page in the solution within appropriate folder


Now press F5

After clicking on site action menu you will be redirected to page you have created.


That’s it, how simple it was, let me know in case of any confusion.

Hi all
today i was trying to deploy my asp.net application on windows 7, 1st step completed successfully but after making some updates in my web.config file i got some deployment errors, after goggling i found there have a lot of modification in new IIS 7+ which a developer must know before deploying the application, i have listed them for your assistance.

Migration errors

These errors occur due to changes in how some ASP.NET configuration is applied in Integrated mode.  IIS will automatically detect this configuration and issue an error asking you to migrate your application, or move it to classic mode if migration is not acceptable (See breaking change #3 below).

 

1) ASP.NET applications require migration when specifying configuration in <httpModules> or <httpHandlers>.

You will receive a 500 – Internal Server Error.  This can include HTTP Error 500.22, and HTTP Error 500.23: An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode.

It occurs because ASP.NET modules and handlers should be specified in the IIS <handlers> and <modules> configuration sections in Integrated mode.

Workaround:

1) You must migrate the application configuration to work properly in Integrated mode.  You can migrate the application configuration with AppCmd:

> %windir%\system32\inetsrv\Appcmd migrate config “<ApplicationPath>”

2) You can migrate manually by moving the custom entries in in the <system.web>/<httpModules> and <system.web>/<httpHandlers> configuration manually to the <system.webServer>/<handlers> and <system.webServer>/<modules> configuration sections, and either removing the <httpHandlers> and <httpModules> configuration OR adding the following to your application’s web.config:

<system.webServer>

<validation validateIntegratedModeConfiguration=”false” />

</system.webServer>

 

2) ASP.NET applications produce a warning when the application enables request impersonation by specifying <identity impersonate=”true”> in configuration

You will receive a 500 – Internal Server Error. This is HTTP Error 500.24: An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode.

It occurs because ASP.NET Integrated mode is unable to impersonate the request identity in the BeginRequest and AuthenticateRequest pipeline stages.


Workaround
:

1) If your application does not rely on impersonating the requesting user in the BeginRequest and AuthenticateRequest stages (the only stages where impersonation is not possible in Integrated mode), ignore this error by adding the following to your application’s web.config:
<system.webServer>

<validation validateIntegratedModeConfiguration=”false” />

</system.webServer>

2) If your application does rely on impersonation in BeginRequest and AuthenticateRequest, or you are not sure, move to classic mode.

 

3) You receive a configuration error when your application configuration includes an encrypted <identity> section.

You will receive a 500 – Internal Server Error.  This is HTTP Error 500.19: The requested page cannot be accessed because the related configuration data for the page is invalid.
The detailed error information indicates that “Configuration section encryption is not supported”.

It occurs because IIS attempts to validate the <identity> section and fails to read section-level encryption.


Workaround:

1) If your application does not have the problem with request impersonation per breaking change #2, migrate your application configuration by using AppCmd as described in breaking change #1:

> %windir%\system32\inetsrv\Appcmd migrate config “<ApplicationPath>”

This will insure that the rest of application configuration is migrated, and automatically add the following to your application’s web.config to ignore the <identity> section:

<system.webServer>

<validation validateIntegratedModeConfiguration=”false” />

</system.webServer>

2) If your application does have the problem with request impersonation, move to classic mode.

 

Authentication, Authorization, and Impersonation

In Integrated mode, both IIS and ASP.NET authentication stages have been unified.  Because of this, the results of IIS authentication are not available until the PostAuthenticateRequest stage, when both ASP.NET and IIS authentication methods have completed.  This causes the following changes:

 

 

4) Applications cannot simultaneously use FormsAuthentication and WindowsAuthentication

Unlike Classic mode, it is not possible to use Forms Authentication in ASP.NET and still require users to authenticate with an IIS authentication method including Windows Authentication, Basic Authentication, etc.  If Forms Authentication is enabled, all other IIS authentication methods except for Anonymous Authentication should be disabled.
In addition, when using Forms Authentication, the following changes are in effect:

–       The LOGON_USER server variable will be set to the name of the Forms Authentication user.

–       It will not be possible to impersonate the authenticated client.  To impersonate the authenticated client, you must use an authentication method that produces a Windows user instead of Forms Authentication.

Workaround:

1) Change your application to use the pattern explained in Implementing a two level authentication scheme using Forms Authentication and another IIS authentication method in IIS 7.0.

 

 

5) Windows Authentication is performed in the kernel by default.  This may cause HTTP clients that send credentials on the initial request to fail.

IIS 7.0 Kernel-mode authentication is enabled by default in IIS 7.0.  This improves the performance of Windows Authentication, and simplifies the deployment of Kerberos authentication protocol.  However, it may cause some clients that send the windows credentials on the initial request to fail due to a design limitation in kernel-mode authentication.  Normal browser clients are not affected because they always send the initial request anonymously.

NOTE: This breaking change applies to both Classic and Integrated modes.


Workaround:

1) Disable kernel-mode authentication by setting the userKernelMode to “false” in the system.webServer/security/authentication/windowsAuthentication section.  You can also do it by AppCmd as follows:

> %windir%\system32\inetsrv\appcmd set config /section:windowsAuthentication /useKernelMode:false

 

6) Passport authentication is not supported.

You will receive an ASP.NET 500 – Server Error: The PassportManager object could not be initialized. Please ensure that Microsoft Passport is correctly installed on the server.

Passport authentication is no longer supported on Windows Vista and Windows Server 2008.  NOTE: This breaking change applies to both Classic and Integrated modes.

 

 

7) HttpRequest.LogonUserIdentity throws an InvalidOperationException when accessed in a module before PostAuthenticateRequest

You will receive an ASP.NET 500 – Server Error: This method can only be called after the authentication event.

HttpRequest.LogonUserIdentity throws an InvalidOperationException when accessed before PostAuthenticateRequest, because the value of this property is unknown until after the client has been authenticated.


Workaround:

1) Change the code to not access HttpRequest.LogonUserIdentity until at least PostAuthenticateRequest

 

 

8) Client impersonation is not applied in a module in the BeginRequest and AuthenticateRequest stages.

The authenticated user is not known until the PostAuthenticateRequest stage.  Therefore, ASP.NET does not impersonate the authenticated user for ASP.NET modules that run in BeginRequest and AuthenticateRequest stages.  This can affect your application if you have custom modules that rely on the impersonating the client for validating access to or accessing resources in these stages.

Workaround:

1) Change your application to not require client impersonation in BeginRequest and AuthenticateRequest stages.

 

9) Defining an DefaultAuthentication_OnAuthenticate method in global.asax throws PlatformNotSupportedException

You will receive an ASP.NET 500 – Server Error: The DefaultAuthentication.Authenticate method is not supported by IIS integrated pipeline mode.

In Integrated mode, the DefaultAuthenticationModule.Authenticate event in not implemented and hence no longer raises. In Classic mode, this event is raised when no authentication has occurred.


Workaround:

1) Change application to not rely on the DefaultAuthentication_OnAuthenticate event.  Instead, write an IHttpModule that inspects whether HttpContext.User is null to determine whether an authenticated user is present.

 

 

10) Applications that implement WindowsAuthentication_OnAuthenticate in global.asax will not be notified when the request is anonymous[M2]

If you define the WindowsAuthentication_OnAuthenticate method in global.asax, it will not be invoked for anonymous requests.  This is because anonymous authentication occurs after the WindowsAuthentication module can raise the OnAuthenticate event.

 

Workaround:

1) Change your application to not use the WindowsAuthentication_OnAuthenticate method.  Instead, implement an IHttpModule that runs in PostAuthenticateRequest, and inspects HttpContext.User.

 

Request limits and URL processing

The following changes result due to additional restrictions on how IIS processes incoming requests and their URLs.

 

11) Request URLs containing unencoded “+” characters in the path (not querystring) is rejected by default

You will receive HTTP Error 404.11 – Not Found: The request filtering module is configured to deny a request that contains a double escape sequence.

This error occurs because IIS is by default configured to reject attempts to doubly-encode a URL, which commonly represent an attempt to execute a canonicalization attack.
Workaround:

1) Applications that require the use of the “+” character in the URL path can disable this validation by setting the allowDoubleEscaping attribute in the system.webServer/security/requestFiltering configuration section in the application’s web.config.  However, this may make your application more vulnerable to malicious URLs:

<system.webServer>

<security>

<requestFiltering allowDoubleEscaping=”true” />

</security>

</system.webServer>

 

12) Requests with querystrings larger then 2048 bytes will be rejected by default

You will receive an HTTP Error 404.15 – Not Found: The request filtering module is configured to deny a request where the query string is too long.

IIS by default is configured to reject querystrings longer than 2048 bytes.  This may affect your application if it uses large querystrings or uses cookieless ASP.NET features like Forms Authentication and others that cumulatively exceed the configured limit on the querystring size.

NOTE: This breaking change applies to both Classic and Integrated modes.


Workaround
:

1) Increase the maximum querystring size by setting the maxQueryString attribute on the requestLimits element in the system.webServer/security/requestFiltering configuration section in your application’s web.config:

<system.webServer>

<security>

<requestFiltering>

<requestLimits maxQueryString=”NEW_VALUE_IN_BYTES” />

</requestFiltering>

</security>

</system.webServer>

Changes in response header processing

These changes affect how response headers are generated by the application.

 

13) IIS always rejects new lines in response headers (even if ASP.NET enableHeaderChecking is set to false)

If your application writes headers with line breaks (any combination of \r, or \n), you will receive an ASP.NET 500 – Server Error: Value does not fall within the expected range.

IIS will always reject any attempt to produce response headers with line breaks, even if ASP.NET’s enableHeaderChecking behavior is disabled.  This is done to prevent header splitting attacks.

NOTE: This breaking change applies to both Classic and Integrated modes.

 

14) When the response is empty, the Content-Type header is not suppressed

If the application sets a Content-Type header, it will remain present even if the response is cleared.  Requests to ASP.NET content types will typically have the “Content-Type: text/html” present on responses unless overridden by the application.
Workaround:
1) While this should not typically have a breaking effect, you can remove the Content-Type header by explicitly setting the HttpResponse.ContentType property to null when clearing the response.

 

15) When the response headers are cleared with HttpResponse.ClearHeaders, default ASP.NET headers are not generated.  This may result in the lack of Cache-Control: private header that prevents the caching of the response on the client

HttpResponse.ClearHeaders does not re-generate default ASP.NET response headers, including “Content-Type: text/html” and “Cache-Control: private”, as it does in Classic mode.  This is because ASP.NET modules may call this API for requests to any resource type, and therefore generating ASP.NET-specific headers is not appropriate.  The lack of the “Cache-Control” header may cause some downstream network devices to cache the response.
Workaround:
1) Change application to manually generate the Cache-Control: private header when clearing the response, if it is desired to prevent caching in downstream network devices.

 

Changes in application and module event processing

These changes affect how the application and module event processing takes place.

 

16) It is not possible to access the request through the HttpContext.Current property in Application_Start in global.asax

If your application accesses the current request context in the Application_Start method in global.asax as part of application initialization, you will receive an ASP.NET 500 – Server Error: Request is not available in this context.

This error occurs because ASP.NET application initialization has been decoupled from the request that triggers it.  In Classic mode, it was possible to indirectly access the request context by accessing the HttpContext.Current property.  In Integrated mode, this context no longer represents the actual request and therefore attempts to access the Request and Response objects will generate an exception.


Workaround:

1) See Request is not available in this context exception in Application_Start for a detailed description of this problem and available workarounds.

 

17) The order in which module event handlers execute may be different then in Classic mode

The following differences exist:

–       For each event, event handlers for each module are executed in the order in which modules are configured in the <modules> configuration section.  Global.asax event handlers are executed last.

–       Modules that register for the PreSendRequestHeaders and PreSendRequestContent events are notified in the reverse of the order in which they appear in the <modules> configuration section

–       For each event, synchronous event handlers for each module are executed before asynchronous handlers.  Otherwise, event handlers are executed in the order in which they are registered.

Applications that have multiple modules configured to run in either of these events may be affected by these change if they share a dependency on event ordering.  This is not likely for most applications.  The order in which modules execute can be obtained from a Failed Request Tracing log.
Workaround:
1) Change the order of the modules experiencing an ordering problem in the system.webServer/modules configuration section.

 

18) ASP.NET modules in early request processing stages will see requests that previously may have been rejected by IIS prior to entering ASP.NET.  This includes modules running in BeginRequest seeing anonymous requests for resources that require authentication.

ASP.NET modules can run in any pipeline stages that are available to native IIS modules.  Because of this, requests that previously may have been rejected in the authentication stage (such as anonymous requests for resources that require authentication) or other stages prior to entering ASP.NET may run ASP.NET modules.

This behavior is by design in order to enable ASP.NET modules to extend IIS in all request processing stages.

 

Workaround:

1) Change application code to avoid any application-specific problems that arise from seeing requests that may be rejected later on during request processing.  This may involve changing modules to subscribe to pipeline events that are raised later during request processing.

 

 

Other application changes

Other changes in the behavior of ASP.NET applications and APIs.

 

 

19) DefaultHttpHandler is not supported.  Applications relying on sub-classes of DefaultHttpHandler will not be able to serve requests.[M3]

If your application uses DefaultHttpHandler or handlers that derive from DefaultHttpHandler, it will not function correctly.  In Integrated mode, handlers derived from DefaultHttpHandler will not be able to pass the request back to IIS for processing, and instead serve the requested resource as a static file.  Integrated mode allows ASP.NET modules to run for all requests without requiring the use of DefaultHttpHandler.

 

Workaround:

1) Change your application to use modules to perform request processing for all requests, instead of using wildcard mapping to map ASP.NET to all requests and then using DefaultHttpHandler derived handlers to pass the request back to IIS.

 

 

20) It is possible to write to the response after an exception has occurred.

In Integrated mode, it is possible to write to and display an additional response written after an exception has occurred, typically in modules that subscribe to the LogRequest and EndRequest events. This does not occur in Classic mode. If an error occurs during the request, and the application writes to the response in EndRequest after the exception has occurred, the response information written in EndRequest will be shown. This only affects requests that include unhandled exceptions. To avoid writing to the response after an exception, an application should check HttpContext.Error or HttpResponse.StatusCode before writing to the response.

 

 

21) It is not possible to use the ClearError API to prevent an exception from being written to the response if the exception has occurred in a prior pipeline stage

Calling Server.ClearError during the EndRequest event does not clear the exception if it occurred during an earlier event within the pipeline.  This is because the exception is formatted to the response at the end of each event that raises an exception.

Workaround:

1) Change your application to call Server.ClearError from the Application_OnError event handler, which is raised whenever an exception is thrown.

 

 

22) HttpResponse.AppendToLog does not automatically prepend the querystring to the URL.[M4]

When using HttpResponse.AppendToLog to append a custom string to the URL logged in the request log file, you will manually need to prepend the querystring to the string you pass to this API.  This may result in existing code losing the querystring from the logged URL when this API is used.
Workaround:

1) Change your application to manually prepend HttpResponse.QueryString.ToString() to the string passed to HttpResponse.AppendToLog.

 

Other changes

Other changes.

 

23) ASP.NET threading settings are not used to control the request concurrency in Integrated mode

The minFreeThreads, minLocalRequestFreeThreads settings in the system.web/httpRuntime configuration section and the maxWorkerThreads setting in the processModel configuration section no longer control the threading mechanism used by ASP.NET.  Instead, ASP.NET relies on the IIS thread pool and allows you to control the maximum number of concurrently executing requests by setting the MaxConcurrentRequestsPerCPU DWORD value (default is 12) located in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0 key.  This setting is global and cannot be changed for individual application pools or applications.

 

Workaround:

1) To control the concurrency of your application, set the MaxConcurrentRequestsPerCPU setting.

 

24) ASP.NET application queues are not used in Integrated mode.  Therefore, the “ASP.NET Applications\Requests in Application Queue” performance counter will always have a value of 0

ASP.NET does not use application queues in Integrated mode.

 

25) IIS 7.0 always restarts ASP.NET applications when changes are made to the application’s root web.config file.  Because of this, waitChangeNotification and maxWaitChangeNotification attributes have no effect.

IIS 7.0 monitors changes to the web.config files as well, and cause the ASP.NET application corresponding to this file to be restarted without regard to the ASP.NET change notification settings including the waitChangeNotification and maxWaitChangeNotification attributes in the system.web/httpRuntime configuration sections.

 

 

26) ASP.NET deadlock detection is not supported in Integrated mode.

ASP.NET 2.0 Classic mode supports a deadlock detection mechanism which monitors ASP.NET responses and considers the process deadlocked if no responses have been received in more then the amount of time specified in the <processModel responseDeadlockInterval> setting, and there are more than a certain number of requests outstanding.  In this case, the process is marked unhealthy and a new process is eventually started.  In Integrated mode, this feature is not supported.  If your application is prone to deadlocks, it may lead to deadlock conditions being undetected, however it should have no effect on healthy applications that do not exhibit deadlocks.

 

I have excerpted a good article on page methods technique, hope fully you will take advantage of it.

This article shows you how to use ASP.NET AJAX PageMethods to perform Create, Read, Update and Delete (CRUD) operations with an HTML table. Here HTML table acts as a light-weight DataGrid.

Inorder to make PageMethods work, following things need to be done:

  1. ScriptManager should be added to your ASPX page.
  2. EnablePageMethods property of the ScriptManager should be set to true.
  3. System.Web.Services namespace should be added as reference on your codebehind class.
  4. Page Methods on your code-behind should be decorated with [WebMethod] attribute.

First let us start with Read.

As mentioned above, add a ScriptManager and set its ‘EnablePageMethods’ property to true. Add an HTML button and an onclick handler to it, and then add an HTML table with thead, tbody and tfoot. Since the HTML table will be referenced from javascript, add id to the table and its body. Here, only HTML tags/controls are used because, server side controls cannot be referenced in PageMethods.


Your ASPX page should look something like this.

<body>

<form id=”form1″ runat=”server”>

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” EnablePageMethods =”true” ></asp:ScriptManager>

<%–This click event handles loading data from the database–%>

<input id=”btn_load” type=”button” value=”Load” onclick = “LoadData()” />

<br /><br />

<div>

<table style=” height: 100%; border: solid 1px #000″ cellpadding=”0″ cellspacing=”1″ id=”tbl_grid” border = “1”>

<thead style = “background-color: #666; color: #fff”>

<tr>

<td style=”width: 100px;”>

Column1

</td>

<td style=”width: 500px;”>

Column2

</td>

<td style=”width: 150px;”>

Edit

</td>

</tr>

</thead>

<tbody id=”tbody_grid”>

</tbody>

<tfoot>

<tr>

<td style=”width: 100px;”>

<input id=”txt_addcol1″ style =”width: 30px” type=”text” />

</td>

<td style=”width: 500px;”>

<input id=”txt_addcol2″ type=”text”  style =”width: 300px” />

</td>

<td style=”width: 150px;”>

<%–This click event handles adding data to the database–%>

<input id=”btn_add” type=”button” onclick = “Add()” value=”Add” />

</td>

</tr>

</tfoot>

</table>

</div>

</form>

</body>

Now add your JavaScript function to load data from the database using PageMethods. PageMethod call should always have a success handler (this will be executed if the page method is executed successfully) and an exception handler (this will be executed if an exception is thrown). Say suppose we added ‘GetData()’ as the page method on the code behind, our javascript will be PageMethods.GetData(SuccessHandler, ExceptionHandler). Just for understanding, I have named the success and exception handler appropriately, you can name them as you wish. In case, the page methods takes parameters, you can add like PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler).

Page methods should be decorated with [WebMethod] attribute and should be declared as static. Its signature shoul look something like this:

[WebMethod]

public static string GetData()



Page method to return data to javascript.

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

{

protected void Page_Load(object sender, EventArgs e)

{

}

[WebMethod]

public static IEnumerable<MyEntity> GetData()

{

try

{

Data fetch part should go here

// used List, as collections are serializable. See below for MyEntity class

List<MyEntity> MyEntities = new List<MyEntity>();

MyEntities.Add(“1”, “abc”);

MyEntities.Add(“2”, “xyz”);

MyEntities.Add(“3”, “pqr”);

MyEntities.Add(“4”, “mno”);

return MyEntities;

}

catch(Exception ex)

{

throw ex;

}

}
}

MyEntity class

public class MyEntity

{

private string _Column1;

public string Column1

{

get { return _Column1; }

set { _Column1 = value; }

}

private string _Column2;

public string Column2

{

get { return _Column2; }

set { _Column2 = value; }

}

public MyEntity(string sCol1, string sCol2)

{

_Column1 = sCol1;

_Column2 = sCol2;

}

}

Javascript function that calls page method and populates the HTML table

<script type =”text/javascript” language = “javascript “>

//Loading Data

// Handles btn_load click event

function LoadData() {

// If data was fetched successfully, SuccessHandler will be called; else, ExceptionHandler

PageMethods.GetData(SuccessHandler, ExceptionHandler);

// Incase parameters need to be passed to PageMethods, you can do like this PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler)

}

// After fetching the data successfully

function SuccessHandler(result) {

var tbody = $get(“tbody_grid”);

// clear the table

for (var j = tbody.rows.length; j > 0; j–) {

tbody.deleteRow(j – 1);

}

// populate the table

for (var i = 0; i < result.length; i++) {

//two columns fetched from database are sent as parameters

AddRow(result[i].Column1, result[i].Column2);

}

return true;

}

// Edit and Delete buttons are added to the rows

function AddRow(col1, col2) {

var tbody = $get(“tbody_grid”);

var row = document.createElement(“tr”)

var td1 = document.createElement(“td”)

td1.innerText = col1;

var td2 = document.createElement(“td”);

td2.innerText = col2;

var td3 = document.createElement(“td”);

// add buttons

var btnEdit = document.createElement(‘input’);

btnEdit.setAttribute(‘type’, ‘button’);

btnEdit.setAttribute(‘name’, ‘Edit’);

btnEdit.setAttribute(‘value’, ‘Edit’);

// first parentNode represents <td> and the second represents <tr>

btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };

var btnDelete = document.createElement(‘input’);

btnDelete.setAttribute(‘type’, ‘button’);

btnDelete.setAttribute(‘name’, ‘Delete’);

btnDelete.setAttribute(‘value’, ‘Delete’);

btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };

td3.appendChild(btnEdit);

td3.appendChild(btnDelete);

row.appendChild(td1);

row.appendChild(td2);

row.appendChild(td3);

tbody.appendChild(row);

}

// Handles exception

function ExceptionHandler(result) {

}

After populating the HTML table



Javascript functions to handle Edit, Update, Delete and Insert:


Editing Data

//  this function handles edit button click

function Edit(row) {

var col1 = row.childNodes[0].innerText;

var col2 = row.childNodes[1].innerText;

// populates values in textboxes and displays Update and Cancel buttons

var editableRow = document.createElement(“tr”)

var td1 = document.createElement(“td”)

var txtBox1 = document.createElement(‘input’);

txtBox1.setAttribute(‘type’, ‘text’);

txtBox1.setAttribute(‘name’, ‘col1’);

txtBox1.setAttribute(‘value’, col1);

txtBox1.setAttribute(‘width’, 30);

td1.appendChild(txtBox1);

var td2 = document.createElement(“td”);

var txtBox2 = document.createElement(‘input’);

txtBox2.setAttribute(‘width’, 300);

txtBox2.setAttribute(‘type’, ‘text’);

txtBox2.setAttribute(‘name’, ‘col1’);

txtBox2.setAttribute(‘value’, col2);

td2.appendChild(txtBox2);

var td3 = document.createElement(“td”);

var btnUpdate = document.createElement(‘input’);

btnUpdate.setAttribute(‘type’, ‘button’);

btnUpdate.setAttribute(‘name’, ‘Update’);

btnUpdate.setAttribute(‘value’, ‘Update’);

btnUpdate.onclick = function() { Update(this.parentNode.parentNode); };

var btnCancel = document.createElement(‘input’);

btnCancel.setAttribute(‘type’, ‘button’);

btnCancel.setAttribute(‘name’, ‘Cancel’);

btnCancel.setAttribute(‘value’, ‘Cancel’);

btnCancel.onclick = function() { Cancel(this.parentNode.parentNode); };

td3.appendChild(btnUpdate);

td3.appendChild(btnCancel);

editableRow.appendChild(td1);

editableRow.appendChild(td2);

editableRow.appendChild(td3);

row.parentNode.replaceChild(editableRow, row);

}

After edit button click

Updating Data

//  this function handles update button click

function Update(row) {

// fetches values entered in the textboxes

// first childNode represent <td> inside <tr> and second childNode represents textbox

var col1 = row.childNodes[0].childNodes[0].value;

var col2 = row.childNodes[1].childNodes[0].value;

// values sent to server

PageMethods.UpdateData(col1, col2, UpdateSuccess(row), ExceptionHandler);

}

// After updating the values successfully

function UpdateSuccess(row) {

var col1 = row.childNodes[0].childNodes[0].value;

var col2 = row.childNodes[1].childNodes[0].value;

var editableRow = document.createElement(“tr”)

var td1 = document.createElement(“td”)

td1.innerText = col1;

var td2 = document.createElement(“td”);

td2.innerText = col2;

var td3 = document.createElement(“td”);

var btnEdit = document.createElement(‘input’);

btnEdit.setAttribute(‘type’, ‘button’);

btnEdit.setAttribute(‘name’, ‘Edit’);

btnEdit.setAttribute(‘value’, ‘Edit’);

btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };

var btnDelete = document.createElement(‘input’);

btnDelete.setAttribute(‘type’, ‘button’);

btnDelete.setAttribute(‘name’, ‘Delete’);

btnDelete.setAttribute(‘value’, ‘Delete’);

btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };

td3.appendChild(btnEdit);

td3.appendChild(btnDelete);

editableRow.appendChild(td1);

editableRow.appendChild(td2);

editableRow.appendChild(td3);

row.parentNode.replaceChild(editableRow, row);

}

// this function handles cancel button click

function Cancel(row) {

// values are again populated in labels instead of textboxes

var col1 = row.childNodes[0].childNodes[0].value;

var col2 = row.childNodes[1].childNodes[0].value;

var editableRow = document.createElement(“tr”)

var td1 = document.createElement(“td”)

td1.innerText = col1;

var td2 = document.createElement(“td”);

td2.innerText = col2;

var td3 = document.createElement(“td”);

var btnEdit = document.createElement(‘input’);

btnEdit.setAttribute(‘type’, ‘button’);

btnEdit.setAttribute(‘name’, ‘Edit’);

btnEdit.setAttribute(‘value’, ‘Edit’);

btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };

var btnDelete = document.createElement(‘input’);

btnDelete.setAttribute(‘type’, ‘button’);

btnDelete.setAttribute(‘name’, ‘Delete’);

btnDelete.setAttribute(‘value’, ‘Delete’);

btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };

td3.appendChild(btnEdit);

td3.appendChild(btnDelete);

editableRow.appendChild(td1);

editableRow.appendChild(td2);

editableRow.appendChild(td3);

row.parentNode.replaceChild(editableRow, row);

}

//  this function handles ‘add’ button click

function Add() {

var col1 = $get(“txt_addcol1”).value;

var col2 = $get(“txt_addcol2”).value;

// data sent to the database

PageMethods.InsertData(col1, col2, AddSuccess(col1, col2), ExceptionHandler);

}

// After adding the data successfully

function AddSuccess(col1, col2) {

// add the values to the table

AddRow(col1, col2);

// clear the textboxes in the footer

$get(“txt_addcol1”).value = “”;

$get(“txt_addcol2”).value = “”;

}

Deleting Data

// this function handles delete button click

function DeleteRow(row) {

var col1 = row.childNodes[0].innerText;

// delete from the database

PageMethods.DeleteData(col1, DeleteSuccess(row), ExceptionHandler);

}

function DeleteSuccess(row) {

// delete the row from the table

var tbody = $get(“tbody_grid”);

tbody.removeChild(row);

}

</script>

Page methods to handle Edit, Update, Delete and Insert:

[WebMethod]

public static void UpdateData(string sCol1, string sCol2)

{

try

{

Data update part should go here

}

catch(Exception ex)

{

throw ex;

}

}

[WebMethod]

public static void InsertData(string sCol1, string sCol2)

{

try

{

Data insert part should go here

}

catch(Exception ex)

{

throw ex;

}

}

[WebMethod]

public static void DeleteData(string sCol1)

{

try

{

Data delete part should go here

}

catch (Exception ex)

{

throw ex;

}

}

}

We can add paging and sorting too.


This code has been tested in IE7+, Firefox, Chrome and Safari.

Some of the limitations in using ASP.NET AJAX PageMethods:

1.       We can’t access asp.net server controls (like TextBox control) in the WebMethod directly as we normally access in the server side methods.

2.       We can’t access any variable declared in the code behind.

Advantage: PageMethods is a simple lightweight way to submit/fetch data to the server using ASP.NET AJAX. This doesn’t submit whole page data to the server and also as opposed to the ASP.NET AJAX call back this doesn’t even fire the Page_Load and other Page events of the code behind page

Enabling AJAX in SharePoint applications was a really tough job, I spent a lot of time to get it work and now I want to save time of others developers. Just follow me on the steps and at the end we will be able to add a web part with AJAX functionality.

I am dividing my post in 2 steps

STEP 1 : in step 1 I will do the necessary web.config modifications. I am pulling all these settings through “FeatureInstalled” event of a feature with Web Application level scope, have a look at the following code

<?xml version=”1.0″ encoding=”utf-8″ ?>

<Feature Id=”c9cf98e2-cc0e-4464-914c-4c974ec2e133″

Scope=”Web”

Title=”UI Feature ”

Description=”This feature enables the UI functionality within a SharePoint Site.”

Version=”1.0.0.0″

Creator=”Shafaqat Ali”

SolutionId=”62298653-d7de-4b56-b50f-5df3d116e590″

ImageUrl=””

ImageUrlAltText=”My Feature Icon”

Hidden=”FALSE”

ActivateOnDefault=”FALSE”

AlwaysForceInstall=”FALSE”

AutoActivateInCentralAdmin=”FALSE”

RequireResources=”FALSE”

DefaultResourceFile=”MyResourceFile”

ReceiverAssembly=”UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6669f18c4e55eb20″

ReceiverClass=”UI.UIFeatureReceiver”

xmlns=”http://schemas.microsoft.com/sharepoint/”&gt;

<ElementManifests>

<ElementManifest Location=”Elements.xml” />

</ElementManifests>

</Feature>

Feature receiver code behind file, lengthy code you can copy paste it.

/***********************************************************************************

public override void FeatureInstalled(SPFeatureReceiverProperties properties) {

#region Extend the SharePoint web.config file, which is typically found in a directory with the following structure

//For ASP.NET 2.0 AJAX Extensions

//1. Add the following <sectionGroup> elements within the <configSections> element.

SPWebConfigModification sectionGroup = this.GetConfigurationSettingsforAJAX();

//2. Add the following controls declaration within the <pages> element, which is located within the <system.web> element.

SPWebConfigModification controlInPages = this.GetControlInPagesSettings();

//3. Add the following assembly declaration within the <assemblies> element.

SPWebConfigModification assembly1 = this.GetAssembly1Settings();

//4. Add the following verb handlers within the <httpHandlers> element.

SPWebConfigModification verb1 = this.GetVerb1Settings();

SPWebConfigModification verb2 = this.GetVerb2Settings();

SPWebConfigModification verb3 = this.GetVerb3Settings();

SPWebConfigModification verb4 = this.GetVerb4Settings();

//5. Add the following script module handler within the <httpModules> element.

SPWebConfigModification scriptmodulehandler = this.GetScriptModuleSettings();

//6.  Add the following safe control entry within the <SafeControls> element, which is located within the <SharePoint> element.

SPWebConfigModification safecontrol = this.GetSafeControlsSettings();

//7. Add the following scripting web service handlers within the <configuration> element.

SPWebConfigModification systemwebextensions = this.GetWebExtensionsSettings();

// These settings are required for AJAX implemenation

SPWebConfigModification systemwebServer = this.GetSystemWebServerSettings();

#endregion

//System.Diagnostics.Debug.Assert(false);

// Iterate through all the Web Applications and apply the changes

SPWebApplicationCollection webAppCollection = SPWebService.ContentService.WebApplications;

System.Collections.IEnumerator enumerator = webAppCollection.GetEnumerator();

while (enumerator.MoveNext())

{

SPWebApplication webApplication = (SPWebApplication)enumerator.Current;

//SPWeb web = properties.Feature.Parent;

webApplication.WebConfigModifications.Add(sectionGroup); webApplication.WebConfigModifications.Add(controlInPages);

webApplication.WebConfigModifications.Add(assembly1);

webApplication.WebConfigModifications.Add(verb2);

webApplication.WebConfigModifications.Add(verb3);

webApplication.WebConfigModifications.Add(verb4);

webApplication.WebConfigModifications.Add(scriptmodulehandler);

webApplication.WebConfigModifications.Add(safecontrol);

webApplication.WebConfigModifications.Add(systemwebextensions);

webApplication.WebConfigModifications.Add(systemwebServer);

webApplication.Update(true);

webApplication.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

}

// We also want to propagate these web.config changes across the farm

//SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

}

private SPWebConfigModification GetConfigurationSettingsforAJAX()

{

SPWebConfigModification sectionGroup = new SPWebConfigModification();

sectionGroup.Path = “configuration/configSections”;

sectionGroup.Name = “sectionGroup[@name=’system.web.extensions’][@type=’System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′]”;

sectionGroup.Sequence = 4;

sectionGroup.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

sectionGroup.Value = “<sectionGroup name=’system.web.extensions’ type=’System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′>”

+ “<sectionGroup name=’scripting’ type=’System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′>”

+ “<section name=’scriptResourceHandler’ type=’System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ requirePermission=’false’ allowDefinition=’MachineToApplication’ />”

+ “<sectionGroup name=’webServices’ type=’System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′>”

+ “<section name=’profileService’ type=’System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ requirePermission=’false’ allowDefinition=’MachineToApplication’ />”

+ “<section name=’authenticationService’ type=’System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ requirePermission=’false’ allowDefinition=’MachineToApplication’ />”

+ “</sectionGroup></sectionGroup></sectionGroup>”;

return sectionGroup;

}

private SPWebConfigModification GetControlInPagesSettings()

{

SPWebConfigModification controlInPages = new SPWebConfigModification();

controlInPages.Path = “configuration/system.web/pages”;

controlInPages.Name = “controls”;

controlInPages.Sequence = 6;

controlInPages.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

controlInPages.Value = “<controls><add tagPrefix=’asp’ namespace=’System.Web.UI’ assembly=’System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ /></controls>”;

return controlInPages;

}

private SPWebConfigModification GetAssembly1Settings()

{

SPWebConfigModification assembly1 = new SPWebConfigModification();

assembly1.Path = “configuration/system.web/compilation/assemblies”;

assembly1.Name = “add[@assembly=’System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′]”;

assembly1.Sequence = 7;

assembly1.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

assembly1.Value = “<add assembly=’System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”;

return assembly1;

}

private SPWebConfigModification GetVerb1Settings()

{

SPWebConfigModification verb1 = new SPWebConfigModification();

verb1.Path = “configuration/system.web/httpHandlers”;

verb1.Name = “remove[@verb=’*’][@path=’*.asmx’]”;

verb1.Sequence = 8;

verb1.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

verb1.Value = “<!–<remove verb=’*’ path=’*.asmx’ />–>”;

return verb1;

}

private SPWebConfigModification GetVerb2Settings()

{

SPWebConfigModification verb2 = new SPWebConfigModification();

verb2.Path = “configuration/system.web/httpHandlers”;

verb2.Name = “add[@verb=’*’][@path=’*.asmx’][@validate=’false’][@type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′]”;

verb2.Sequence = 9;

verb2.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

verb2.Value = “<add verb=’*’ path=’*.asmx’ validate=’false’ type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”;

return verb2;

}

private SPWebConfigModification GetVerb3Settings()

{

SPWebConfigModification verb3 = new SPWebConfigModification();

verb3.Path = “configuration/system.web/httpHandlers”;

verb3.Name = “add[@verb=’*’][@path=’*_AppService.axd’][@validate=’false’][@type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′]”;

verb3.Sequence = 10;

verb3.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

verb3.Value = “<add verb=’*’ path=’*_AppService.axd’ validate=’false’ type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”;

return verb3;

}

private SPWebConfigModification GetVerb4Settings()

{

SPWebConfigModification verb4 = new SPWebConfigModification();

verb4.Path = “configuration/system.web/httpHandlers”;

verb4.Name = “add[@verb=’GET,HEAD’][@path=’ScriptResource.axd’][@type=’System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′][@validate=’false’]”;

verb4.Sequence = 11;

verb4.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

verb4.Value = “<add verb=’GET,HEAD’ path=’ScriptResource.axd’ type=’System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ validate=’false’ />”;

return verb4;

}

private SPWebConfigModification GetScriptModuleSettings()

{

SPWebConfigModification scriptmodulehandler = new SPWebConfigModification();

scriptmodulehandler.Path = “configuration/system.web/httpModules”;

scriptmodulehandler.Name = “add[@name=’ScriptModule’][@type=’System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′]”;

scriptmodulehandler.Sequence = 12;

scriptmodulehandler.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

scriptmodulehandler.Value = “<add name=’ScriptModule’ type=’System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”;

return scriptmodulehandler;

}

private SPWebConfigModification GetSafeControlsSettings()

{

SPWebConfigModification safecontrol = new SPWebConfigModification();

safecontrol.Path = “configuration/SharePoint/SafeControls”;

safecontrol.Name = “SafeControl[@Assembly=’System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′][@Namespace=’System.Web.UI’][@TypeName=’*’][@Safe=’True’]”;

safecontrol.Sequence = 13;

safecontrol.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

safecontrol.Value = “<SafeControl Assembly=’System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ Namespace=’System.Web.UI’ TypeName=’*’ Safe=’True’ />”;

return safecontrol;

}

private SPWebConfigModification GetWebExtensionsSettings()

{

SPWebConfigModification systemwebextensions = new SPWebConfigModification();

systemwebextensions.Path = “configuration”;

systemwebextensions.Name = “system.web.extensions”;

systemwebextensions.Sequence = 14;

systemwebextensions.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

systemwebextensions.Value = “<system.web.extensions><scripting><webServices></webServices></scripting></system.web.extensions>”;

return systemwebextensions;

}

private SPWebConfigModification GetSystemWebServerSettings()

{

SPWebConfigModification systemwebServer = new SPWebConfigModification();

systemwebServer.Path = “configuration”;

systemwebServer.Name = “system.webServer”;

systemwebServer.Sequence = 15;

systemwebServer.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

systemwebServer.Value = “<system.webServer><validation validateIntegratedModeConfiguration=’false’ /><modules><add name=’ScriptModule’ preCondition=’integratedMode’ type=’System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”

+ “</modules><handlers><remove name=’WebServiceHandlerFactory-Integrated’ /><add name=’ScriptHandlerFactory’ verb=’*’ path=’*.asmx’ preCondition=’integratedMode’ type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”

+ “<add name=’ScriptHandlerFactoryAppServices’ verb=’*’ path=’*_AppService.axd’ preCondition=’integratedMode’ type=’System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ />”

+ “<add name=’ScriptResource’ preCondition=’integratedMode’ verb=’GET,HEAD’ path=’ScriptResource.axd’ type=’System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ /></handlers></system.webServer>”;

return systemwebServer;

}

***********************************************************************************/

Step 1 is complete, all required settings for AJAX functionality have been implemented, you can check AJAX functionality by adding a simple logic on any page your sharepoint site.

Let’s move to step 2

STEP2

create a simple class say “MyFirstWebPart” and inherit it form “Microsoft.SharePoint.WebPartPages.WebPart” class

public class MyFirstWebPart: Microsoft.SharePoint.WebPartPages.WebPart

{

private string imagepath;

[DefaultValue(“”), WebBrowsable(true), Category(“ProgressTemplate”), Personalizable(PersonalizationScope.Shared)]

public string ImagePath

{

get { return imagepath; }

set { imagepath = value; }

}

private string disptext;

[DefaultValue(“”), WebBrowsable(true), Category(“ProgressTemplate”), Personalizable(PersonalizationScope.Shared)]

public string DisplayText

{

get { return disptext; }

set { disptext = value; }

}

protected override void CreateChildControls()

{

base.CreateChildControls();

UpdatePanel updatePanel1 = new UpdatePanel();

updatePanel1.ID = “udpItemListingWebPart”;

updatePanel1.UpdateMode = UpdatePanelUpdateMode.Conditional;

UpdateProgress updateProgress1 = new UpdateProgress();

updateProgress1.AssociatedUpdatePanelID = “udpItemListingWebPart”;

updateProgress1.ProgressTemplate = new ProgressTemplate(ImagePath, DisplayText);

Button button1 = new Button();

button1.ID = “btnClick”;

button1.Text = “Update”;

button1.Click += new EventHandler(button1_Click);

Label label1 = new Label();

label1.ID = “lblShowTime”;

label1.Text = string.Format(“Updated at: {0} “, DateTime.Now.ToLongTimeString());

updatePanel1.ContentTemplateContainer.Controls.Add(label1);

updatePanel1.ContentTemplateContainer.Controls.Add(button1);

this.Controls.Add(updateProgress1);

ScriptManager sc = new ScriptManager();

this.Controls.AddAt(0, sc);

this.Controls.Add(updatePanel1);

}

void button1_Click(object sender, EventArgs e)

{

//this.label1.Text = string.Format(“Updated at: {0} “, DateTime.Now.ToLongTimeString());

}

protected override void Render(HtmlTextWriter writer)

{

base.Render(writer);

if (!this.Page.IsAsync)

{

string script = “”;

script = @”

var ITEMLISTINGBUTTONID;

with(Sys.WebForms.PageRequestManager.getInstance()){

add_beginRequest(onBeginRequest);

add_endRequest(onEndRequest);

}

function onBeginRequest(sender, args){

ITEMLISTINGBUTTONID = args.get_postBackElement().id;

$get(ITEMLISTINGBUTTONID).parentElement.style.display = ‘none’;

}

function onEndRequest(sender, args){

$get(ITEMLISTINGBUTTONID).parentElement.style.display = ”;

}

“;

this.Page.ClientScript.RegisterStartupScript(this.GetType(), “HideSimpleAJAXWebPartUDP”, script, true);

}

}

}

public class ProgressTemplate : ITemplate

{

private string imagepath;

public string ImagePath

{

get { return imagepath; }

set { imagepath = value; }

}

private string disptext;

public string DisplayText

{

get { return disptext; }

set { disptext = value; }

}

public ProgressTemplate(string imagePath, string displayText)

{

ImagePath = imagePath;

DisplayText = displayText;

}

public void InstantiateIn(Control container)

{

Image img = new Image();

img.ImageUrl = SPContext.Current.Site.Url + “/” + ImagePath;

Label lbl = new Label();

lbl.Text = DisplayText;

container.Controls.Add(img);

container.Controls.Add(lbl);

}

}

Now add your assembly to safe controls list

<SafeControl Assembly=”YourAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6669f18c4e55eb20″ Namespace=”UI.Code” TypeName=”*” Safe=”True” />

Refresh the page you will see this screen

1

I know the code is very complex, try at your end, if you find any problem or stuck anywhere do contact me.

Upto Visual Studio 2008, one can set the Title of the page declaratively or through program using Page.Title.  However, as more and more web traffic is happening through search engines, Page’s Title, Keyword and description become more important.  Although the Keyword feature was exploited and hence many search engines today ignore it, Page Description is something still major search engines such as Google, Bing use for identifying and indexing pages based on content.

The new feature in ASP.NET 4.0 allows users to programmatically set the Page Description and Keywords as follows:-

protected void Page_Load(object sender, EventArgs e)
{

this.Page.Title = “My ASP.NET Blog”;

this.Page.MetaKeywords = “ASP.NET, Web Development, Blog, ASP.NET Blog”;

this.Page.MetaDescription = “This Blog contains posts related to ASP.NET and Web Development”;

}

The above code appends the following markup

<meta content=”ASP.NET, Web Development, Blog, ASP.NET Blog” />

<meta content=”This Blog contains posts related to ASP.NET and Web Development” />

And the way it works is that, if the meta tags are already present in the HTML markup, whatever is set in the code behind  will fill up the “content” part alone if the “name” tag is matching.

Although this looks simple, it is very useful in cases where you want to set these dynamically based on a condition / criteria.  So far, these were set statically in the HTML.  Now with Page Class level access, these can be set dynamically.

ASP.NET 4.0 has many improvements for different set of scenarios such as Webforms, Dynamic Data & AJAX based web development.  There are also a lot of enhancements to the core runtime that powers ASP.NET such as Caching, Session & Request/Response objects.

For this post, we will examine some of the web form enhancements.  There are sure a lot of them and we will examine some of them in the future posts.

Controlling View State using the ViewStateMode Property – Performance Enhancement

One of the most complained thing in ASP.NET Webform is the growing viewstate which becomes a concern for performance.  While earlier you can set the EnableViewState property to true or false, post that, all the controls, by default inherit and even if you set it to enabled at control level, the behaviour was inconsistent.

With ASP.NET 4.0, the ViewStateMode property helps to determine for every control, whether the ViewState should be enabled, disabled or inherited accordingly.  Ex.-

<asp:Panel ID=”pnlViewState” runat=”server” ViewStateMode=”Disabled”>
Disabled: <asp:Label runat=”server”  Text=”Value set in markup” ViewStateMode=”Inherit” /><br />
Enabled: <asp:Label  runat=”server” Text=”Value set in markup” ViewStateMode=”Enabled” />
<hr />
<asp:button ID=”Button1″ runat=”server”  Text=”Postback” />
</asp:Panel>

In the code-behind

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
label1.Text = “Value set in code behind”;
label2.Text = “Value set in code behind”;
}
}

When you run the above page, you can find that the intial value for both the labels is set to “Value set in code behind” whereas after clicking on the button (postback), the value of label1 changes to “Value set in markup” whereas the value of label2 remains unchanged.  As you can see, the Panel which holds both these lables has ViewStateMode set to Disabled and label1 is inherting the mode (this is the default if not specified) and label2 has it enabled.  That is the reason label2 maintains viewstate while label1 loses it.

While it is arguably possible using the simple EnableViewState property earlier, it was never consistent.  Considering the fact that in most of our performance sessions, we talk about disabling viewstate and then enabling it at control level while it doesnt work, this ViewStateMode is a welcome architectural change to improve performance.

Next Page »