Tag Archives: .net

Output SQL Server Reporting Services (SSRS) Report as PDF from URL with VB.NET or C#.NET

Outputting an existing SQL Server Reporting Services (SSRS) report to a PDF via a web URL is a convenient way to distribute SSRS reports, invoices, or anything else from SSRS. This post focuses on an existing report; however, links to the basic set up for a report are included. The code to output an existing report as PDF are given and uses a ReportViewer control.

You can skip to the PDF Output section if your server is all set up with the ReportViewer controls.

The pieces and parts to output an SSRS report as a PDF were culled from several disparate sources. All sources are given appropriate credit for their work.

As an added bonus, VB.NET and C#.NET versions are shown.

Add Report Viewer Redistributable to Server

The ReportViewer controls need to be installed on the server and Microsoft provides the redistributable for that in their download center.

The Microsoft Report Viewer 2008 Redistributable Package includes Windows Forms and ASP.NET Web server controls for viewing reports designed using Microsoft reporting technology.

Add HTTP Handler Web Server

The server has to know what it is dealing with when it is asked to generate a ReportViewer control. To help the server out, add the appropriate handlers.

Brite Global provides some excellent instructions on how to add the handlers.

Create Report on SSRS Server

The “Who Needs SQL Server’s Reporting Services?” article by DataSprings is an excellent tutorial for getting started with your first report.

Add Generic User to Report Server

For security reasons, a generic user will need to be added to the SSRS server. These credentials will be used by the .aspx page to access the report.

Give this user “Browser – May view folders, reports and subscribe to reports” only rights.

This generic (aka anonymous) user’s credentials will be stored in a separate config file and pulled into the web.config. That way if they change, you are not mucking about in the web.config file.

Create a appSetting.config and add the following information:

<appSettings>
    <add key="SSRS" value="http://YOUR-REPORTSERVER-URL" />
    <add key="rvUser" value="GENERIC-USERNAME" />
    <add key="rvPassword" value="GENERIC-PASSWORD" />
    <add key="rvDomain" value="YOUR-REPORTSERVER-DOMAIN" />
  </appSettings>

Pop it into the web.config as such:

<appSettings file="appSettings.config">
<!-- Could have other keys here -->
</appSettings>

The authorization is handled by using the IReportServerCredentials Interface which “allows applications to provide credentials for connecting to a Reporting Services report server.”

PDF Output

Add the ReportViewer control the an .aspx page by adding an assembly reference and the control itself:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="YOUR-FILE_NAME.vb" Inherits="YOUR-INHERITS" %>

<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>

<!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></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <rsweb:ReportViewer ID="ReportViewer1" runat="server">
        </rsweb:ReportViewer>

    </div>
    </form>
</body>
</html>

The code behind page got a lot of help from Viral at Beyond Relational’s post “Generating and exporting SSRS reports programatically using Report Viewer Control” and using Microsoft’s IReportServerCredentials Interface that was mentioned earlier:

VB.NET

Imports System.Net
Imports System.IO
Imports System.Security.Principal
Imports Microsoft.Reporting.WebForms

Partial Class YOUR_PAGE_CLASS
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        SetReportParameters()
    End Sub

    Private Sub SetReportParameters()
        'Set Processing Mode
        ReportViewer1.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote
        ' Set report server and report path
        ReportViewer1.ServerReport.ReportServerUrl = _
           New Uri(SSRS)

        ReportViewer1.ServerReport.ReportPath = _
           "/YOUR-REPORT-PATH"

        Dim paramList As New Generic.List(Of ReportParameter)
        Dim pInfo As ReportParameterInfoCollection
        pInfo = ReportViewer1.ServerReport.GetParameters()

        'if you have report parameters - add them here
        paramList.Add(New ReportParameter("PARAM1-EXAMPLE", "1", True))
        paramList.Add(New ReportParameter("PARAM2-EXAMPLE", "2", True))

        ReportViewer1.ServerReport.SetParameters(paramList)

        ' Process and render the report
        ReportViewer1.ServerReport.Refresh()

        'output as PDF
        Dim returnValue As Byte()
        Dim format As String = "PDF"
        Dim deviceinfo As String = ""
        Dim mimeType As String = ""
        Dim encoding As String = ""
        Dim extension As String = "pdf"
        Dim streams As String() = Nothing
        Dim warnings As Microsoft.Reporting.WebForms.Warning() = Nothing

        returnValue = ReportViewer1.ServerReport.Render(format, deviceinfo, mimeType, encoding, extension, streams, warnings)
        Response.Buffer = True
        Response.Clear()

        Response.ContentType = mimeType

        Response.AddHeader("content-disposition", "attachment; filename=YOUR-OUTPUT-FILE-NAME.pdf")

        Response.BinaryWrite(returnValue)
        Response.Flush()
        Response.End()
    End Sub

    Protected Sub Page_Init(ByVal sender As Object, _
                            ByVal e As System.EventArgs) _
                            Handles Me.Init

        ReportViewer1.ServerReport.ReportServerCredentials = _
            New MyReportServerCredentials()

    End Sub
End Class

<Serializable()> _
Public NotInheritable Class MyReportServerCredentials
    Implements IReportServerCredentials
    Public userName As String = ConfigurationManager.AppSettings("rvUser")
    Public password As String = ConfigurationManager.AppSettings("rvPassword")
    Public domain As String = ConfigurationManager.AppSettings("rvDomain")

    Public ReadOnly Property ImpersonationUser() As WindowsIdentity _
            Implements IReportServerCredentials.ImpersonationUser
        Get
            'Use the default windows user.  Credentials will be
            'provided by the NetworkCredentials property.
            Return Nothing
        End Get
    End Property

    Public ReadOnly Property NetworkCredentials() As ICredentials _
            Implements IReportServerCredentials.NetworkCredentials
        Get
            'Read the user information from the web.config file.
            'By reading the information on demand instead of storing
            'it, the credentials will not be stored in session,
            'reducing the vulnerable surface area to the web.config
            'file, which can be secured with an ACL.

            If (String.IsNullOrEmpty(userName)) Then
                Throw New Exception("Missing user name from web.config file")
            End If

            If (String.IsNullOrEmpty(password)) Then
                Throw New Exception("Missing password from web.config file")
            End If

            If (String.IsNullOrEmpty(domain)) Then
                Throw New Exception("Missing domain from web.config file")
            End If

            Return New NetworkCredential(userName, password, domain)

        End Get
    End Property

    Public Function GetFormsCredentials(ByRef authCookie As Cookie, _
                                        ByRef userName As String, _
                                        ByRef password As String, _
                                        ByRef authority As String) _
                                        As Boolean _
            Implements IReportServerCredentials.GetFormsCredentials

        authCookie = Nothing
        userName = Nothing
        password = Nothing
        authority = Nothing

        'Not using form credentials
        Return False

    End Function

End Class

C#

using System;
using System.Configuration;
using System.Net;
using System.Security.Principal;
using Microsoft.Reporting.WebForms;
partial class YOUR_PAGE_CLASS : System.Web.UI.Page
{
    public string SSRS = ConfigurationManager.AppSettings["SSRS"];
    protected void Page_Load(object sender, System.EventArgs e)
    {
        SetReportParameters();
    }
    private void SetReportParameters()
    {
        //Set Processing Mode
        //ReportViewer1.ProcessingMode = ProcessingMode.Remote
        ReportViewer1.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote;
        // Set report server and report path
        ReportViewer1.ServerReport.ReportServerUrl = new Uri(SSRS);

        ReportViewer1.ServerReport.ReportPath = "/YOUR-REPORT-PATH";

        System.Collections.Generic.List<ReportParameter> paramList = new System.Collections.Generic.List<ReportParameter>();
        ReportParameterInfoCollection pInfo = default(ReportParameterInfoCollection);
        pInfo = ReportViewer1.ServerReport.GetParameters();

        //if you have report parameters - add them here
        paramList.Add(new ReportParameter("PARAM1-EXAMPLE", "1", true));
        paramList.Add(new ReportParameter("PARAM1-EXAMPLE", "2", true));

        ReportViewer1.ServerReport.SetParameters(paramList);

        // Process and render the report
        ReportViewer1.ServerReport.Refresh();

        //output as PDF
        byte[] returnValue = null;
        string format = "PDF";
        string deviceinfo = "";
        string mimeType = "";
        string encoding = "";
        string extension = "pdf";
        string[] streams = null;
        Microsoft.Reporting.WebForms.Warning[] warnings = null;

        returnValue = ReportViewer1.ServerReport.Render(format, deviceinfo, out mimeType, out encoding, out extension, out streams, out warnings);
        Response.Buffer = true;
        Response.Clear();

        Response.ContentType = mimeType;

        Response.AddHeader("content-disposition", "attachment; filename=YOUR-OUTPUT-FILE-NAME.pdf");

        Response.BinaryWrite(returnValue);
        Response.Flush();
        Response.End();
    }

    protected void Page_Init(object sender, System.EventArgs e)
    {
        ReportViewer1.ServerReport.ReportServerCredentials = new MyReportServerCredentials();

    }
    public YOUR-PAGE-CLASS()
    {
        Init += Page_Init;
        Load += Page_Load;
    }
}
[Serializable()]
public sealed class MyReportServerCredentials : IReportServerCredentials
{
    public string userName = ConfigurationManager.AppSettings["rvUser"];
    public string password = ConfigurationManager.AppSettings["rvPassword"];

    public string domain = ConfigurationManager.AppSettings["rvDomain"];
    public WindowsIdentity ImpersonationUser
    {

        //Use the default windows user.  Credentials will be
        //provided by the NetworkCredentials property.

        get { return null; }
    }

    public ICredentials NetworkCredentials
    {

        get
        {
            //Read the user information from the web.config file.
            //By reading the information on demand instead of storing
            //it, the credentials will not be stored in session,
            //reducing the vulnerable surface area to the web.config
            //file, which can be secured with an ACL.

            if ((string.IsNullOrEmpty(userName)))
            {
                throw new Exception("Missing user name from web.config file");
            }

            if ((string.IsNullOrEmpty(password)))
            {
                throw new Exception("Missing password from web.config file");
            }

            if ((string.IsNullOrEmpty(domain)))
            {
                throw new Exception("Missing domain from web.config file");
            }

            return new NetworkCredential(userName, password, domain);

        }
    }

    public bool GetFormsCredentials(out Cookie authCookie,
               out string userName, out string password,
               out string authority)
    {
        authCookie = null;
        userName = null;
        password = null;
        authority = null;

        // Not using form credentials
        return false;
    }

}

Now just run your URL in a browser (http://YOUR-DOMAIN.com/YOUR-PAGE.aspx) and the File Download warning box will pop up for the PDF.

PDF Layout Tips and Things to Look Out For

  1. Set Report PageSize to 8.5in, 11in for portrait or 11in, 8.5in for landscape.
  2. Set the Report Margins as you would like.
  3. Make sure your Report Body (white staging area in Visual Studio) does not exceed your Report PageSize minus your margins.
  4. Remove any unused white space in Report Body no matter what you set the sizes at.

Generating Barcodes with Barcode Generator and ASP.NET

Generating barcodes in ASP.NET is pretty easy with Barcode Generator. Barcode Generator is free for non-commercial use but priced right for commercial use. If you are a commercial site, try the free version locally and, if it works for you, spring for the license. VB.NET is used below but Barcode Generator’s examples are in C#.

This post modifies the example provided by Barcode Generator only enough so you can put a barcode on a page with a plain img tag as such:

<img src="barcode.aspx?code=hqcfqs55kioevn55saz0me55" alt="barcode" />

barcode example from screenshot
I also got some help from this post by Chris Love: A Quick and Dirty Bar Code Image httpHandler

First, follow the instructions on Barcode Generator’s site to install the dll’s.

Then on barcode.aspx put the following:

Imports System.Web
Imports System.Drawing
Imports System.Drawing.Imaging
Imports BarcodeGenerator

Public Class barcode
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Documentation:
        'http://www.barcodeasp.com/1d/manual.php?ns=BarcodeGenerator&id=BCGBarcode1D
        Dim font As New BCGFont(New Font("Arial", 10, FontStyle.Regular))
        Dim barcode As String

        Dim color_black As New BCGColor(Color.Black)
        Dim color_white As New BCGColor(Color.White)

        If Not IsNothing(Request("code")) AndAlso Len(Request("code").ToString) Then
            barcode = Request("code").ToString
        Else
            barcode = Now.Month.ToString & Now.Day.ToString & Now.Year.ToString
        End If

        Dim code As BCGBarcode1D = New BCGcode39()
        code.setScale(1)
        ' Resolution
        code.setThickness(30)
        ' Thickness
        code.setForegroundColor(color_black)
        ' Color of bars
        code.setBackgroundColor(color_white)
        ' Color of spaces
        code.setFont(font)
        ' Font
        code.parse(barcode)

        Dim drawing As New BCGDrawing(color_white)
        drawing.setBarcode(code)
        drawing.draw()

        Response.ContentType = "image/jpeg"
        ' Save the image into jpeg format.
        drawing.finish(ImageFormat.Jpeg, Response.OutputStream)
    End Sub
End Class

And, that’s it. Set your image tag to the path of your barcode.aspx file with the code as a url param and you’re done.

Google Analytics Click Event Tracking on LinkButton in ASP.NET (VB)

Google Analytics integration with .NET web parts requires more planning and execution than with straight HTML. To apply dynamic event tracking to a LinkButton we can attach a function to the OnClientClick attribute of the LinkButton.

First, a review of how the event tracking method is set up directly from Google:

_gaq.push(['_trackEvent', 'category', 'action', 'optional_label', 'optional_value']);

category (required)

The name you supply for the group of objects you want to track.

action (required)

A string that is uniquely paired with each category, and commonly used to define the type of user interaction for the web object.

label (optional)

An optional string to provide additional dimensions to the event data.

value (optional)

An integer that you can use to provide numerical data about the user event.

To set it up on the LinkButton:

<asp:LinkButton ID="lb_mylinkbutton"
OnClientClick='<%# GetGoogleAnalyticsEventTracking("Downloads", "PDF", "/link/to/myPDF.pdf") %>'
runat="server">My Link Button</asp:LinkButton>

In the code above the values are hard coded, but you can use variables in their place for dynamic links:

<asp:LinkButton ID="lb_mylinkbutton"
OnClientClick='<%# GetGoogleAnalyticsEventTracking(Eval("link_category"), Eval("link_action"), Eval("link_label")) %>'
runat="server">My Link Button</asp:LinkButton>

And, the .NET function, VB flavor:

Protected Function GetGoogleAnalyticsEventTracking(ByVal link_category As String, ByVal link_action As String, ByVal link_label As String) As String

        Return String.Format("_gaq.push(['_trackEvent','{0}','{1}','{2}']);", link_category, link_action, link_label)

End Function

When the user clicks the LinkButton, the Google Analytics track event method will fire and, provided Google Analytics tracking is set up properly on the site, you will see the click events tracked within a day.

Required Field Validator for Checkbox in ASP.NET

Unlike other form fields, ASP.NET does not have a required field validator control for checkbox. You have to roll your own with a custom field validator. Quick and easy example straight from Microsoft:

Checkbox Control

<asp:Label Font-Bold="true"
  ID="lbl_CheckBoxPrint"
  Text="I have the ability to print from this computer or device:"
  AssociatedControlID="CheckBoxPrint" runat="server" />

<asp:CheckBox
  id="CheckBoxPrint"
  runat="server"></asp:CheckBox>

Custom Validator

<asp:CustomValidator
  id="cust_CheckBoxPrint"
  runat="server"
  ErrorMessage="Print Capability"
  OnServerValidate="ValidatePrint">* required</asp:CustomValidator>

Do not forget to put the validation function name in the OnServerValidate attribute.

Validation Code

Sub ValidatePrint(ByVal source As Object, ByVal args As ServerValidateEventArgs)
        args.IsValid = (CheckBoxPrint.Checked = True)
End Sub

Not that hard, but not quite as easy as just adding a required field validator control.

Complete Code

  <asp:Label Font-Bold="true"
    ID="lbl_CheckBoxPrint"
    Text="I have the ability to print from this computer or device:"
    AssociatedControlID="CheckBoxPrint"
    runat="server" />

<asp:CheckBox
  id="CheckBoxPrint"
  runat="server"></asp:CheckBox>

<asp:CustomValidator
   id="cust_CheckBoxPrint"
   runat="server"
   ErrorMessage="Print Capability"
   OnServerValidate="ValidatePrint">* required</asp:CustomValidator>

'This goes in a script block or on a code behind page
Sub ValidatePrint(ByVal source As Object, ByVal args As ServerValidateEventArgs)
        args.IsValid = (CheckBoxPrint.Checked = True)
End Sub

Pop-up Survey with ASP.NET and jQuery Dialog

Same pop-up survey as in the Pop-up Survey with jQuery UI Dialog post except with ASP.NET (VB) this time.
pop-up survey

Pop-up Behavior

  1. Pop-up survey opens when page loads. Pop-ups on window.unload or window close are being blocked by most browsers due to abuse and overuse.
  2. Cookie is set when survey submitted or user opts out (“No, thanks” click).
  3. Closing dialog will not set cookie

All survey data is stored in a database and jQuery .post is used to shuttle the information back and forth.

Code for the survey dialog:

<div id="survey" title="Pop-Up Survey">
	<p id="surveyDenied"><a href="#">No, thanks</a></p>
		<p>Pop-up survey that cookies browser on completion or on opt-out. Short 411 demo survey.</p>
		<form id="popup_survey" name="popup_survey" method="post">
        <p><strong>Pink or blue?</strong><br />
		<input id="pink" type="radio" name="radio_color" value="pink"  />Pink<br />
        <input id="blue" type="radio" name="radio_color" value="blue"  />Blue</p>
        <p><strong>Soccer or futbol?</strong><br />
		<input id="soccer" type="radio" name="radio_sport" value="soccer"  />Soccer<br />
        <input id="futbol" type="radio" name="radio_sport" value="futbol"  />Futbol</p>
        </form>
	<div id="error_message"></div>
</div>

It’s just a couple of radio buttons and a place for an error message. The submit is handled by the dialog button.

Here is the survey dialog code:

$(function(){
			$('#survey').dialog({
				bgiframe: true,
				autoOpen: false,
				modal: true,
				width: 500,
				resizable: false,
				buttons: {
					Submit: function(){
						if($("input[name='radio_color']:checked").val() !== undefined && $("input[name='radio_sport']:checked").val() !== undefined){
							setCookie('POPsurvey','POPsurvey',30);
							$.post("process_survey.aspx", $("#popup_survey").serialize(),
							function(data){
								if(data.db_check == 'fail'){
									$("#error_message").html("<p>Database not available. Please try again.</p>");
								} else {
									$("div.pink").css("width",data.perPink);
									$(".perPink").html(data.perPink + "% (" + data.totalPink + ")");

									$("div.blue").css("width",data.perBlue);
									$(".perBlue").html(data.perBlue + "% (" + data.totalBlue + ")");

									$("div.soccer").css("width",data.perSoccer);
									$(".perSoccer").html(data.perSoccer + "% (" + data.totalSoccer + ")");

									$("div.futbol").css("width",data.perFutbol);
									$(".perFutbol").html(data.perFutbol + "% (" + data.totalFutbol + ")");

									$(".totalRes").html(data.totalRes);

									$('#survey').dialog('close');
									$('#survey_thanks').dialog('open');
								}
								}, "json");
						}else{
							$("#error_message").html("<p>Please answer all questions.</p>");
						}
					}
				}
			});
		});

Lots of stuff but it does several things. First, on submit, it checks that the user answered both questions. Then it sets the cookie. And, finally, it sends the form data off via post and puts the response in elements on the page that are part of the “Thank you” dialog. Speaking of which…

The “Thank you” dialog code is thus:

<div id="survey_thanks" title="Pop-Up Survey - Thank You!">
    <p>Thank you for taking the time to answer our survey. Your input will help us improve the site.</p>
    <p>Responses: <span class="totalRes"></span></p>

    <div class="progress-container">
        pink <span class="perPink"></span>
        <div class="pink"></div>
        blue <span class="perBlue"></span>
        <div class="blue"></div>
    </div>

    <div class="progress-container">
        soccer <span class="perSoccer"></span>
        <div class="soccer"></div>
        futbol <span class="perFutbol"></span>
        <div class="futbol"></div>
    </div>
</div>
$(function(){
			$('#survey_thanks').dialog({
				bgiframe: true,
				autoOpen: false,
				modal: true,
				width: 500,
				resizable: false,
				buttons: {
					Close: function(){
						$(this).dialog('close');
						}
					}
			});
		});

Processing the Survey

The process_survey page adds the answers to the database and brings back the totals that are calculated by a view.

<%@ Page Language="VB" Debug="true" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Math" %>

<script runat="server">
    Dim serializer As JavaScriptSerializer

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        serializer = New JavaScriptSerializer()
        Response.Write(JSONData(Request("radio_color").ToString,Request("radio_sport").ToString))
    End Sub

    Public Class Survey
		Public dbcheck As String
        Public totalPink As Integer
		Public perPink As Integer
        Public totalBlue As Integer
		Public perBlue As Integer
        Public totalSoccer As Integer
		Public perSoccer As Integer
		Public totalFutbol As Integer
		Public perFutbol As Integer
		Public totalRes As Integer
    End Class

    Private Function JSONData(ByVal color As String, ByVal sport As String) As String
		Dim srvy As New Survey()

		If color.Length and sport.Length then

			Dim mySql As String
			Dim insertSql As String
			Dim insertCommand As SqlCommand
			Dim objConn As New SqlConnection("Server=YOUR_SERVER_HERE;Database=YOUR_DB_HERE;User ID=YOUR_ID_HERE;Password=YOUR_PW_HERE")
			insertSql = "INSERT INTO survey (color,sport) VALUES ('"
			insertSql += color & "', '"
			insertSql += sport & "')"
			objConn.Open()
			insertCommand = New SqlCommand(insertSql,objConn)

			insertCommand.ExecuteNonQuery()

			Dim myds As New DataSet("Survey")
			mySql = "SELECT * FROM v_totals"

			Dim adapter As New SqlClient.SqlDataAdapter(mySql, objConn)
			Dim dr As DataRow

			adapter.Fill(myds, "Survey")

			dr = myds.Tables(0).Rows(0)

				srvy.dbcheck = "OK"
				srvy.totalPink = dr("Pink")
				srvy.perPink = Round(dr("Pink")/(dr("Pink")+dr("Blue")),2)*100
				srvy.totalBlue = dr("Blue")
				srvy.perBlue = Round(dr("Blue")/(dr("Pink")+dr("Blue")),2)*100
				srvy.totalSoccer = dr("Soccer")
				srvy.perSoccer = Round(dr("Soccer")/(dr("Soccer")+dr("Futbol")),2)*100
				srvy.totalFutbol = dr("Futbol")
				srvy.perFutbol = Round(dr("Futbol")/(dr("Soccer")+dr("Futbol")),2)*100
				srvy.totalRes = dr("Total")

			objConn.Close()

		Else
			 srvy.dbcheck = "fail"
        End If

		Return serializer.Serialize(srvy)
    End Function
</script>    

The totals for the return data are stored in a view to prevent separate and multiple calls to the database. The table and the view can be created in SQL Server as such:

CREATE TABLE [dbo].[survey](
	[id] [smallint] IDENTITY(1,1) NOT NULL,
	[color] [varchar](4) NOT NULL,
	[sport] [varchar](6) NOT NULL,
 CONSTRAINT [PK_survey] PRIMARY KEY CLUSTERED
(
	[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE VIEW [dbo].[v_totals]
AS
SELECT     TOP (1)
                          (SELECT     COUNT(color) AS Expr1
                            FROM          dbo.survey
                            WHERE      (color = 'pink')) AS Pink,
                          (SELECT     COUNT(color) AS Expr2
                            FROM          dbo.survey AS survey_5
                            WHERE      (color = 'blue')) AS Blue,
                          (SELECT     COUNT(sport) AS Expr3
                            FROM          dbo.survey AS survey_4
                            WHERE      (sport = 'futbol')) AS Futbol,
                          (SELECT     COUNT(sport) AS Expr3
                            FROM          dbo.survey AS survey_3
                            WHERE      (sport = 'soccer')) AS Soccer,
                          (SELECT     COUNT(id) AS Expr4
                            FROM          dbo.survey AS survey_2) AS Total
FROM         dbo.survey AS survey_1

Cookies

The code to handle setting, checking, and deleting cookies is standard javascript:

function setCookie(c_name,value,expiredays)
{
	var exdate=new Date();
	exdate.setDate(exdate.getDate()+expiredays);
	document.cookie=c_name+ "=" +escape(value)+((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
} 

function getCookie(c_name)
{
	if (document.cookie.length>0)
	  {
	  c_start=document.cookie.indexOf(c_name + "=");
	  if (c_start!=-1)
		{
		c_start=c_start + c_name.length+1;
		c_end=document.cookie.indexOf(";",c_start);
		if (c_end==-1) c_end=document.cookie.length;
		return unescape(document.cookie.substring(c_start,c_end));
		}
	  }
	return "";
}

function checkCookie(c_name)
{
	cookie_value=getCookie(c_name);
	if (cookie_value=="") {
		$('#survey').dialog('open');
	}
}

function deleteCookie(c_name) {
	document.cookie = c_name +'=; expires=Thu, 01-Jan-70 00:00:01 GMT;';
}

The style for the “Thank you” graph:

div.progress-container {
  border: 1px solid #ccc;
  width: 150px;
  padding: 1px;
  margin-bottom: 5px;
  background: white;
}

div.progress-container > div {
  height: 12px;
  margin-bottom: 2px;
}
div.progress-container > div.pink {
  background-color:#CC6699;
}
div.progress-container > div.blue {
  background-color: #3366CC;
}
div.progress-container > div.soccer {
  background-color: #006633;
}
div.progress-container > div.futbol {
  background-color: #663333;
}

You’ll notice in the .post function that the width of the bar graph is set with the percent of responses for each answer that comes back from the database.

Note: The download zip does not include a web.config. You will need to create your own.

Download zip of all files