Tag Archives: ASP.NET

How I help IntelliSense to provide more useful information #coding #JavaScript

OK, maybe it’s a hack rather than help, but there’s a lot that IntelliSense can figure out and some “basic” stuff it can’t. JavaScript is dynamic, often the type isn’t provided until runtime and this hinders IntelliSense, this is what I try to help it with. I’m using Microsoft Visual Studio Ultimate 2013 Update 2 with the corresponding Web Essentials.

Here’s starting simple, this works well:

var Person = function (who, bikes)
{
    this.Who = who;
    this.Bikes = bikes;
};

var p = new Person("Tim", ["bluebell", "rudy", "nexus"]);
console.log(p.Who.toUpperCase() + " has " + p.Bikes.join("; "));

“TIM has bluebell; rudy; nexus” is output to the JavaScript console in Microsoft Internet Explorer 11. IntelliSense can figure out what Who and Bikes is, so toUpperCase and join came from the auto-completion list it provides.

Wow, you think, IntelliSense is clever, it is, but take away the type information, for example I create a Log function and execute it somewhere else, let’s say in another script, this still outputs the same:

// Script 1
var Person = function (who, bikes)
{
    this.Who = who;
    this.Bikes = bikes;
};

Person.prototype.Log = function ()
{
    console.log(this.Who.toUpperCase() + " has " + this.Bikes.join("; "));
};

// Script 2
var p = new Person("Tim", ["bluebell", "rudy", "nexus"]);
p.Log();

But IntelliSense within the Log function does not know Who is a string and has the toUpperCase function and that Bikes is an array and has the join function.
Since the types are going to be fixed, I’ll never want anyone to do something like new Person(1, 2), I can comment the Person constructor function, but that doesn’t help when writing the Log (or other) functions.

IntelliSense has an API, so you can log messages to the Output (JavaScript Language Service) panel in Visual Studio like so:

intellisense.logMessage("Hello :)"); 

But you only want to do that if it intellisense is defined, so…

if (typeof intellisense !== "undefined")
{
    intellisense.logMessage("Hello :)");
}

That code will even work in production now, the if statement block contents will not be executed unless you (or the JavaScript runtime) defines a global called intellisense, but in Visual Studio it will be run.

So we can help IntelliSense by faking some values in the Person constructor function, so it can figure out what the types are:

// Script 1
var Person = function (who, bikes)
{
    this.Who = who;
    this.Bikes = bikes;

    // Help IntelliSense
    if (typeof intellisense !== "undefined")
    {
        this.Who = "";
        this.Bikes = [];
    }
};

Person.prototype.Log = function ()
{
    console.log(this.Who.toUpperCase() + " has " + this.Bikes.join("; "));
};

// Script 2
var p = new Person("Tim", ["bluebell", "rudy", "nexus"]);
p.Log();

Now the Log function has auto-completion for Who and Bikes, yay! You can also stick a logMessage call in there too, so you can see when it’s helping you.

This is an especially useful trick when you have dependency injection and complex object parameters (more on this another time I hope) and can be used anywhere (not just in constructor functions).

If you are struggling with IntelliSense (I always am), then I hope this helps in some way, please post a comment with your experiences.

How I share JavaScript files between web projects #coding #JavaScript

It’s the first wall to climb when you have multiple web projects with common code, how to share scripts between web projects without duplication, copy paste etc. Sure, I have nugget packages for libs, but do I need to have the same scripts in every web project (and branches thereof too)? My last count was 15 copies of everything (15 TFS workspaces), if I make a change to only one of my scripts, that is 14 that are potentially out of date and it’s easy to miss one!

TFS workspaces are certainly not as helpful as they could be, so I resorted to windows symbolic links / symlinks (CreateSymbolicLink function in kernel32.dll) as a means of sharing files and folders and then cloaking the folders in my TFS workspace. I can live with manually including additions and deletions as a result of the cloaking, the upside is that I can link extra scripts into one web project and share the rest with the other projects. It is perfect for an administration project that has extra scripts from the normal projects and we don’t want to have those admin scripts included in the normal projects.

So, I have a good solution that reduces the duplication, but it didn’t play well with IntelliSense (go to definition). I’m using Microsoft Visual Studio Ultimate 2013 Update 2 with the corresponding Web Essentials and IntelliSense doesn’t like these links, specifically, configuring the _references.js file in “Tools -> Options -> Text Editor -> JavaScript -> IntelliSense -> References” doesn’t seem to work for me, maybe I’ve just not got it correct yet, anyway, I gave up in favour of a different approach. It also falls flat when someone doesn’t have it configured correctly, it requires everyone to have it configured, and it’s fixed regardless of project.

Fortunately (and deliberately) the relative path to each Scripts folder is the same level of depth. So rather than use the above way to configure it, I opted for placing a reference to it in each script I wanted it, like so:

/// <reference path=”~/../../Shared/Scripts/_references.js” />

And in the _references.js the references are like so (of course there are a LOT more than just this one):

/// <reference path=”~/Scripts/angular.js” />

where the symlinks are like so:

XYZ/Solution1/Project1/Scripts/_references.js -> XYZ/Shared/Scripts/_references.js

XYZ/SolutionN/ProjectN/Scripts/_references.js -> XYZ/Shared/Scripts/_references.js

and

XYZ/Solution1/Project1/Scripts/angular.js -> XYZ/Shared/Scripts/angular.js

XYZ/SolutionN/ProjectN/Scripts/angular.js -> XYZ/Shared/Scripts/angular.js

This means I only have one copy of the scripts on my hard disk, the _references.js are shared between each project etc and I’m not constantly fighting to keep them all up to date.

Additional references can be defined in other files and referenced where required, for example the administration ones, but I tend to only keep core script references in the _references because if you get a circular reference then IntelliSense stops working!

If you are struggling with sharing scripts, then I hope this helps in some way, please post a comment with your experiences

AjaxControlToolkit version 7.0123 with .NET 4.5

Here’s my steps and workarounds from the very beginning (in Visual Studio 2012), hopefully some part of this will help fix whatever error you are encountering.

File -> New Project
.NET Framework 4.5
Visual C# -> Web
ASP.NET Web Forms Application
Add AjaxControlToolkit version 7.0123 (dll is actually 4.5.7.123 which is January 2013 I believe) via NuGet

Open Default.aspx
Add a calendar to the BodyContent / MainContent:

<asp:TextBox ID="myTextBox" runat="server" />
<ajaxToolkit:CalendarExtender ID="myCalendar" runat="server" TargetControlID="myTextBox" Format="dd/MM/yyyy" />

Run it up (F5 will do)

It might error about ASP.NET Ajax 4.0 scripts:
0x800a139e – JavaScript runtime error: AjaxControlToolkit requires ASP.NET Ajax 4.0 scripts. Ensure the correct version of the scripts are referenced. If you are using an ASP.NET ScriptManager, switch to the ToolkitScriptManager in AjaxControlToolkit.dll.

I’ve also seen it error about:
‘MsAjaxBundle’ is not a valid script name. The name must end in ‘.js’.

No bother, let’s remove that reference from the Site.Master, so:

    <asp:ScriptManager runat="server">
        <Scripts>
            <%--Framework Scripts--%>
            <asp:ScriptReference Name="MsAjaxBundle" />
            <asp:ScriptReference Name="jquery" />
            <asp:ScriptReference Name="jquery.ui.combined" />
            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
            <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
            <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
            <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
            <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
            <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
            <asp:ScriptReference Name="WebFormsBundle" />
            <%--Site Scripts--%>

        </Scripts>
    </asp:ScriptManager>

Now becomes:

    <asp:ScriptManager runat="server">
        <Scripts>
            <asp:ScriptReference Name="jquery" />
            <asp:ScriptReference Name="jquery.ui.combined" />
            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
            <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
            <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
            <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
            <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
            <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
            <asp:ScriptReference Name="WebFormsBundle" />
        </Scripts>
    </asp:ScriptManager>

Next is ToolkitScriptManager, the snippet above now becomes:

    <ajaxToolkit:ToolkitScriptManager runat="server">
        <Scripts>
            <asp:ScriptReference Name="jquery" />
            <asp:ScriptReference Name="jquery.ui.combined" />
            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
            <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
            <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
            <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
            <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
            <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
            <asp:ScriptReference Name="WebFormsBundle" />
        </Scripts>
    </ajaxToolkit:ToolkitScriptManager>

But of course this fails with:
Could not load file or assembly ‘System.Web’ or one of its dependencies. The system cannot find the file specified.

Remove the Assembly=”System.Web” part from the ScriptReference so we have have:

    <ajaxToolkit:ToolkitScriptManager runat="server">
        <Scripts>
            <asp:ScriptReference Name="jquery" />
            <asp:ScriptReference Name="jquery.ui.combined" />
            <asp:ScriptReference Name="WebForms.js" Path="~/Scripts/WebForms/WebForms.js" />
            <asp:ScriptReference Name="WebUIValidation.js" Path="~/Scripts/WebForms/WebUIValidation.js" />
            <asp:ScriptReference Name="MenuStandards.js" Path="~/Scripts/WebForms/MenuStandards.js" />
            <asp:ScriptReference Name="GridView.js" Path="~/Scripts/WebForms/GridView.js" />
            <asp:ScriptReference Name="DetailsView.js" Path="~/Scripts/WebForms/DetailsView.js" />
            <asp:ScriptReference Name="TreeView.js" Path="~/Scripts/WebForms/TreeView.js" />
            <asp:ScriptReference Name="WebParts.js" Path="~/Scripts/WebForms/WebParts.js" />
            <asp:ScriptReference Name="Focus.js" Path="~/Scripts/WebForms/Focus.js" />
            <asp:ScriptReference Name="WebFormsBundle" />
        </Scripts>
    </ajaxToolkit:ToolkitScriptManager>

It seems the new web forms project template adds ‘Microsoft.AspNet.ScriptManager.MSAjax 4.5.6’ package, this appears to conflict with the toolkit, so remove this via “Manage NuGet Packages”
Visual Studio might still leave the dll in your bin directory even after a clean, make sure you manually clean that out.

So there we are, works for me, best of luck.

EDIT:

Silly me, I forgot, remove the Name too (e.g. Name=”WebForms.js” ) for each that have a Path. If you don’t you will get errors like so:
The assembly ‘AjaxControlToolkit, Version=4.5.7.123, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e’ does not contain a Web resource that has the name ‘WebForms.js’. Make sure that the resource name is spelled correctly.

ASP.NET Web Forms Response.Write in an UpdatePanel #dev #web

I recently had a problem at work where I wanted to use some code that writes to the Response.Output TextWriter, this works fine until you stick an UpdatePanel around the line that writes to it. Various searches on the internet didn’t reveal any clues as to how to do this, all that I found suggested alternatives and used words like “doesn’t work” and use “PostBackTrigger” (which, by the way, negates the whole point of an UpdatePanel).

For fear of being labelled a hack-it together guy, I came up with two solutions, one is rock solid, the other is less so, but works wonderfully until they change how UpdatePanels work (which is unlikely given the fact that Web Forms is a dying technology, if you disagree then we will never be friends).

The basis of the solution

A control (anything inheriting from WebControl) is given a TextWriter on RenderBeginTag, RenderEndTag, … etc. Ah (ching, the penny drops), maybe this is different from Response.Output when we are processing an Async Postback? Indeed it is!

An example where Response.Output.Write doesn’t work

This is the standard Web Forms template application with the content removed.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <% Response.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Click the button and the Response.Output.Write destroys the response:

Unhandled exception at line 1, column 126350 in http://localhost:49213/bundles/MsAjaxJs?v=J4joXQqg80Lks57qbGfUAfRLic3bXKGafmR6wE4CFtc1

0x800a139e – JavaScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Details: Error parsing near ‘1|#||4|Hello245|updatePanel’.

Here’s a server control that captures the TextWriter and sticks it into the Response.Output (this is the less so option):

using System.Web.UI;
using System.Web.UI.WebControls;

namespace ResponseWriteUpdatePanel
{
    public class MyResponseHelper : WebControl
    {
        public override void RenderBeginTag(HtmlTextWriter output)
        {
            this.Page.Response.Output = output;
        }

        public override void RenderEndTag(HtmlTextWriter output)
        {
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
        }
    }
}

Then add to the page, like so:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<%@ Register TagPrefix="tim" Namespace="ResponseWriteUpdatePanel" Assembly="ResponseWriteUpdatePanel" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <tim:MyResponseHelper ID="MyOutput" runat="server"></tim:MyResponseHelper>
            <% Response.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Voila, it works.

Next, the more rock solid solution which avoids tinkering with the Response.Output:

using System.Web.UI;
using System.Web.UI.WebControls;

namespace ResponseWriteUpdatePanel
{
    public class MyResponseHelper : WebControl
    {
        public HtmlTextWriter Output { get; set; }

        public override void RenderBeginTag(HtmlTextWriter output)
        {
            Output = output;
        }

        public override void RenderEndTag(HtmlTextWriter output)
        {
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
        }
    }
}

And the page directly uses the TextWriter from the control instead of the Response.Output, like so:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<%@ Register TagPrefix="tim" Namespace="ResponseWriteUpdatePanel" Assembly="ResponseWriteUpdatePanel" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <tim:MyResponseHelper ID="MyOutput" runat="server"></tim:MyResponseHelper>
            <% MyOutput.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Of course, should you have two UpdatePanels on the same page then you would use a MyResponseHelper within each and use that instance.

Hook an ASP.NET MVC 2 Web Application into an existing SQL Server 2008 R2 instance

I was revisiting project templates in VisualStudio 2010 and when I was playing around I created an ASP.NET MVC 2 Web Application. I then wanted to hook into my existing SQL Server 2008 R2 instance rather than the SQLEXPRESS instance (the default the project template is setup to use) because I was getting this error:
“Unable to connect to SQL Server database.”
“A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)”

This was because the SQLEXPRESS instance was disabled, of course I enabled it and then it created the ASPNETDB.MDF in the App_Data folder and registered a new user just fine. But I didn’t want this, I wanted a “real” DB to play about with so I disabled the SQLEXPRESS instance again and deleted the ASPNETDB.MDF file.
I changed the default connection string from:
“data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true”
to:
“Data Source=localhost;Integrated Security=True;Initial Catalog=aspnetdb;”
Great, but I then needed to create the aspnetdb DB, but that was easy, I used aspnet_regsql.exe (ASP.NET SQL Server Setup Wizard). You can configure the name you want for your database (aspnetdb in my case) in the wizard or the application takes command line arguments too.
I then had a “real” DB I could play about with in Management Studio without attaching the ASPNETDB.MDF or any other fiddling about.

LINQ Basic DataSource binding

This is a quick example of LINQ and binding to a DataGridView control (via DataSource) the property name is used as the column header (Column[idx].HeaderText) this can be change via the following attribute:
System.ComponentModel.DisplayName(“Column header name here”)

The following example uses a LINQ query on a string collection to demonstrate this:

C#

var objCollection = from objs in fileStringCollection
                    select new WrapperForStrings
                    {StringProperty = objs};
this.DataGridView2.DataSource = objCollection.ToList();
this.DataGridView2.AutoResizeColumns();
...
public class WrapperForStrings
{
    private String stringValue;

    [System.ComponentModel.DisplayName("Column header name here C#")]
    public String StringProperty
    {
        get
        {
            return stringValue;
        }
        set
        {
            stringValue = value;
        }
    }
}

VB.NET

Dim objCollection = From objs In fileStringCollection _
                    Select New WrapperForStrings _
                    With {.StringProperty = objs}
Me.DataGridView2.DataSource = objCollection.ToList()
Me.DataGridView2.AutoResizeColumns()
...
Public Class WrapperForStrings
    Private stringValue As String

    <System.ComponentModel.DisplayName("Column header name here VB")> _
    Public Property StringProperty() As String
        Get
            Return stringValue
        End Get
        Set(ByVal value As String)
            stringValue = value
        End Set
    End Property
End Class