PlayOn Plugin - TECH.ED 2011

Well I really enjoyed creating the MIX 2011 PlayOn plugin that I decided to do the same for TECH.ED 2011. I am going to do a bit more research and see if in the next release I can provide a folder for each year as they have published all of the archives for TECH.ED and MIX back to 2008.

When you access the TECH.ED 2011 channel you will see it grouped by All Sessions - Provides a entire list of all sessions, By Category - groups each of the sessions based on the category it falls under, By Speaker - groups each of the videos by the speaker

TECHED2011.plugin (33.50 kb)

To install download the file and then open your playon software and go to the Plugins tab. At the bottom of that screen click Install and browse out to the file.

**** UPDATE ****

Just updated the download with a new version that supports checking for updates and cached the RSS feed so that subsequent access to the sessions is very quick. 

PlayOn Plugin - MIX 2011

I have been using PlayOn software to view online content via my XBOX for about 6 months now and while it is really cool I dont find myself using it as much as I thought I would. However one thing I have enjoyed is using it to view last years MIX 2010 content that someone provided a plugin script for. However as of MIX 2011 they reformatted the website and now the previous plugin does not work.

So this prompted me to take a look at the PlayOn API and see if I could either fix the script or create a new one. In the process of things I decided to write my own. If you are using PlayOn premium feel free to download and install my plugin to view the MIX 2011 sessions. 

It is truly a joy to sit in front of my TV instead of my computer and watch these sessions. When you access the MIX 2011 channel you will see it grouped by All Sessions - Provides a entire list of all sessions, By Category - groups each of the sessions based on the category it falls under, By Speaker - groups each of the videos by the speaker

MIX2011.plugin (30.50 kb)

To install download the file and then open your playon software and go to the Plugins tab. At the bottom of that screen click Install and browse out to the file.

**** UPDATE ****

Just updated the download with a new version that supports checking for updates and cached the RSS feed so that subsequent access to the sessions is very quick.

Fix error: Failed to generate a user instance of SQL Server due to a failure in starting the process for the user instance.

For anyone using Visual Studio and trying to add a SQL Database File and getting the error: "Failed to generate a user instance of SQL Server due to a failure in starting the process for the user instance." you might want to give the following steps a try.

 

Make sure you have enabled user instances. Open SQL Server Management Studio and connect to .\SQLEXPRESS

Run the following query

exec sp_configure 'user instances enabled', 1
go
reconfigure

Now restart SQL

Now you must delete the files that SQLExpress creates when adding instances if they already exist.

Go to your Local Settings folder.

Windows 7: C:\Users\YOUR_USERNAME\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS

Windows XP: C:\Documents and Settings\YOUR_USERNAME\Local Settings\Application Data\Microsoft\Microsoft SQL Server Data\SQLEXPRESS

Delete all files in the above folder

Hopefully if the above worked you will now be able to create databases inside VS with no issue.

ASP.NET CustomValidator that validates multiple controls using both Server Side and Client Side scripting

ASP.NET has some nice validation controls built in that can help make validating forms much easier. Listed below are a few of the available controls.

RequiredFieldValidator – Ensures that the user does not skip a field that has some requirement for being selected or filled out.

CompareValidator - Compares a user's entry against a constant value, against the value of another control (using a comparison operator such as less than, equal, or greater than), or for a specific data type.

RangeValidator - Checks that a user's entry is between specified lower and upper boundaries. You can check ranges within pairs of numbers, alphabetic characters, and dates.

RegularExpressionValidator - Checks that the entry matches a pattern defined by a regular expression. This type of validation enables you to check for predictable sequences of characters, such as those in e-mail addresses, telephone numbers, postal codes, and so on.

All the above controls have you specify the ControlToValidate which can be any one of these types: DropDownList, FileUpload, ListBox, RadioButtonList, TextBox, HtmlInputFile, HtmlInputPassword, HtmlInputText, HtmlSelect and HtmlTextArea

But what if you want to perform validation against a control type not listed or on multiple controls? Have no fear as the  CustomValidator control allows you to write your own server side and client side validation logic and get as complex as you want.

All of the previously mentioned controls require you to specify the control you want to validate via the poperty ControlTValidate, however with CustomValidator you can leave it blank which then leaves you to specify logic server side and client side to perform any validation you like.

So let’s take this to the real world. Recently I was faced a scenario that could not be handled by the standard set of validation controls.

Example) A series of 5 independent checkbox controls and at least one of them was required to be checked. Plus if Other is selected then you must fill in the textbox.

image

So the behavior should be that you must select at least one checkbox and if none selected then you will get an error “You must select at least one checkbox” and if the Other checkbox is selected then they must also supply text in the texbox field.

Here is a snippet from the ASPX source showing the controls and the CustomValidator

Code Snippet
  1. Please select the skill's you have:
  2. <br />
  3. <asp:CheckBox ID="checkBoxCSharp" runat="server" Text="C#" />
  4. <br />
  5. <asp:CheckBox ID="checkBoxASPNET" runat="server" Text="ASP.NET" />
  6. <br />
  7. <asp:CheckBox ID="checkBoxJavascript" runat="server" Text="Javascript" />
  8. <br />
  9. <asp:CheckBox ID="checkBoxHtml" runat="server" Text="Html" />
  10. <br />
  11. <asp:CheckBox ID="checkBoxOther" runat="server" Text="Other" />
  12. &nbsp;
  13. <asp:TextBox ID="textBoxOther" runat="server" />
  14. <br />
  15. <br />
  16. <asp:Button ID="buttonSubmit" runat="server" Text="Submit" />
  17. <asp:CustomValidator
  18.     ID="CustomValidatorSkillsYouHave"
  19.     runat="server"
  20.     ErrorMessage="You must select at least one skill"
  21.     ForeColor="Red"
  22.     OnServerValidate="CustomValidatorSkillsYouHave_ServerValidate" />

Notice that we do not have specified ControlToValidate. As well we have defined a OnServerValidate method that will get called when the page is posted back to the server.

Here is the server side method

Code Snippet
  1. protected void CustomValidatorSkillsYouHave_ServerValidate(
  2.     object source, ServerValidateEventArgs args)
  3. {
  4.     if (!this.checkBoxASPNET.Checked &&
  5.         !this.checkBoxCSharp.Checked &&
  6.         !this.checkBoxHtml.Checked &&
  7.         !this.checkBoxJavascript.Checked &&
  8.         !this.checkBoxOther.Checked)
  9.     {
  10.         args.IsValid = false;
  11.     }
  12.     else if (this.checkBoxOther.Checked &&
  13.         string.IsNullOrEmpty(this.textBoxOther.Text.Trim()))
  14.     {
  15.         ((CustomValidator)source)
  16.             .ErrorMessage = @"You must supply a text
  17.                               description when selecting other";
  18.         args.IsValid = false;
  19.     }
  20. }

In this method we check to see if at least one checkbox was checked and if not set the args.IsValid = false which will cause the validator to fail. If the first test is passed we check to see if the Other checkbox is checked and if so ensure that the texbox was filled out. If not then we set args.IsValid = false but we also change the error message to provide a better description of the failure.

However the above only happens when posted back to the server. We also want to provide some client side validation in order to prevent a post back to the server if the same type of validation fails on the client side.

To do this we specify the ClientValidationFunction property on the CustomValidator to point to our JavaScript function to perform the client side validation. In this case I created a JavaScript function called IsSkillsYouHaveValid as shown below.

Code Snippet
  1. <script type="text/javascript">
  2.     function IsSkillsYouHaveValid(source, args) {
  3.         var checkBoxCSharp = document.getElementById('checkBoxCSharp');
  4.         var checkBoxASPNET = document.getElementById('checkBoxASPNET');
  5.         var checkBoxJavascript = document.getElementById('checkBoxJavascript');
  6.         var checkBoxHtml = document.getElementById('checkBoxHtml');
  7.         var checkBoxOther = document.getElementById('checkBoxOther');
  8.         var textBoxOther = document.getElementById('textBoxOther');
  9.  
  10.         if (!checkBoxASPNET.checked &&
  11.         !checkBoxCSharp.checked &&
  12.         !checkBoxHtml.checked &&
  13.         !checkBoxJavascript.checked &&
  14.         !checkBoxOther.checked) {
  15.             args.IsValid = false;
  16.         }
  17.         else if (checkBoxOther.checked &&
  18.         textBoxOther.value == "") {
  19.             source.innerText = 'You must supply a text ' +
  20.                             'description when selecting other';
  21.             args.IsValid = false;
  22.         }
  23.  
  24.     }
  25. </script>

So with this extra bit of client side code we will now perform client side validation that if failed will prevent the page from being posted back to the server, thus avoiding an unnecessary round-trip.

BUT we are not done yet. I am picky and one of the things I don’t like about the following solution so far is that when you correct the validation failure by for instance selecting at least one checkbox or by filling out the textbox if you have selected Other is that the error message still appears until you click the submit button. I want the user to immediately know once they have correct the issue that they have satisfied the validation.

To do this we need to add one more method. This method will be responsible revalidating to see if the validation passes if any change happens to one of the controls we are validating.

Code Snippet
  1. function ValidateSkillsYouHave() {
  2.     var customValidator = document.getElementById('CustomValidatorSkillsYouHave');
  3.     var checkBoxCSharp = document.getElementById('checkBoxCSharp');
  4.     var checkBoxASPNET = document.getElementById('checkBoxASPNET');
  5.     var checkBoxJavascript = document.getElementById('checkBoxJavascript');
  6.     var checkBoxHtml = document.getElementById('checkBoxHtml');
  7.     var checkBoxOther = document.getElementById('checkBoxOther');
  8.     var textBoxOther = document.getElementById('textBoxOther');
  9.  
  10.     if (!checkBoxASPNET.checked &&
  11.     !checkBoxCSharp.checked &&
  12.     !checkBoxHtml.checked &&
  13.     !checkBoxJavascript.checked &&
  14.     !checkBoxOther.checked &&
  15.     !checkBoxOther.checked) {
  16.         customValidator.isvalid = false;
  17.         customValidator.style.visibility = "visible";
  18.     }
  19.     else if (checkBoxOther.checked &&
  20.     textBoxOther.value == "") {
  21.         customValidator.innerText = 'You must supply a text ' +
  22.                         'description when selecting other';
  23.         customValidator.isvalid = false;
  24.         customValidator.style.visibility = "visible";
  25.     }
  26.     else {
  27.         customValidator.isvalid = true;
  28.         customValidator.style.visibility = "hidden";
  29.     }
  30. }

Now when we submit the form and the validation fails and the user goes and selects at least one checkbox then the validation will be re-evaluated and immediately update the display to remove the validation error when it passes.

I know this was a bit of extra work but when you have a big form and you have implemented RequiredFieldValidators etc.. in which the error message goes away when you fill in the field but your custom validators do not it starts to stand out and the extra little bit of work provides a better end user experience.

Now much of the Javascript code written about could have been done much easier using JQuery and no guarantee the javascript written is cross browse safe. I used IE8 in all my testing and would personally recommend implementing a Javascript library like JQuery that abstracts the browser differences out. However I wanted to keep it simple without adding the need to explain the JQuery syntax.

Click on the download link to download a copy of the full source for this article Download Source

 

kick it on DotNetKicks.com

Silverlight PivotViewer control released

The silverlight PivotViewer control allows you to build very large collections and embed them on your website. Works really well for collections that provide a visual representation of the data you are navigating and uses the silverlight deep zoom feature so navigating high resolution images is very quick.

To download the control go here

To view some demo's check out these sites using it already.

Netflix Demo

Hitched wedding site in the UK

Also Scott Guthrie provides a more in depth article.

ASP.NET MVC3 Preview 1 - Released Today

You can download the new ASP.NET MVC3 Preview 1 here

This is the next major release of the ASP.NET MVC framework and is fully backwards compatible with projects using ASP.NET MVC2.

ASP.NET MVC3 has all the great features of the previous releases and builds on top of that foundational work. So everything you previously used and learned still apply.

So what is new?

Multiple View Engines - Views now allow you to select the desired view engines you have installed on your machine. Example (ASPX, Razor, NHaml, Spark

Global Filters allow developers to apply filter logic across all controllers in an application.

Dynamic ViewModel Property enables you to use the new dynamic language support to pass ViewData in a cleaner syntax.

New ActionResult types - HttpNotFound, HttpRedirectResult and HttpStatusCodeResult

Built-in JSON binding support to enable action methods to receive JSON-encoded data and bind it to action method parameters.

Model Validation improvements added support for the new .NET 4 DataAnnotations metadata attributes, IValidateObject interface to do custom validation at the class level.

Dependency injection - Better support for using Dependency Injection and IOC containers. You can now use dependency injection in Controllers, Views and Action Filters with future support for Model Binders, Value Providers, Validation Providers and Model metadata Providers.

Visit Brad Wilson's article on MVC3 dependency injection support.

I am excited to see the improvements and look forward to upgrading my current projects to use some of the new features.

Bind DNS – Configuring multiple views on primary and secondary DNS servers

If you have a firewall with DMZ and Internal zones and you have machines that sit behind the firewall that query DNS that resolves back to your machines inside one of those zones then it is likely that you have had to setup some type of DNS configuration that allows internal hosts to resolve a DNS name to the internal IP rather than the public IP address.

Now you could do that by creating hosts entries on each machine so that it does not use DNS to resolve the machine name, or you could setup a set of DNS servers for internal machines to use that only host internal DNS. However that complicates things and makes it very hard to maintain.

If you are using BIND DNS then you have an option called Views. Views allow you to create zones  that will return different information based on the IP address or range of IP addresses that are querying. However getting this configuration right can be a little tricky as my experience it researching the topic resulted in lots of bad information.

So I am attempting to create an article that hopefully will help the next person who needs to set this up.

So lets take a look at views. A view as defined by the creator of BIND is “The view statement is a powerful feature of BIND 9 that lets a name server answer a DNS query differently depending on who is asking. …. Each view statement defines a view of the DNS namespace that will be seen by a subset of clients. A client matches a view if its source IP address matches the address_match_list of the view's match-clients clause ”

This looks like it will accomplish exactly what we want. So let me provide an example scenario to help us walk through the configuration.

We will be setting up 2 DNS servers. One of the servers will act as our primary (master) server and the other as a secondary (slave) server. The master is were all DNS changes will be made to our zones and those changes will then get propagated to the slave server. We want DNS servers and clients on the public internet to be able to query for our zones and get returned to them the public IP information. However the servers and machines inside our firewall should have returned to them the internal IP addresses when querying the same zone.

I am attaching the two named.conf files that are referenced below.

Master Server  named.conf

Secondary named.conf

The following information is fictitious and only used to create this example.

External Network: 74.125.127.0/24

Internal Network: 192.168.1.0/24

Domain: mydomain.com

So lets assume our external zone should look like the following.

$ttl 38400
mydomain.com.   IN      SOA     dns1.mydomain.com. postmaster.mydomain.com. (
                        1271863698
                        10800
                        3600
                        604800
                        38400 )
mydomain.com.   IN      NS      dns1.mydomain.com.
mydomain.com.   IN      NS      dns2.mydomain.com.

dns1.mydomain.com.     IN      A       74.125.127.10
dns2.mydomain.com.     IN      A       74.125.127.11

mail.mydomain.com.      IN      A       74.125.127.5
mydomain.com.   IN      MX      10 mail.mydomain.com.

www.mydomain.com     IN      A       74.125.127.6

and our internal zone looks like this

$ttl 38400
mydomain.com.   IN      SOA     dns1.mydomain.com. postmaster.mydomain.com. (
                        1271863698
                        10800
                        3600
                        604800
                        38400 )
mydomain.com.   IN      NS      dns1.mydomain.com.
mydomain.com.   IN      NS      dns2.mydomain.com.

dns1.mydomain.com.     IN      A       192.168.1.10
dns2.mydomain.com.     IN      A       192.168.1.11

mail.mydomain.com.      IN      A       192.168.1.5
mydomain.com.   IN      MX      10 mail.mydomain.com.

www.mydomain.com     IN      A       192.168.1.6

So what we want to happen is that if a client on the internet queries for www.mydomain.com they will get 74.125.127.6 and if anything behind the firewall queries for www.mydomain.com they will get the internal IP 192.168.1.6

MASTER SERVER

So lets take a look at the named.conf on our master server and see how it looks.

We first create some acl entries that will make it easier to configure some of our options by using a friendly name that contains a list of IP addresses.

The first ACL “dns_slaves” will be used to hold the IP addresses we will use on our secondary servers. Notice that it has two IP addresses .11 and .12. This is because later we will be configuring our secondary server with 2 IP addresses to allow it to use a different source IP address for queries to the master server based on if we are getting external or internal zone information.

acl "dns_slaves" {
        192.168.1.11;
        192.168.1.12;
};

The ACL “internal_slave” is the IP address that will be used by the secondary DNS server to query for internal zone information

acl "internal_slave" {
        192.168.1.11;
};

The ACL “external_slave” is the IP address that will be used by the secondary DNS server to query for external zone information

acl "external_slave" {
        192.168.1.12;
};

The ACL “internal_hosts” represents the IP range of our internal network that queries will come from

acl "internal_hosts" {
        192.168.1.0/24;
};

options allows us to define global defaults for all zones and views. The two options that are important are the allow-query { any; } which allows by default any client to query the zone mydomain.com and any others we may decide to host in our DNS servers. The next important settings is recursion setting which we have defaulted to no. Recursion allows clients to query a DNS server for any domain that the server is not responsible for and get back DNS information. Since we do not want the world to use our DNS servers except when resolving our domains we have set this by default to no. Later we will override that setting for clients behind the firewall since they will be using the DNS server to also resolve other domains.

options {
        directory "/etc";
        pid-file "/var/run/named/named.pid";
        allow-query { any; };
        recursion no;
};

Now here is the configuration for our internal view.

match-clients - Since the internal view should only be used by IP addresses querying from inside our network the match-clients has two entries. !external_slave which will block a query coming from the slave server IP that is used for the external zone and an entry matching our internal_hosts acl which is any IP address in that acl range. Note that since we do not have any other acl anything else is automatically denied.

recursion –Set to yes so that internal clients can do recursive lookups using this server.

allow-transfer - Set to internal_slave so that the secondary can request transfers for this views zones.

also-notify - Set to the IP address of the secondary server. For some reason BIND does not allow you use an ACL when setting this entry. This is also not necessary to add but I found it made it very explicit. By default BIND will use the DNS entries listed for the zone.

zone mydomain.com - Simply defines that it is a master zone.

view "internal" {

        match-clients {
                !external_slave;
                internal_hosts;
        };

        recursion yes;

        allow-transfer {
                internal_slave;
        };

        also-notify {
                192.168.1.11;
        };

        zone "." {
                type hint;
                file "/var/named/root.internal";
        };
        zone "localhost" {
                type master;
                file "/var/named/localhost.internal.hosts";
        };
        zone "1.0.0.127.in-addr.arpa" {
                type master;
                file "/var/named/127.0.0.1.internal.rev";
        };
         zone "mydomain.com" {
                type master;
                file "/var/named/mydomain.com.internal";
        };

};

Now we jump to our external view

match-clients – Matches a query from external_slave which is the IP address that will be used by the slave server to query for zone information to the primary server. !internal_hosts excludes any other IP address internal from querying the zones in external and the last statement any allows all other IP’s to match the view.

recursion – Set to no so that no external clients can use the DNS server for recursive queries

allow-transfer – Set to allow the IP of the slave server assigned for external view to make zone transfers

also-notify – Set to IP of secondary to notify it of zone updates

zone mydomain.com – points to file containing the internal zone information

view "external" {

        match-clients {
                external_slave;
                !internal_hosts;
                any;
        };

        recursion no;

        allow-transfer {
                external_slave;
        };

        also-notify {
                192.168.1.12;
        };

        zone "mydomain.com" {
                type master;
                file "/var/named/mydomain.com.external";
        };

};

So that finishes up our primary (master) server confirmation. In summary our master has two views “Internal” and “External” which hosts different zone files based on the clients that will query it. If someone queries and matches our “External” view they will get the public IP addresses. If someone queries and matches our “Internal” view they will get the private IP addresses.

SECONDARY SERVER

ACL entries

dns_master is the IP address of the master server

acl dns_masters {
        192.168.1.10;
        };

internal_hosts is our internal ip range

acl internal_hosts {
        192.168.1.0/24;
        };

options has two entries that are important. allow-query {any;} which allows any IP to query the zones we host and recursion no to not allow by default recursive lookups.

options {
        directory "/etc";
        pid-file "/var/run/named/named.pid";
        allow-query { any; };
        recursion no;
};

Here is our internal view

match-clients – Set to internal_hosts to only allow IP addresses inside the network to match the view

recursion – Set to yes to allow internal clients recursive lookup capabilities

zone mydomain.com – This is the important part. Notice that transfer-source is set to 192.168.1.11. This forces the zone transfer request to come from the IP 192.168.1.11. When the master server see’s the query coming from that IP it will match the internal view and transfer the correct zone information for mydomain.com that matches the internal zone.

view "internal" {

        match-clients {
                internal_hosts;
                };

        recursion yes;

        allow-notify {
                dns_masters;
                };

        zone "." {
                type hint;
                file "/var/named/root.internal";
                };

        zone "localhost" {
                type master;
                file "/var/named/localhost.internal.hosts";
                };
        zone "1.0.0.127.in-addr.arpa" {
                type master;
                file "/var/named/127.0.0.1.internal.rev";
                };

        zone "mydomain.com" {
                type slave;
                masters { 192.168.1.10; };
                transfer-source 192.168.1.11
                file "/var/named/slaves/mydomain.com.internal";
        };
};

External View

match-clients - !internal_hosts prevents internal IP’s from getting external view and matches everything else due to the any statement.

recursion – Set to no so that external clients are not able to perform recursive lookups.

allow-notify – Set to dns_masters to allow notifications from the master server

zone mydomain.com - This is the important part. Notice that transfer-source is set to 192.168.1.12. This forces the zone transfer request to come from the IP 192.168.1.12. When the master server see’s the query coming from that IP it will match the internal view and transfer the correct zone information for mydomain.com that matches the internal zone.

view "external" {

        match-clients {
                !internal_hosts;
                any;
                };

        recursion no;

        allow-notify {
                dns_masters;
                };

        zone "mydomain.com" {
                type slave;
                masters { 192.168.1.10; };
                transfer-source 192.168.1.12;
                file "/var/named/slaves/mydomain.com.external";
        };

};

Reed Copsey, Jr presented Windows Forms to WPF with MVVM at last Seattle DOT Net User Group Meeting

I am mostly an ASP.NET developer but after watching Reed show the group the basics of WPF and how easy it was in my opinion compared to winforms I am convinced now that I am going to start doing WPF going forward.

Reed put together some great slides and a basic application to demonstrate the power of WPF. He moved from a basic winform app using event driven development to a converted WPF app with the same event driven style as the winform version. Then he slowly moved his app over to more advanced features of WPF and ended with using the MVVM design pattern.

Reed was kind enough to publish his slides and samples: http://reedcopsey.com/talks/from-windows-forms-to-wpf-with-mvvm/

Here is an excerpt from the page

This talk illustrates how Windows Presentation Foundation can dramatically improve the experience of developers, not just designers. Two versions of a simple application will be demonstrated, one developed using Windows Forms, and one using the same approach in WPF. By showing the same application in both technologies, we will show how a short learning curve can be used to migrate development to WPF.

I’ll then discuss three new features of WPF: Data Binding, Templating, and Commanding. I’ll show how they enable a new application architecture, the Model-View-ViewModel pattern, and illustrate how rethinking our approach to design in terms of these three features allows for huge gains in flexibility, testability, and maintainability of our applications.

Finally, we’ll look at third version of our application, a rewrite of our previous application using the Model-View-ViewModel pattern.

This talk is approximately 1 hour and 15 minutes in length.

 

 

Seattle DOT Net User Group Meeting - March 2010 Meeting : An Introduction to Visual Studio 2010 Extensibility

For more information about the usergroup visit www.seattledotnet.org

When

From: March 10, 2010 05:45 PM

To: March 10, 2010 08:00 PM

Publication date: February 07, 2010 12:00 AM

Location

Where
Street: 2401 Utah Ave. S.
City: Seattle
State: Washington
Country: USA

What

Speaker: Nathan Halstead

 
Nathan Halstead is the Program Manager responsible for the Visual Studio 2010 SDK.  Over the past two years, Nathan has worked to improve the packaging, licensing, diagnostic, and extensibility technologies at the core of the Visual Studio architecture.  Prior to his work with the Visual Studio team, Nathan worked on the data modeling features in the Microsoft Office PerformancePoint Server product suite, and as a research assistant on machine learning technologies at Carnegie Mellon University’s Institute for Software Research.  Nathan holds a Bachelor’s degree in Computer Science from Carnegie Mellon University.  In his spare time, Nathan has been spotted playing amateur hockey at local ice rinks or falling gracefully down mountains covered in snow in an attempt to ski.

 

Abstract : An Introduction to Visual Studio 2010 Extensibility

Have you ever wanted to customize and enhance the out-of-box Visual Studio 2010 development environment? Do you have an idea for a new integrated tool, but don't know how to get started? This talk will cover the basics of Visual Studio extensibility and show you how to take advantage of the numerous extension points inside Visual Studio. Additionally, we'll be discussing the new extensibility enhancements in Visual Studio 2010 and how you can leverage those in your application. This will be a fun session with plenty of demos, and will have something for both the Visual Studio novice and the seasoned veteran.

Want a head start?  Visit the developer center: http://www.msdn.com/vsx.

(MVP) Model View Presenter - Passive View

In my journey to write better software I have been looking at various patterns available. One of them is known as the Model View Presenter or MVP pattern. In doing some reading many of the sites I have come across point to Martin Fowlers website who is well known for his contribution in design patterns. He has put the MVP pattern into two separate types Passive View  and Supervising Controller.

In this blog entry I am going to focus on the Passive View as it provides complete separation from your model and allows you to completely mock out your view for testing. One additional note is that I found many people swap out the term Presenter for Controller which is a bit confusing since another pattern exists called (MVC) Model View Controller. So I will be sticking to the term Presenter.

 mvp-pattern-diagram

Disclaimer: I am just starting to understand this pattern so I may not explain it or design it in a way that maintains 100% true to the pattern. I am looking forward to feedback or comments that would correct anything I have misunderstood or may provide a clearer understanding of the pattern.

Views - Views are the entry point into the process. In the case of a asp.net application this would be the .aspx page. In the case of a winform application it would be the form itself.  Each view will have a interface that represents the data that needs to be inserted, retrieved, or databound to the view.

Presenter - Each view will have a presenter assigned to it that is responsible for handling all interaction with the view. The goal of the presenter is to move the logic out of the view itself and put the responsibility into the presenter.

Model - The model is a representation of the data that should be displayed on the view. In some cases the model is represented by some object that is returned from a datasource such as a database. In many cases additional layers exist between the datasource and model and business specific entities may have been created to represent the model while abstracting away the source of the information.

So how does this relate to a standard project we would create. In order to demonstrate the benefit of the pattern I am going to create a small winform application using the way I would have normally coded it and then refactor the project to use the MVP pattern.

Project Summary: Create a windows application with one form that if given a customerId will lookup customer in our datasource and display the first and last name, City and State. Once a customer has been retrieved the user should be able to edit the City or State and save the changes. Validation should also be performed to ensure that customerId is an integer value, City and State is required and cannot be empty.

Project Details: Winform application using .net 3.5 framework. Data will be stored and retrieved from SQL Express database using Linq to SQL and will return to the Presenter the actual Ling to SQL entities that this framework creates.

Project Layout: I created a folder called Views which will contain a sub folder for each view I am creating. I personally do this because each view has an associated Interface and Presenter class created and this provides a simple way to keep them together. I will also create a Models folder which will hold my Linq to SQL code and anything I do to extend the Models. 

ProjectFolderView

CustomerView Form – Here is the form that will display and allow editing of City and State

CustomerView.cs - Here is the initial code with all interaction between the model and the view being directly inside the form. The problem with this particular way of developing is that the only way to test the application is to bring up an instance of the application and manually test or use some kind of test automation software that records and plays back things.

public partial class CustomerView : Form
{
    public CustomerView()
    {
        InitializeComponent();
    }

    private void buttonSearch_Click(object sender, EventArgs e)
    {
        string customerIdString = this.textBoxCustomerId.Text.Trim();
        int customerId;
        Customer customer = null;

        if (customerIdString == "")
        {
            MessageBox.Show("CustomerId cannot be empty");
            return;
        }

        try
        {
            customerId = Int32.Parse(customerIdString);
        }
        catch
        {
            MessageBox.Show("CustomerId must be an integer value");
            return;
        }

        try
        {
            customer = Customer.GetCustomerById(customerId);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            return;
        }

        this.textBoxCustomerIdReadOnly.Text = customer.CustomerId.ToString();
        this.textBoxFirstName.Text = customer.FirstName;
        this.textBoxLastName.Text = customer.LastName;
        this.textBoxCity.Text = customer.City;
        this.textBoxState.Text = customer.State;

    }

    private void buttonSave_Click(object sender, EventArgs e)
    {
        string city = this.textBoxCity.Text.Trim();
        string state = this.textBoxState.Text.Trim();

        if (this.textBoxCustomerIdReadOnly.Text == "")
        {
            MessageBox.Show("No customer has been loaded");
            return;
        }

        if (city == "")
        {
            MessageBox.Show("City cannot be empty");
            return;
        }

        if (state == "")
        {
            MessageBox.Show("State cannot be empty");
            return;
        }

        Customer customer = new Customer();
        customer.CustomerId = Convert.ToInt32(this.textBoxCustomerIdReadOnly.Text);
        customer.FirstName = this.textBoxFirstName.Text;
        customer.LastName = this.textBoxLastName.Text;
        customer.City = this.textBoxCity.Text;
        customer.State = this.textBoxState.Text;

        try
        {
            Customer.SaveCustomer(customer);

            MessageBox.Show("Customer Saved");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

Refactoring to use MVP: Now I will refactor the above code to use the MVP Passive View pattern. This will create an Interface that represents the view and place a presenter in between the Model and the View to do all the interaction between layers.

ICustomerView – I created an interface ICustomerView that will represent the data on the form as shown below. This view will get injected into the Presenter constructor so that it has access to writing and retrieving values from the View.

public interface ICustomerView
{
    string CustomerIdInput { get; }
    string CustomerIdReadOnly { set; get; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string City { get; set; }
    string State { get; set; }
    void ShowMessage(string message);
}

CustomerViewPresenter – The CustomerView form will contain an instance of this class which will take control of the setting and getting of values from the form. It will also handle the retrieving and saving of information from the Model. Notice that the constructor takes an instance of ICustomerView

public class CustomerViewPresenter
{
    private ICustomerView customerView;

    public CustomerViewPresenter(ICustomerView customerView)
    {
        this.customerView = customerView;
    }

    public void LoadCustomer()
    {
    }

    public void SaveCustomer()
    {
    }

}

Refactored Project View – This shows the additional files created ICustomerView and CustomerViewPresenter.

ProjectFolderView-refactored

CustomerView Refactored - Now that I have the interface and presenter created let’s move our code from our CustomerView form into our presenter. Notice that the form now has a private instance declared CustomerViewPresenter and in the constructor of the view we instantiate a new instance of the presenter and pass in ICustomerView represented by this. Also note that the search and save button click events no longer contain any code to load or save the customer but rather calls the presenter methods to take care of the logic.

public partial class CustomerView : Form, ICustomerView
{
    CustomerViewPresenter customerViewPresenter;

    public CustomerView()
    {
        InitializeComponent();
        customerViewPresenter = new CustomerViewPresenter(this);
    }

    private void buttonSearch_Click(object sender, EventArgs e)
    {
        customerViewPresenter.LoadCustomer();

    }

    private void buttonSave_Click(object sender, EventArgs e)
    {
        customerViewPresenter.SaveCustomer();
    }

    #region ICustomerView Members

    public string CustomerIdInput
    {
        get { return this.textBoxCustomerId.Text.Trim(); }
    }

    public string CustomerIdReadOnly
    {
        get { return this.textBoxCustomerIdReadOnly.Text; }
        set { this.textBoxCustomerIdReadOnly.Text = value; }
    }

    public string FirstName
    {
        get { return this.textBoxFirstName.Text.Trim(); }
        set { this.textBoxFirstName.Text = value; }
    }

    public string LastName
    {
        get { return this.textBoxLastName.Text.Trim(); }
        set { this.textBoxLastName.Text = value; }
    }

    public string City
    {
        get { return this.textBoxCity.Text.Trim(); }
        set { this.textBoxCity.Text = value; }
    }

    public string State
    {
        get { return this.textBoxState.Text.Trim(); }
        set { this.textBoxState.Text = value; }
    }

    public void ShowMessage(string message)
    {
        MessageBox.Show(message);
    }

    #endregion
}

CustomerViewPresenter - Below shows what is inside the presenter now. Since the presenter gets passed into it an interface representing the view it can now interact directly with the view. It is now up to the presenter to talk to the Model and get a customer and set the views information or retrieve information from the view and save it.

public class CustomerViewPresenter
{
    private ICustomerView customerView;

    public CustomerViewPresenter(ICustomerView customerView)
    {
        this.customerView = customerView;
    }

    public void LoadCustomer()
    {
        Customer customer = null;
        int customerId;

        if (customerView.CustomerIdInput == "")
        {
            customerView.ShowMessage("CustomerId cannot be empty");
            return;
        }

        try
        {
            customerId = Int32.Parse(customerView.CustomerIdInput);
        }
        catch
        {
            customerView.ShowMessage("CustomerId must be an integer value");
            return;
        }

        try
        {
            customer = Customer.GetCustomerById(customerId);
        }
        catch (Exception ex)
        {
            customerView.ShowMessage(ex.Message);
            return;
        }

        customerView.CustomerIdReadOnly = customer.CustomerId.ToString();
        customerView.FirstName = customer.FirstName;
        customerView.LastName = customer.LastName;
        customerView.City = customer.City;
        customerView.State = customer.State;
    }

    public void SaveCustomer()
    {

        if (customerView.CustomerIdReadOnly == "")
        {
            customerView.ShowMessage("No customer has been loaded");
            return;
        }

        if (customerView.City == "")
        {
            customerView.ShowMessage("City cannot be empty");
            return;
        }

        if (customerView.State == "")
        {
            customerView.ShowMessage("State cannot be empty");
            return;
        }

        Customer customer = new Customer();
        customer.CustomerId = Convert.ToInt32(customerView.CustomerIdReadOnly);
        customer.FirstName = customerView.FirstName;
        customer.LastName = customerView.LastName;
        customer.City = customerView.City;
        customer.State = customerView.State;

        try
        {
            Customer.SaveCustomer(customer);

            customerView.ShowMessage("Customer Saved");
        }
        catch (Exception ex)
        {
            customerView.ShowMessage(ex.Message);
        }
    }

}

So you might be asking about now “Why do I want to move all my logic to another class? Seems like all I did was make things more complicated and created more code!”. The real value of doing it this way comes in the ability to now write unit tests against our code.

Since the CustomerView now has an interface ICustomerView that represents the view, we can now substitute the real form for a mocked version of it and perform all the validation we would normally have done manually.

The other benefit you get is that you have separated the logic from your view so you could use this same code to create an asp.net web application by just creating your aspx pages and reusing all of your interface and presenter code.

Testing – Below is the project view of my test project. It is when you get to this part you find the real advantages of your work above. Below is the view of the test project. Note the two files CustomerViewMock.cs which is a mock of our real view and CustomerViewTests.cs which contains all our test we want to perform.

testprojectview

CustomerViewMock – This class in my test project represents my view. Note that the class inherits from my ICustomerView interface. You will also notice that I created public properties representing each of the components that would have been on my real form. I do this to keep my tests feeling like I am interacting with the real form.

public class CustomerViewMock : ICustomerView
{
    public string textBoxCustomerId { private get; set; }
    public string textBoxCustomerIdReadOnly { get; private set; }
    public string textBoxFirstName { get; private set; }
    public string textBoxLastName { get; private set; }
    public string textBoxCity { get; set; }
    public string textBoxState { get; set; }
    public string messageBox { get; private set; }

    private CustomerViewPresenter customerViewPresenter;

    public CustomerViewMock()
    {
        customerViewPresenter = new CustomerViewPresenter(this);
    }

    public void ButtonLoad()
    {
        customerViewPresenter.LoadCustomer();
    }

    public void ButtonSave()
    {
        customerViewPresenter.SaveCustomer();
    }

    #region ICustomerView Members

    public string CustomerIdInput
    {
        get { return textBoxCustomerId; }
    }

    public string CustomerIdReadOnly
    {
        get { return textBoxCustomerIdReadOnly; }
        set { textBoxCustomerIdReadOnly = value; }
    }

    public string FirstName
    {
        get { return textBoxFirstName; }
        set { textBoxFirstName = value; }
    }

    public string LastName
    {
        get { return textBoxLastName; }
        set { textBoxLastName = value; }
    }

    public string City
    {
        get { return textBoxCity; }
        set { textBoxCity = value; }
    }

    public string State
    {
        get { return textBoxState; }
        set { textBoxState = value; }
    }

    public void ShowMessage(string message)
    {
        messageBox = message;
    }

    #endregion
}

CustomerViewTest - And here is my test class with the various tests that I would have normally had to do manually. Now I can go in and make changes to the logic of my presenter and quickly run my existing tests and be sure I am not going to break any existing logic.

[TestClass]
public class CustomerViewTest
{
    public CustomerViewTest()
    {
    }

   
    [TestMethod]
    public void CustomerView_LoadValidCustomerId()
    {
        CustomerViewMock customerView = new CustomerViewMock();
        customerView.textBoxCustomerId = "1";
        customerView.ButtonLoad();

        Assert.AreEqual<string>("1", customerView.textBoxCustomerIdReadOnly);

    }

    [TestMethod]
    public void CustomerView_SaveCustomerCity()
    {
        CustomerViewMock customerView = new CustomerViewMock();
        customerView.textBoxCustomerId = "1";
        customerView.ButtonLoad();

        customerView.City = "Bellevue";
        customerView.ButtonSave();

        Assert.AreEqual<string>("Customer Saved", customerView.messageBox);

    }

    [TestMethod]
    public void CustomerView_CustomerIdTextBoxEmpty()
    {
        CustomerViewMock customerView = new CustomerViewMock();
        customerView.textBoxCustomerId = "";
        customerView.ButtonLoad();

        Assert.AreEqual<string>("CustomerId cannot be empty", customerView.messageBox);

    }

    [TestMethod]
    public void CustomerView_CustomerIdTextBoxWithSpace()
    {
        CustomerViewMock customerView = new CustomerViewMock();
        customerView.textBoxCustomerId = "";
        customerView.ButtonLoad();

        Assert.AreEqual<string>("CustomerId cannot be empty", customerView.messageBox);

    }

    [TestMethod]
    public void CustomerView_CustomerIdTextBoxNotInteger()
    {
        CustomerViewMock customerView = new CustomerViewMock();
        customerView.textBoxCustomerId = "ABC";
        customerView.ButtonLoad();

        Assert.AreEqual<string>("CustomerId must be an integer value", customerView.messageBox);

    }
}

That is all I have for now. Please provide feedback if you see anything wrong or have any suggestions that would further improve my approach. I am thinking about adding on to this post an example of taking the Interface and Presenter and moving them into its own project. Then creating this same interface in asp.net just to show the ability to reuse the code. For now I hope this helps someone with understanding the MVP – Passive View pattern.

kick it on DotNetKicks.com