navigation
 Friday, July 06, 2007
It’s a big week for the staff at Falafel who has been cooking up a course certain to whet the appetite for project teams everywhere. With the release of ActiveFocus, the Falafel team has once again demonstrated their ability to deliver as promised.
posted on July 6, 2007  #    by Lino Tadros  Comments [0] Trackback
 Thursday, July 05, 2007
SAN JOSE, Calif. July 5, 2007 -- Falafel Software, an industry leader in consulting, training, and software development is pleased to announce the hiring of Steve Trefethen as Software Architect. Trefethen, former R&D Staff Engineer at CodeGear, Borland’s Developer Tools Group, has over 15 years of experience working along side some of the world’s leading software developers.
posted on July 5, 2007  #    by Lino Tadros  Comments [0] Trackback
 Sunday, July 01, 2007
Falafel Software is pleased to announce the arrival of the ActiveFocus public download. This download, available on the Falafel Software community server, enables anyone to utilize a fully functional version of ActiveFocus with no expirations, demos, or crippling. From installation to completing your first project, the ActiveFocus public download gives you a direct experience of the compete ActiveFocus.
posted on July 1, 2007  #    by Lino Tadros  Comments [0] Trackback

Last week I needed to add some personalization features to our ActiveFocus application, and it seemed like the built in logic around the Profile class in ASP.Net 2.0 Personalization would do the trick. It's actually pretty neat. First, you "declare" your profile data in web.config, something like this:

<profile enabled="true">
  <providers>
    <clear/>
    <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ActiveFocus"       applicationName="/ActiveFocus"/>
  </providers>
  <properties>
    <group name="Grids">
      <add name="MainGridRows" type="System.Int16" />
      <add name="DetailGridRows" type="System.Int16" />
    </group>
    <add name="LastProject" type="System.Int32" />
  </properties>
</profile>

The Properties portion defines the profile data structure. You can use simple data types like System.Int16, nested types (like the Grids property), and your own data types. You can also declare how these types are to be serialized.

When you add a declaration like this to your project, Visual Studio 2005 generates a class for you that implements this data structure (more on how this actually needs a little help for it to work later!). The class basically wraps the HttpContext.Current.Profile object, which is of type ProfileBase. It adds accessors for the members you declared in the web.config file, and sub objects for nested types.

In runtime, the ProfileBase reads and writes it values to a column in the table aspnet_Profile. Here is what it looks like when an instance of the profile class above is written to that table:

UserId                               PropertyNames                                                          PropertyValuesString

7B07AE10-61A7-4DEE-AFF1-172BB42A5E95 Grids.DetailGridRows:S:0:1:Grids.MainGridRows:S:1:2:LastProject:S:3:1: 8202

The profile is tied to user using the UserID column, and the PropertyNames column determines what offset and length in PropertyValuesString each data item occupies. For instance, MainGridRows starts at offset 1 and is 2 characters (so the value is 20). You can use attributes in web.config to control how the properties are serialized.

In code, to access the profile, you just need to declare a property in your form that casts the Profile object of the current Page (or HttpContext.Current.Profile) to a WebProfile (this is the type name of the auto generated ProfileBase wrapper) :

protected WebProfile Profile
{
  get
  {
    return (WebProfile) this.Profile;
  }
}

Now you can read and write the Profile using this property:

tbRowsPerMainGrid.Text = Profile.Grids.MainGridRows.ToString();
tbRowsPerDetailGrid.Text = Profile.Grids.DetailGridRows.ToString();

Here is how you can save it back:

Profile.Grids.MainGridRows = Int16.Parse( tbRowsPerMainGrid.Text );
Profile.Grids.DetailGridRows = Int16.Parse( tbRowsPerDetailGrid.Text );
Profile.Save();

Pretty cool, huh?

Profile data can be stored for authenticated users, but it can also be stored for anonymous users and "upgraded" to an authenticated user if the anonymous user becomes an authenticated user.

So what is the catch with all this magic?

Well, it turns out that this handy dandy auto generating of wrapper classes is only done for Web Site Projects, not Web Application Projects (WAPs)! This is true even of the latest Visual Studio 2005 SP1. I tried doing this in the ActiveFocus WAP, and the compile failed miserably, there was no WebProfile class to be found. I figured this would be easy to Google, and indeed it was, and it turns out that there is a Visual Studio add in on gotdotnet that adds this capability to WAPs, but to my dismay I saw that the gotdotnet site is "being phased out", and the download is gone!

So I turned to my old colleague and friend Charlie Calvert at Microsoft, and he did some digging. He found this post at andornot.com, which references the original post by Scott Guthrie on scottgu.com, and helpfully provides the vanished download!

I downloaded the software and installed it, and now when I right clicked on the web.config node in the Solution Explorer, there was a menu option saying Generate WebProfile:

And what's more, it actually worked! ActiveFocus is now equipped with a user profile capability! Thanks for the help, all of you guys with helpful blogs above! Hopefully this blog will help you too.

posted on July 1, 2007  #    by John Waters  Comments [0] Trackback
 Wednesday, June 27, 2007

I stumbled upon this great series of articles that go into much more detail about functional programming in C#, the culmination of which is to write implementations of the "big three" higher-order functions: Map, Filter, and Reduce.

http://diditwith.net/PermaLink,guid,a1a76478-03d2-428f-9db6-9cf4e300ea0f.aspx

posted on June 27, 2007  #    by Adam Anderson  Comments [0] Trackback
 Friday, June 22, 2007

I have an ASP.Net 2.0 form that uses Teleriks RadServiceManager to call a web service in the same application. All was working fine, but when I deployed it to another machine, the web service calls failed. I checked the Event Log and found something like this:

 

Request format is unrecognized for URL unexpectedly ending in '/ArtifactSearch/'. 

 

Googling turned up this helpful article. Apparently, web service calls using HTTP GET and POST are disabled by default on 1.1 installations, and I guess that can linger in machine.config or somewhere, and even though my app was a 2.0 app, it inherited these settings. You can enable the calls by adding this to the <system.web> section of your apps web.config: 

 

<webServices>

  <protocols>

    <add name="HttpGet"/>

    <add name="HttpPost"/>

  </protocols>

</webServices>

 

That did the trick for me!

posted on June 22, 2007  #    by John Waters  Comments [0] Trackback
 Thursday, June 21, 2007

You can write your own cmdlet ("command-let") to extend PowerShell in the .NET language of your choice.  You need to write both the cmdlet and a PowerShell snap-in to help install and register the command.  Here's an example snap-in for a "get-food" command  that lists tasty Mediterranean foods (like Falafels):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.ObjectModel; // supports Collection
using System.Management.Automation; // supports PSSnapIn
using System.Management.Automation.Runspaces; // supports *ConfigurationEntry
using System.ComponentModel; // supports RunInstaller
using Falafel;

// Project also references System.Configuration.Install

public class FalafelSnapIn : CustomPSSnapIn
{
public FalafelSnapIn()
: base()
{
}

public override string Name
{
get
{
return "FalafelSnapIn";
}
}

public override string Vendor
{
get
{
return "Falafel Software ";
}
}

public override string Description
{
get
{
return "Runs custom Falafel commands.";
}
}

/// <summary>
/// Specify the cmdlets that belong to this custom PowerShell snap-in.
/// </summary>
private Collection<CmdletConfigurationEntry> _cmdlets;
public override Collection<CmdletConfigurationEntry> Cmdlets
{
get
{
if (_cmdlets == null)
{
_cmdlets = new Collection<CmdletConfigurationEntry>();
_cmdlets.Add(
new CmdletConfigurationEntry("get-food", typeof(FalafelCmdlet), null));
}

return _cmdlets;
}
}
}

CustomPSSnapIn knows how to be installed via installutil.exe, contains information about name, vendor, description etc., and has collections of types that can be registered with PowerShell such as cmdlets, Types, Formats and Providers.  FalafelSnapIn descends from CustomPSSnapIn, overrides the Cmdlets collection and adds the "get-food" cmdlet to the collection. Notice that much of the PowerShell specific functionality is supported in the System.Management.Automation namespace.

 Next we'll look at FalafelCmdlet, the implementing class for the "get-food" cmdlet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Management.Automation; // supports PSSnapIn, CmdLet, Parameter

namespace Falafel
{
[Cmdlet(VerbsCommon.Get, "Food")]
public class FalafelCmdlet : Cmdlet
{
private string _contains;

[Parameter(Mandatory = false, Position = 0, HelpMessage =
"List item descriptions containing this string")]
public string Contains
{
get { return _contains; }
set { _contains = value; }
}

protected override void ProcessRecord()
{
MediterraneanFoods foods = new MediterraneanFoods();
foreach (MediterraneanFood food in foods.FindFoods(_contains))
{
WriteObject(food);
}
}
}
}

First the Cmdlet attribute marks this class as a cmdlet and helps formalize the naming convention for cmdlets as being verb-noun combinations.  VerbsCommon lists the verbs that may be used:

FalafelCmdlet descends from Cmdlet but you can also use PSCmdlet.  Cmdlet is lighter-weight but PSCmdlet has more access to the PowerShell runtime. For this example the functionality would be the same so I will go with the lighter-weight Cmdlet.  The Contains property in this example holds a string used in searching food descriptions.  The Parameter attribute marks the Contains property as a parameter for the cmdlet, provides a help string and identifies Contains as not being mandatory.

Finally the ProcessRecord() method of Cmdlet is overridden to perform the actually work of the command.  In ProcessRecord() a class called MediterraneanFoods returns a generic list of MediterraneanFood objects based on description.  We won't get into the workings of MediterraneanFoods here because its purpose is to simply provide sample functionality for the command.  Note: Watch this space for a tasty blog by Lino on Anonymous Delegates that gets into how the generic list is searched.

The really cool part of ProcessRecord() is the WriteObject() method of Cmdlet.  Instead of Console.Writeline() text-only output, WriteObject() actually ouputs MediteraneanFood objects into the PowerShell pipeline.  This means that your objects are automatically usable by other commands.  You'll see this in a minute when we register and run the command. 

Here are the PowerShell commands I use to install and register the cmdlet:

cd C:\Clients\Falafel\Projects\FalafelCmdletLibrary\bin\Debug
set-alias iu $Env:windir\Microsoft.NET\Framework\v2.0.50727\installutil.exe
iu FalafelCmdletLibrary.dll
Add-PSSnapin FalafelSnapIn

The first line changes the directory to where the assembly for the FalafelCmdlet is stored.  Then, as a convenience you can use set-alias to make access to InstallUtil.exe easier.  The "IU" alias for InstallUtil installs the assembly.  This step produces a certain amount of logging I won't include here.  Finally the Add-PSSnapin makes the snap-in available to the current PowerShell console session.  You can call Get-PSSnapin to see the description and verify it's there:

Now we can run the "get-food" command, passing the "contains" parameter.  Notice the output by default is in table format.

Remember the call to WriteObject() that makes all our output actual objects instead of text?  Here's an example of piping the output of the one command that will easily work with an existing command without any adapting or parsing necessary to make it all work.  The "|" character is used to pipe the output from get-food to a format-list:

...and we have the output in list, not table, format.  Or we could pipe the output to the get-member command that performs reflection on objects passed to it.  You can see the MediterraneanFood object has Description and Name properties:

This all opens up possibilities for you to wrap existing .NET functionality in command-line form and to use the output in other existing commands.

posted on June 21, 2007  #    by Noel Rice  Comments [0] Trackback

Read all about it here. Something that looks very interesting is support for sometimes connected applications...

posted on June 21, 2007  #    by John Waters  Comments [0] Trackback
 Wednesday, June 20, 2007

Today I worked on an AJAX application that uses JSON over xmlhttp to provide a quick search feature in our product ActiveFocus. Here you can see it in action: as you type in the searchbox, each time a key is pressed, the search string is sent to the server, a freetext search is done against the database, the results are returned in a JSON array, and then rendered as a HTML table:

Originally, this was hand coded in JavaScript at a very low level, using an ASP.Net 2.0 page on the server side to create and return the JSON object. The task at hand was to convert this to a more high level approach using Teleriks RadServiceManager to call a ASP.Net 2.0 Web Service, which returns a standard .NET type that is automatically converted to a JSON object.

In my Search Web Service, I return an array of SearchResultRows:

public struct SearchResultRow
{
  public int ID;
  public string ArtifactType;
  // ...
}

[WebMethod(EnableSession = true)]
public SearchResultRow[] ArtifactSearch( string searchKey)
{
  //…

This was amazingly straight forward. On the client side, when the callback returns, you can access the array through JSON indexing, something like this:

function CallSearch( searchKey )
{
  Search.ArtifactSearch(
    searchKey,
    SearchServiceCompleteCallback, SearchErrorCallback);
}


function SearchServiceCompleteCallback(ResponseAsJSON, ResponseAsXml, ResponseAsText)
{
  var Results = ResponseAsJSON;
  for( i=0; i < Results.length; i++)
  {
    // …
 

After debugging it in FireFox/FireBug (highly recommended! See article by my colleague Noel), I switched back to Internet Explorer 7.0 to test it there, confident that all was well. At first, the search behaved just like it should. But when I typed a search phrase that narrowed the search down to just one record in the returned array, I suddenly found that the table of results did not get displayed at all. It would display two or more results, but not one!

Intrigued, I switched back to FireBug to debug the mystery. But in FireFox, a one row array worked just fine. I could inspect the value of Results and see the JSON encoding, and verify that it was correct. So, I switched back to IE, this time using the VS 2005 IDE Script Debugger, which is pretty primitive compared to FireBug, but I had no choice.

Now, when I went to inspect Results, I found something very strange. When two or more records were returned, the JSON looked just like the FireFox version:

But when the call only returned one row, the JSON object had a different layout! Instead of a JSON  array of SearhResultRow records, there was an inner object named the same thing as the type of the array elements (SearchResultRow), which contained the field values for that one record!

Go figure!

At this point I had spent way too much time debugging and needed to get the job done, so I just added a check to see if the singleton format was present and handled the two different cases in seprate branches of the if statement, which did the trick.

However, I am curious as to whether this is a bug or not. Clearly, it is the same code running both server side and client side, yet in the two main browser versions, the JSON objects differ for one record arrays.

Let me know if you have any input! If not, maybe at least this blog will save you some debugging time…

posted on June 20, 2007  #    by John Waters  Comments [0] Trackback
 Friday, June 15, 2007

I just spent some quality time with Firefox and Firebug trying to figure out why my client-side validators weren't preventing a postback when invalid data was entered. The symptoms were puzzling: when I entered invalid data and then attempted to submit the form, the validators would appear briefly, but then the page would post anyway!

A little debugging revealed that the button I was clicking called the JavaScript function WebForm_DoPostBackWithOptions, which called Page_ClientValidate, which called ValidationSummaryOnSubmit. This function looped through a list of validation summaries named Page_ValidationSummaries and then performed operations on each list element, which naturally meant accessing its properties.

ValidationSummaryOnSubmit doesn't test each summary in the list to ensure that the summary is not null before attempting to access its properties, so if a null reference finds its way into this list, an error occurs, which causes the entire call chain to terminate abnormally, in this case resulting in a failure to prevent the form from posting.

A little more debugging followed, and I located where the Page_ValidationSummaries list is initialized, and found which reference was returning a null value. It was a validation summary in the footer of a DataGrid, and the DataGrid's ShowFooter property was false. This of course meant that all of the controls within the footer were never rendered to the client, but the code that generated the list of summaries was including the reference anyway.

The solution to the problem was clearly to find a way to get the generated script to exclude the summary when the footer wasn't visible. I tinkered with a few alternatives, ultimately settling on this one: set the summary's Enabled property to be databound to the expression:

Enabled='<%# DataBinder.Eval( Container.NamingContainer, "ShowFooter" ) %>'

Within templated controls such as a DataGrid, Container refers to the DataGridItem of the current row. DataGrids are naming containers for DataGridItems, so accessing Container.NamingContainer gives a reference to the DataGrid. Eval then uses reflection to find the ShowFooter property of the grid and assign it to the Enabled property of the contained ValidationSummary. My testing showed that with this expression, the summary no longer appeared in the Page_ValidationSummaries initialization list when the footer was hidden, and client-side validation prevented postbacks again. Problem solved!

posted on June 15, 2007  #    by Adam Anderson  Comments [0] Trackback