Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts

Thursday, July 10, 2008

SharePoint 2007 - Using .NET 3.5 AJAX / AjaxControlToolkit

One of the things Microsoft advertised with the release of SharePoint 2007 SP1, was the fact that SharePoint would now jive with AJAX. Although they had previously provided instructions on how to do it before SP1, it was never officially supported.* Unfortunately, once SP1 was released, it wasn't clear on how to get AJAX to work or what you should do if you had followed their previous instructions.

After much troubleshooting, I was finally able to find an easy solution. Essentially, if you had followed the previous instructions that added a couple dozen entries to your web.config, you could now simply use assembly bindings to redirect your old AJAX 1.1 assemblies to the new AJAX 3.5 assemblies.

Instructions

1.) Follow the instructions in the following SharePoint Team Blog post:

Integrating ASP.NET AJAX with SharePoint

2.) Add the following assembly bindings to your SharePoint web.config. (This will redirect your AJAX 1.1 assemblies to use AJAX 3.5.)

<configuration>
   <runtime>
      <assemblyBinding>
         <dependentAssembly>
            <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
         </dependentAssembly>
         <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

I also highly recommend Daniel Larson' blog if you are trying to troubleshoot SharePoint with AJAX.

Daniel Larson's Developer Blog

Update: I am including all web.config settings below. There are a whopping 8 updates!

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<
configuration>
<
configSections>
<!--
AJAX.NET SUPPORT 1 of 8 START-->
<
sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<
sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<
section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
<
sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<
section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" />
<
section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
<
section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
</
sectionGroup>
</
sectionGroup>
</
sectionGroup>
<!--
AJAX.NET SUPPORT 1 of 8 END-->
</
configSections>
<
SharePoint>
<
SafeControls>
<!--
AJAX.NET SUPPORT 2 of 8 START-->
<
SafeControl Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TypeName="*" Safe="True" />
<!--
AJAX.NET SUPPORT 2 of 8 END-->
</
SafeControls>
</
SharePoint>
<
system.web>
<
httpHandlers>
<!--
AJAX.NET SUPPORT 3 of 8 START-->
<
remove verb="*" path="*.asmx" />
<
add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<
add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<
add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false" />
<!--
AJAX.NET SUPPORT 3 of 8 END-->
</
httpHandlers>
<
httpModules>
<!--
AJAX.NET SUPPORT 4 of 8 START-->
<
add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<!--
AJAX.NET SUPPORT 4 of 8 END-->
</
httpModules>
<
compilation batch="false" debug="true">
<
assemblies>
<!--
AJAX.NET SUPPORT 5 of 8 END-->
<
add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<
add assembly="System.Web.Extensions.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<!--
AJAX.NET SUPPORT 5 of 8 START-->
</
assemblies>
</
compilation>
<
pages enableSessionState="false" enableViewState="true" enableViewStateMac="true" validateRequest="false" pageParserFilterType="Microsoft.SharePoint.ApplicationRuntime.SPPageParserFilter, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" asyncTimeout="7">
<!--
AJAX.NET SUPPORT 6 of 8 START-->
<
controls>
<
add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<
add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<
add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit, Version=3.0.20229.28221, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" tagPrefix="ajax" />
</
controls>
<!--
AJAX.NET SUPPORT 6 of 8 END-->
</
pages>
<
trust level="Full" originUrl="" />
</
system.web>
<!--
AJAX.NET SUPPORT 7 of 8 START-->
<
runtime>
<
assemblyBinding>
<
dependentAssembly>
<
assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
<
bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</
dependentAssembly>
<
dependentAssembly>
<
assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
<
bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</
dependentAssembly>
</
assemblyBinding>
</
runtime>
<!--
AJAX.NET SUPPORT 7 of 8 END-->
<!--
AJAX.NET SUPPORT 8 of 8 START-->
<
system.web.extensions>
<
scripting>
<
webServices>
<
jsonSerialization maxJsonLength="500000">
<
converters>
</
converters>
</
jsonSerialization>
</
webServices>
<
scriptResourceHandler enableCompression="false" enableCaching="true" />
</
scripting>
</
system.web.extensions>
<
system.webServer>
<
validation validateIntegratedModeConfiguration="false" />
<
modules>
<
add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</
modules>
<
handlers>
<
remove name="WebServiceHandlerFactory-ISAPI-2.0" />
<
add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<
add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, &#xD;&#xA; System.Web.Extensions, Version=3.5.0.0, Culture=neutral, &#xD;&#xA; PublicKeyToken=31bf3856ad364e35" />
<
add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, &#xD;&#xA; System.Web.Extensions, Version=3.5.0.0, Culture=neutral, &#xD;&#xA; PublicKeyToken=31bf3856ad364e35" />
</
handlers>
</
system.webServer>
<!--
AJAX.NET SUPPORT 8 of 8 END-->
</
configuration>



* Mike Fitzmaurice was Microsoft's SharePoint Developer Evangelist at the time and is now at Nintex.

Wednesday, February 27, 2008

GridView + DetailsView + LinqDataSource + ModalPopupExtender - Hello World Example

I recently found a limitation when using a GridView, DetailsView, LinqDataSource, and ModalPopupExtender that prevented any records other than the first to be displayed in the DetailsView shown in the ModalPopupExtender. Although I am told that this can be alleviated by using an UpdatePanel, I was working in an extranet environment using Juniper VPN which doesn't like UpdatePanels or at least rewrites the HTML in such a way that prevents an UpdatePanel from working properly. In order to get this to work, all you need to do is hook up the RowCommand and RowDataBound events of the GridView so that a CommandArgument is created and then subsequently used in a Linq query when the item is clicked. You will need SQLExpress with the Northwind sample database and a Linq to SQL Classes (dbml) file that point to the Products table to get this to work.

For amusement, you can read about my struggles in the ASP.NET Forum here: http://forums.asp.net/p/1224034/2195642.aspx Also, a special thanks from the tiredblogger with his post which got me on the right track. http://tiredblogger.wordpress.com/2007/09/16/using-a-modal-popup-to-modify-linq-gridviews/

Without further ado, the code:

ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Test.aspx.cs" Inherits="LinqTester.Test" EnableEventValidation="false" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!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 id="Head1" runat="server">
<title>Untitled Page</title>
<style type="text/css">
.modalBackground
{
background-color: Black;
filter: alpha(opacity=80);
opacity: 0.8;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div style="text-align: center;">
<table>
<tr>
<td style="text-align: left;">
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" DataKeyNames="ProductID"
AllowSorting="True" AutoGenerateColumns="False" DataSourceID="LinqDataSource1"
OnRowDataBound="GridView1_RowDataBound"
onrowcommand="GridView1_RowCommand">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="ProductName" ReadOnly="True"
SortExpression="ProductName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" ReadOnly="True"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="Details" runat="server" CommandName="ShowDetails" Text="Details"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</td>
</tr>
</table>
</div>
<asp:Panel ID="UpdateRecordPanel" runat="server" CssClass="" Style="display:none">
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" DataSourceID="LinqDataSource2"
Height="50px" Width="125px" BackColor="White">
<Fields>
<asp:BoundField DataField="ProductName" HeaderText="ProductName" ReadOnly="True"
SortExpression="ProductName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" ReadOnly="True"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" ReadOnly="True" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" ReadOnly="True"
SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" ReadOnly="True"
SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" ReadOnly="True"
SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" ReadOnly="True"
SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
<asp:Button ID="CancelPopupButton" runat="server" Text="Cancel" />
</asp:Panel>

<cc1:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
BackgroundCssClass="modalBackground"
CancelControlID="CancelPopupButton"
PopupControlID="UpdateRecordPanel"
TargetControlID="HiddenButton" >
</cc1:ModalPopupExtender>

<asp:Button ID="HiddenButton" runat="server" Style="display:none" />

<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="LinqTester.Data.NorthwindDataContext"
Select="new (ProductName, QuantityPerUnit, ProductID)" TableName="Products">
</asp:LinqDataSource>
<asp:LinqDataSource ID="LinqDataSource2" runat="server" ContextTypeName="LinqTester.Data.NorthwindDataContext"
Select="new (ProductName, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued)"
TableName="Products" Where="ProductID == @ProductID">
<WhereParameters>
<asp:ControlParameter ControlID="GridView1" Name="ProductID" PropertyName="SelectedValue"
DefaultValue="1" Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
</form>
</body>
</html>


ASPX.CS



using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using AjaxControlToolkit;

namespace LinqTester
{
public partial class Test : System.Web.UI.Page
{
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.Header && e.Row.RowType != DataControlRowType.Footer && e.Row.RowType != DataControlRowType.Pager)
{
LinkButton lb = e.Row.FindControl("Details") as LinkButton;
if (lb != null)
{
lb.CommandArgument = ((TableCell)e.Row.Controls[2]).Text;
}
}
}

protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "ShowDetails")
{
ProductDetails productDetails = GetProductDetails(Convert.ToInt32(e.CommandArgument));
DetailsView1.Rows[0].Cells[1].Text = productDetails.ProductName;
DetailsView1.Rows[1].Cells[1].Text = productDetails.Quantity;
DetailsView1.Rows[2].Cells[1].Text = productDetails.UnitPrice.ToString();
DetailsView1.Rows[3].Cells[1].Text = productDetails.UnitsInStock.ToString();
DetailsView1.Rows[4].Cells[1].Text = productDetails.UnitsOnOrder.ToString();
DetailsView1.Rows[5].Cells[1].Text = productDetails.ReorderLevel.ToString();
DetailsView1.Rows[6].Cells[1].Text = productDetails.Discontinued.ToString();
ModalPopupExtender1.Show();
}
}

private ProductDetails GetProductDetails(int productId)
{
LinqTester.Data.NorthwindDataContext northwind = new LinqTester.Data.NorthwindDataContext();
List productDetails = (from p in northwind.Products
where p.ProductID == productId
select new ProductDetails
{
ProductName = p.ProductName,
Quantity = p.QuantityPerUnit,
UnitPrice = p.UnitPrice.HasValue == true ? 0 : (int)p.UnitPrice,
UnitsInStock = p.UnitsInStock.HasValue == true ? 0 : (int)p.UnitsInStock,
UnitsOnOrder = p.UnitsOnOrder.HasValue == true ? 0 : (int)p.UnitsOnOrder,
ReorderLevel = p.ReorderLevel.HasValue == true ? 0 : (int)p.ReorderLevel,
Discontinued = p.Discontinued
}).ToList();
return productDetails[0];
}
}

public class ProductDetails
{
public string ProductName { get; set; }
public string Quantity { get; set; }
public decimal UnitPrice { get; set; }
public int UnitsInStock { get; set; }
public int UnitsOnOrder { get; set; }
public int ReorderLevel { get; set; }
public bool Discontinued { get; set; }
}

}

Sunday, November 25, 2007

Resolving an embedded Control ID in JavaScript

One of the great things about ASP.NET is that you have the ability to incorporate things like MasterPages, UserControls, and WebParts in your pages. Unfortunately, if you ever decide to do some client-side scripting for validation, AJAX, or any other reason, it becomes very cumbersome if you have to retrieve a given control's id. The old document.getElementById syntax isn't going to cut it. Fortunately, you can embed some handy ASP.NET rendering code syntax in your JavaScript to do the trick. Here's a simple example:

<asp:button id="ClickMe" runat="server" onmouseover="javascript:toggleMyControlColor();" onmouseout="javascript:toggleMyControlColor();" Text="Click Me" / >

function toggleMyControlColor()
{
    var myControl = $get('<%= ClickMe.ClientID %>');
    if(myControl.styles.backgroundColor == 'red')
    {
        myControl.styles.backgroundColor = 'blue'
        }
    else
    {
        myControl.styles.backgroundColor = 'red'
    }
}

I have used this technique in MasterPages, UserControls, and WebParts (including those hosted in SharePoint), and it works like a charm.