# Monday, October 12, 2009

I finally carved out some time to experiment with Silverlight 3 and .NET RIA Services over the weekend. Specifically I wanted to experiment with Forms security and how one might secure a Silverlight "page" as well as the services on the server side along with a custom membership, role and profile providers. Here's the result.

Tools
Before you follow along on your own machine, be sure that you have these:

1. Visual Studio 2008 Pro (Visual Studio 2008 Professional Edition (90-day Trial))

2. Visual Studio 2008 SP1 (Microsoft Visual Studio 2008 Service Pack 1 (Installer))

3. Silverlight SDK (Microsoft® Silverlight™ 3 Tools for Visual Studio 2008 SP1)

4. RIA Services July 2009 Preview (Microsoft .NET RIA Services July 2009 Preview)

5. Download code for this post (download DemoAgRia.zip 427KB).

Once you have the tools installed, you can start a new Visual Studio project from the Silverlight projects types called Silverlight Business Application. Name yours whatever you like. I've chosen DemoAgRia.

s1

The project template creates a Silverlight and ASP.NET Web Application project and populates them with a number of helpful artifacts to get us started. There are two DomainService classes, one for authentication and one for user registration. These services use the standard ASP.NET Membership, Role and Profile provider model.

s2

You also get several "views" or Page and ChildWindow XAML controls with code-behind. These files are a familiar construct to any classic ASP.NET developer. Of course XAML is a whole new ballgame compared to the hodge podge of HTML. But rather than focus on these page and child window objects, I will focus this post on the security aspects of the app.

While the project template sets authentication to "Forms" based authentication there are no membership, role, or profile providers configured in the web.config. Since I'm going to create some custom providers in order to just experiment with the mechanics of security within the Silverlight and the web app, I'll just spin up some stub providers. Here's the web.config sections (including the "Forms" authentication node) for them:

<authentication mode="Forms"/>

<roleManager enabled="true" defaultProvider="AgRoleProvider">
  <providers>
    <clear />
    <add name="AgRoleProvider" type="DemoAgRia.Web.AgRoleProvider" />
  </providers>
</roleManager>
<membership defaultProvider="AgMembershipProvider">
  <providers>
    <clear />
    <add name="AgMembershipProvider" type="DemoAgRia.Web.AgMembershipProvider" />
  </providers>
</membership>
<profile enabled="true" defaultProvider="AgProfileProvider">
  <providers>
    <clear />
    <add name="AgProfileProvider" type="DemoAgRia.Web.AgProfileProvider" />
  </providers>
  <properties>
    <clear />
    <add name="PhoneNumber" />
    <add name="FullName" />
  </properties>
</profile>

Now I stub out the provider classes in the Providers folder of the web application. I won't post the code here because the implementation provides dumb data or place holders. Of course, a real set of providers, whether you use the AspSqlMembership provider or role your own, will do real authentication and provide real role and profile access. The stub membership class will authenticate any username and password to allow us to just play with the happy path for now.

Note the custom properties I've added to the profile provider above. These require some custom code in two places. First, in the profile provider class and then in the User class found in the AuthenticationService.cs file. Here's the code for both:

in AgProfileProvider.cs:

public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, 
  SettingsPropertyCollection collection)
{
  string userName = context["UserName"].ToString(); //use this to look up real values for user

  SettingsPropertyValueCollection s = new SettingsPropertyValueCollection();
  foreach (SettingsProperty p in collection)
  {
    if (p.Name == "PhoneNumber") s.Add(new SettingsPropertyValue(p) { PropertyValue = "508.555.1212" });
    if (p.Name == "FullName") s.Add(new SettingsPropertyValue(p) { PropertyValue = "Tyler Jensen" });
    //NOTE: replace with real lookups
  }
  return s;
}
in AuthenticationService.cs:

public class User : UserBase
{
  // NOTE: Profile properties can be added for use in Silverlight application.
  // To enable profiles, edit the appropriate section of web.config file.

  // public string MyProfileProperty { get; set; }
  public string FullName { get; set; }
  public string PhoneNumber { get; set; }
}

Now to use these new profile provider properties, let's modify some XAML in the LoginControl.xaml file so that rather than seeing the username of the logged in user, we'll see the FullName and the PhoneNumber.

Here's the existing XAML which we will modify:

<StackPanel x:Name="logoutControls" Style="{StaticResource LoginPanelStyle}">
  <TextBlock Text="welcome " Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="{Binding Path=User.Name}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
  <Button x:Name="logoutButton" Content="logout" Click="LogoutButton_Click" Style="{StaticResource LoginRegisterLinkStyle}" />  
</StackPanel>

We now modify this XAML snippet to this:

 
<StackPanel x:Name="logoutControls" Style="{StaticResource LoginPanelStyle}">
  <TextBlock Text="welcome " Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="{Binding Path=User.FullName}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  phone: " Style="{StaticResource SpacerStyle}"/>
  <TextBlock Text="{Binding Path=User.PhoneNumber}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
  <Button x:Name="logoutButton" Content="logout" Click="LogoutButton_Click" Style="{StaticResource LoginRegisterLinkStyle}" />
</StackPanel>

Now lets add a DomainService for fecthing some data. Right click on the web application's Services folder and select Add | New Item.

s3

Of course, we don't have a data or object context class, so we don't have any to choose from in the dialog.

s4

Leave "Enable client access" checked. We want a proxy class to automatically be generated from our service class on the server side. Just click OK and let's create our own custom DomainService.

Now you'll see something like this:

 
namespace DemoAgRia.Web.Services
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.ComponentModel.DataAnnotations;
  using System.Linq;
  using System.Web.Ria;
  using System.Web.Ria.Data;
  using System.Web.DomainServices;


  // TODO: Create methods containing your application logic.
  [EnableClientAccess()]
  public class DemoDataService : DomainService
  {
  }
}

I'll put it into the root of the namespace by lopping off the ".Services" in the namespace declaration. This is just a convenience to me. You can do with it what you like.

Now let's add a couple of simplistic methods. Be sure to decorate them with the ServiceOperation attribute or the build process will not autogenerate the DemoDataContext class and proxy class in the Silverlight client app.

 
[EnableClientAccess()]
public class DemoDataService : DomainService
{
  [ServiceOperation]
  public string GetApplicationName()
  {
    return "Demo Ag Ria";
  }

  [ServiceOperation]
  public string GetApplicationAddress()
  {
    return "http://www.demoagria.com";
  }
}

To use the DemoDataService on the client, let's try the following code in the Home.xaml.cs file. Note the two additional using statements and take special note that all calls to the server are asynchronous:

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.IO;
using DemoAgRia.Web;
using System.Windows.Ria.Data;

namespace DemoAgRia
{
  public partial class Home : Page
  {
    public Home()
    {
      InitializeComponent();
    }

    // Executes when the user navigates to this page.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
      DemoDataContext ddc = new DemoDataContext();
      InvokeOperation<string> invAddress = ddc.GetApplicationAddress();
      invAddress.Completed += new EventHandler(invAddress_Completed);
      
      InvokeOperation<string> invAppName = ddc.GetApplicationName();
      invAppName.Completed += new EventHandler(invAppName_Completed);
    }

    void invAppName_Completed(object sender, EventArgs e)
    {
      InvokeOperation<string> op = sender as InvokeOperation<string>;
      string appName = op.Value;
      this.ContentText.Text += string.Format("{0}app name: {1}", Environment.NewLine, appName);
    }

    void invAddress_Completed(object sender, EventArgs e)
    {
      InvokeOperation<string> op = sender as InvokeOperation<string>;
      string address = op.Value;
      this.ContentText.Text += string.Format("{0}address: {1}", Environment.NewLine, address);
    }

  }
}

If you F5 and run a debug test, you'll note that the text in the Home page gets modified as expected.

s5

Now let's add a RequiresAuthentication to the GetApplicationName method:

[ServiceOperation, RequiresAuthentication]
public string GetApplicationName()
{
  return "Demo Ag Ria";
}

Run the app again and you will notice that the GetApplicationName's InvokeOperation<string> object's Value property is null. Now login and click the About page link and then go back to the Home page link. Note that the text has maintained it's state. We're not clearing it, but this time we've added text which includes the app name.

s6

Now try modifying the GetApplicationAddress method like this:

[ServiceOperation, RequiresRoles("Supervisor")]
public string GetApplicationAddress()
{
  return "http://www.demoagria.com";
}

Since the stubbed role provider gives your logged in user the Admin and Analyst role, you can run this and see that you are getting a null value for the operation. Now change the role to "Admin" and try the same thing. This time when you login and come back to the Home page you'll see what we'd expect.

Getting this far was almost enough fun, but then I wondered how I would prevent a user from navigating to a specific Silverlight page if they were not authenticated. There are probably better ways, but here's the solution I arrived at after a little fiddling.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

namespace DemoAgRia
{
  public class PageSecurity
  {
    private Page page;
    private string url;

    public PageSecurity(Page page)
    {
      this.page = page;
    }

    public void Authenticate()
    {
      Authenticate(null);
    }

    public void Authenticate(string url)
    {
      this.url = url;
      if (!RiaContext.Current.User.IsAuthenticated)
      {
        ErrorWindow ew = new ErrorWindow("You must be logged in to view this page.", 
          "Using this page is not allowed unless you are logged in.");
        ew.Title = "Authentication Required";
        ew.IntroductoryText.Text = "Not Authenticated";
        ew.LabelText.Text = "Message";
        ew.Closed += new EventHandler(ew_Closed);
        ew.Show();
      }
    }

    void ew_Closed(object sender, EventArgs e)
    {
      if (null == url)
        this.page.NavigationService.GoBack();
      else
      {
        if (!url.StartsWith("/")) url = "/" + url;
        try
        {
          this.page.NavigationService.Navigate(new Uri(url, UriKind.Relative));
        }
        catch
        {
          this.page.NavigationService.GoBack(); 
        }
      }
    }
  }
}

To test this code, I've added the following code to the About.xaml.cs code to see how it plays.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  PageSecurity ps = new PageSecurity(this);
  ps.Authenticate("Home");
}

Now all you have to do is download the code and you've got a headstart on Silverlight and .NET RIA Services security. Let me know if you find any exciting improvements or alternatives.

posted on Monday, October 12, 2009 3:01:52 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Wednesday, September 09, 2009

I am extremely impressed by the sage wisdom of Sir Charles Antony Richard Hoare's The Emperor's Old Clothes given at his acceptance of the Turing Award in 1980 and subsequently published by the Association for Computing Machinery (ACM) in 1981. Here are my favorite excerpts. I hope you will read the entire text using the link below.

"You know, you shouldn't trust us intelligent programmers. We can think up such good arguments for convincing ourselves and each other of the utterly absurd."
...
"Programmers are always surrounded by complexity; we cannot avoid it. Our applications are complex because we are ambitious to use our computers in ever more sophisticated ways. Programming is complex because of the large number of conflicting objectives for each of our programming projects. If our basic tool, the language in which we design and code our programs, is also complicated, the language itself becomes part of the problem rather than part of its solution."
...
"At first I hoped that such a technically unsound project would collapse but I soon realized it was doomed to success. Almost anything in software can be implemented, sold, and even used given enough determination. There is nothing a mere scientist can say that will stand against the flood of a hundred million dollars. But there is one quality that cannot be purchased in this way--and that is reliability. The price of reliability is the pursuit of the utmost simplicity. It is a price which the very rich find most hard to pay."
...
"The mistakes which have made in the last twenty years are being repeated today on an even grander scale."
...
"If only we could learn the right lessons from the successes of the past, we would not need to learn from our failures."
...
"To have our best advice ignored is the common fate of all who take on the role of consultant, ever since Cassandra pointed out the dangers of bringing a wooden horse within the walls of Troy."

The Emperor's Old Clothes
Sir Charles Antony Richard Hoare
Creator of the Quicksort algorithm
1980 Turing Award Winner
© 1981 ACM 0001-0782/81/0200-0075

Full text here in PDF.

Having accidentally browsed into this today, I reiterate the axiom that complexity is the enemy of sound software development and hereby recommit to following the path of simplification, learning more lessons from my successes to avoid more failures and to sometimes keeping my best advice to myself.

posted on Wednesday, September 09, 2009 8:53:36 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [2]
# Thursday, August 27, 2009

A week ago in a misguided attempt to make things easier, I created something like the following code. My mistake was not in creating the code necessarily, but in applying it to data driven auto generated enums. If you have those, don’t use this.

If you have nice, well behaved static enums wandering around your code and you wish you had a nice way to convert that enum to a usable Dictionary<int, string>, then you’ve come to the right place. So dress up that drab enum with a Description attribute like you see below and call EnumConverter.ConvertToDictionary<DrabEnum>();

And let me know how it works out.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace FunStuff
{
  public enum FunEnum
  {
    [Description("Happy Enum")]
    Happy = 1,

    [Description("Sad Enum")]
    Sad = 2
  }


  public static class EnumConverter
  {
    private static object lo = new object(); //used for locking access to the Cache
    private static Dictionary<Type, Dictionary<int, string>> enumStore = 
      new Dictionary<Type, Dictionary<int, string>>();

    /// <summary>
    /// Returns thread safe copy of enum value and name dictionary. Where Description <br />
    /// attribute exists, returns the description value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Dictionary<int, string> ConvertToDictionary<T>() where T : IComparable
    {
      lock (lo)
      {
        Type t = typeof(T);
        if (!t.IsEnum) throw new ArgumentException("T must be an enum.");
        if (!enumStore.ContainsKey(t)) enumStore.Add(t, Load(t));
        return new Dictionary<int, string>(enumStore[t]);
      }
    }

    private static Dictionary<int, string> Load(Type t)
    {
      Dictionary<int, string> list = new Dictionary<int, string>();
      foreach (MemberInfo m in t.GetMembers())
      {
        if (m.MemberType == MemberTypes.Field && m.Name != "value__")
        {
          string label = m.Name;
          foreach (var att in m.GetCustomAttributes(false))
          {
            DescriptionAttribute da = att as DescriptionAttribute;
            if (null != da)
            {
              if (da.Description.Length > 0)
              {
                label = da.Description;
              }
            }
          }
          int id = Convert.ToInt32(System.Enum.Parse(t, m.Name));
          list.Add(id, label);
        }
      }
      return list;
    }
  }
}
posted on Thursday, August 27, 2009 9:15:44 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Monday, July 27, 2009

In anticipation of repaving my Vista x64 machine with Windows 7 after the MSDN release on August 6, I’ve prepared my wish list of hardware upgrades I’d like to do at the same time I pave the machine with the new OS.

Should the family financial officer (FFO) decline to approve my purchase request, I’ll at least sneak in the SSD purchase.

Update (new list, bigger appetite):

Qty Description

Price

2 SUPER TALENT 12GB (3 x 4GB) 240-Pin DDR3 SDRAM DDR3 1333

$ 739.98

1 ASUS Z8NA-D6C Dual LGA 1366 Intel 5500 ATX Dual Intel Xeon 5500 Series

259.99

2 Intel Xeon E5520 Nehalem 2.26GHz LGA 1366 80W Quad-Core

765.98

1 SUPER TALENT MasterDrive SX SAM56GM25S 2.5" 256GB SATA II MLC Internal SSD

629.99

Total

$ 2,395.94

What plans do you have for your Windows 7 upgrade?

Drool….

posted on Monday, July 27, 2009 4:30:03 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [2]
# Tuesday, July 21, 2009

Here’s the content of the most exciting email I’ve received lately (invite code redacted of course):

Thank you for your interest in Windows® Azure™.

Your invitation code is xxxxx-xxxxx-xxxxx-xxxxx-xxxxx.

You can now sign up for a Windows Azure account at http://lx.azure.microsoft.com/fs. Please keep this email in a safe place.

This invitation to participate in the Windows Azure Community Technical Preview is subject to the following usage limits:

        Total compute usage: 2000 VM hours
        Cloud storage capacity: 50GB
        Total storage bandwidth: 20GB/day

During the CTP, we reserve the right to suspend your account activity (this does not imply we will delete your cloud storage) if you exceed these usage limits.

Sincerely,
Windows Azure Platform Team

You have received this email because you registered as being interested in the Community Technology Preview (CTP) of Windows Azure. As a participant in the Windows Azure CTP program, you will continue to receive emails related to that program unless you end your participation by emailing azinvite@microsoft.com with “END PARTICIPATION” in the subject line.

To ensure proper delivery of future updates please add azinvite@microsoft.com to your address book or safe-senders list.

Microsoft respects your privacy. To learn more about Microsoft's privacy policy, please click here.

Microsoft Corporation
One Microsoft Way
Redmond, WA 98052

I’m very excited to begin learning to develop against Azure in all my spare time. If I learn anything worthy of note here, I’ll share it. Just too many things to dabble in and too little time.

posted on Tuesday, July 21, 2009 4:26:23 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Sunday, July 12, 2009

With the release of Silverlight 3 on Friday, I’m wondering whether the enterprise (that mythical stereotype) will adopt Silverlight 3 for line of business (LOB) applications. The official “what’s new” section included the following items that I found very interesting:

Improving Rich Internet Application Productivity. New features include:

  • 60+ controls with source code : Silverlight 3 is packed with over 60 high-quality, fully skinnable and customizable out-of-the-box controls such as charting and media, new layout containers such as dock and viewbox, and controls such as autocomplete, treeview and datagrid. The controls come with nine professional designed themes and the source code can be modified/recompiled or utilized as-is. Other additions include multiple selection in listbox controls, file save dialog making it easier to write files, and support for multiple page applications with navigation.
  • Deep Linking. Silverlight 3 includes support for deep linking, which enables bookmarking a page within a RIA.
  • Search Engine Optimization (SEO). Silverlight 3 enables users to solve the SEO-related challenges posed by RIAs. By utilizing business objects on the server, together with ASP.NET controls and site maps, users can automatically mirror database-driven RIA content into HTML that is easily indexed by the leading search engines.
  • Enhanced Data Support Silverlight 3 delivers:
    • Element to Element binding : UI designers use binding between two UI properties to create compelling UI experiences. Silverlight now enables property binding to CLR objects and other UI components via XAML, for instance binding a slider value to the volume control of a media player.
    • Data Forms. The Data Form control provides support for layout of fields, validation, updating and paging through data.
    • New features for data validation which automatically catch incorrect input and warn the user with built-in validation controls.
    • Support for business objects on both client and server with n-Tier data support. Easily load, sort, filter and page data with added support for working with data. Includes a new built-in CollectionView to perform a set of complex operations against server side data. A new set of .NET RIA services supports these features on the server.
  • Improved performance, through:
    • Application library caching, which reduces the size of applications by caching framework on the client in order to improve rendering performance.
    • Enhanced Deep Zoom, allows users to fluidly navigate through larger image collections by zooming.
    • Binary XML allows communication with the server to be compressed, greatly increasing the speed at which data can be exchanged.
    • Local Connection This feature allows communication between two Silverlight applications on the client-side without incurring a server roundtrip: for instance a chart in one control can communicate with a datagrid in another.

I’ve just downloaded the bits and will begin exploring the new controls and just how easy it is or is not to build applications. My only criteria at the moment is whether or not the applications are as easy to build as a Windows Forms application. Obviously there are far more important evaluation criteria, but I’m wondering whether my stated criteria here will be the more common question raised in the enterprise. That is, can we build apps faster, easier, better with this? If not, I’m not sure the enterprise will get too awfully excited about it unless a clear case can be made for replacing the often time consuming, error prone web application development process with a simpler Silverlight 3 development process.

One way or another, I’m excited about Silverlight 3 and eager to dive in and have some fun.

posted on Sunday, July 12, 2009 2:59:43 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Saturday, May 02, 2009

Here’s my favorite feature’s of Windows 7 release candidate right after install into a VMware virtual machine.

win7rc

posted on Saturday, May 02, 2009 3:20:01 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Monday, April 27, 2009

A few weeks ago I made a major course correction in our choice of ORM data layer. We had planned to use LLBLGen Pro but several issues with the code that it generates continued to bother me. First, it's support for stored procedures lacked the ability to strongly type the resultset. Second, the data entity classes do not easily support serialization over WCF with the option to dress them up with the appropriate attributes.

So I took a second look at PLINQO with CodeSmith 5.0, something I had considered some time ago but had decided against because I felt it was not sufficiently mature for our team's use. I wanted to see if the dev team had improved the product to the point that I believed it would work for us. I'm very happy I gave it another try. They have done a great job and restored my confidence in LINQ to SQL.

With PLINQO, I found that I could return to standard LINQ to SQL queries and enjoy many of the benefits I had looked forward to using in LLBLGen Pro such as "disconnected" entities. And much to my satisfaction, PLINQO resolves the two major issues I had with the LLBLGen Pro. The improvements over standard LINQ to SQL may seem small at first but when dealing with a very large, enterprise class database, the enhancements that PLINQO offers are critical, including the separation of entities into individual class files.

There are many more features and benefits with PLINQO than I have time to review here. If you're looking for a better LINQ to SQL than LINQ to SQL, look very carefully at PLINQO. I mean, who couldn't fall in love with code like this all buttoned up for you automatically:

private long _userId;

//// <summary>
/// Gets the USER_ID column value.
/// </summary>
[System.Data.Linq.Mapping.Column(Name = "USER_ID", Storage = "_userId", 
     DbType = "bigint NOT NULL IDENTITY", IsPrimaryKey = true, 
	 IsDbGenerated = true, CanBeNull = false)]
[System.Runtime.Serialization.DataMember(Order = 1)]
public long UserId
{
    get { return _userId; }
    set
    {
        if (_userId != value)
        {
            OnUserIdChanging(value);
            SendPropertyChanging("UserId");
            _userId = value;
            SendPropertyChanged("UserId");
            OnUserIdChanged();
        }
    }
}
posted on Monday, April 27, 2009 9:31:03 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [8]
# Sunday, March 15, 2009

In a recent project I wanted to simplify the creation and configuration of a WCF proxy client and enforce programmatic configuration so that the client could only be used in a specific configuration. Here’s the result of that effort. Note that there is a static Create method and the standard ClientBase constructors have been marked as internal to prevent creation of the client in any other way.

public class ControlServiceClient : ClientBase<IControlService>, IControlService
{
    public static ControlServiceClient Create()
    {
        string controlServiceAddress = ConfigurationManager.AppSettings["controlServiceAddress"];
        NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Transport, false);
        tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
        tcpBinding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;

        //set other binding attributes
        tcpBinding.CloseTimeout = new TimeSpan(0, 1, 30);     //default is 1 minute.
        tcpBinding.MaxBufferPoolSize = 1048576;               //1MB default is 65,536 bytes

        //not allowed by partially trusted 
        //tcpBinding.MaxBufferSize = 262144;                  //256KB default is 65,536 bytes

        tcpBinding.MaxConnections = 10;                       //default is 10:
        tcpBinding.MaxReceivedMessageSize = 4194304;          //4MB The default is 65,536 bytes
        tcpBinding.OpenTimeout = new TimeSpan(0, 1, 30);      //The default value is 1 minute
        tcpBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);   //The default value is 10 minute
        tcpBinding.SendTimeout = new TimeSpan(0, 1, 30);      //The default value is 1 minute

        EndpointAddress endpointAddress = 
            new EndpointAddress(string.Format("net.tcp://{0}", controlServiceAddress));
        ControlServiceClient client = new ControlServiceClient(tcpBinding, endpointAddress);
        return client;
    }

    internal ControlServiceClient() { }

    internal ControlServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    { }

    internal ControlServiceClient(Binding binding, EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    { }

    internal ControlServiceClient(InstanceContext callbackInstance) :
        base(callbackInstance)
    { }

    public string GetData(int value)
    {
        return base.Channel.GetData(value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        return base.Channel.GetDataUsingDataContract(composite);
    }
}
posted on Sunday, March 15, 2009 9:29:31 AM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Saturday, January 10, 2009

Every few months I give up on stacking everything on my desk and begin the arduous task of cleaning it up. In my most recent battle with desktop clutter, I came to realize that I am a book addict. Set aside the numerous entertaining novels I've bought and read over the last few months because they don't make it to my work desk. If they did, I'd never get any work done.

Here's a list of just the books currently floating in the stacks on my desk. No, I am not making this up. And no, I'm not going to give you a link to each one of them. You can always hit www.amazon.com or your favorite alternative and look them up. Many of these come from my local Borders store and others from Amazon. My Amazon Prime account has more than paid for itself.

I must also confess that some of these were not purchased recently but have somehow made their way back off my shelf and onto my desk in recent months. The order is of no particular import except to note that it is essentially a LIFO list which may provide a quasi reverse chronological order to my wandering interests and/or problems/challenges.

  • Agile Principles, Patterns and Practices in C# by Martin and Martin
  • The Data Model Resource Book Volume 1 by Silverston
  • The Data Model Resource Book Volume 2 by Silverston
  • The Data Model Resource Book Volume 3 by Silverston and Agnew
  • Pro ASP.NET 2.0 in C# 2005 by MacDonald and Szpuszla
  • SQL Server Analysis Services 2005 with MDX by Harrinath and Quinn
  • Windows Workflow Foundation by Scribner
  • Programming WCF Services by Lowy
  • Pro C# 2008 and the .NET 3.5 Platform by Troelsen
  • jQuery in Action by Bibeault and Katz
  • Building a Data Warehouse by Rainardi
  • Programming Collective Intelligence by Segaran
  • Workflow in the 2007 Microsoft Office System by Mann
  • Pro SharePoint 2007 Development Techniques by Bruggeman and Bruggeman
  • Regular Expressions by Friedl
  • Regular Expression Recipes for Windows Developers by Good
  • Microsoft SharePoint Buidling Office 2007 Solutions in C# 2005 by Hillier
  • C# Cookbook by Teilhet and Hilyard
  • Refactoring Databases Evolutionary Database Design by Ambler and Sadalage
  • SharePoint Server 2007 Best Practices by Curry and English

Update: Wandering through the house, I found several more at various favorite reading spots. They've now taken their proper place on my desk piles. Here they are:

  • Pro Silverlight 2 in C# 2008 by MacDonald
  • Thinking in C++ Second Edition Volume 1 by Eckel
  • Chris Crawford on Interactive Storytelling by Crawford
  • A Programmer's Introduction to C# Second Edition by Gunnerson
  • Visual C# 2005: The Base Class Library by Balena (I won this one)

Yes, this is a sad but not unhealthy addiction. The only detriment here is to my pocketbook and the fact that I'm running out of shelf space. Do you any of you have similar addictions?

posted on Saturday, January 10, 2009 12:12:24 PM (Mountain Standard Time, UTC-07:00)  #    Comments [1]