DCSIMG
Smallfish

Smallfish

Tips, Tricks, Shticks & Anything That Can Help You Be better Developer

Quality Code Short Tip #3 – Use Nested Class for Constants

One of the ‘best-practice’ and code styling guidelines say that you need to use constants instead of literals for more readability and ease of maintenance. Among the usages there are time that you want to specify database field names, xml attribute / element names and etc. In such cases the code easily get messed with dozens of constants around the code and make it harder to find the constant you need.

A little trick can aid here:

Instead of:

   1:  class TheClassUsingTheConstants
   2:  {
   3:      public const string CustomerIdField = “CustomerId”;
   4:      public const string CustomerNameField = “CustomerName”;
   5:      public const string TaskIdField = “TaskId”;
   6:      public const string TaskTitleField = “TaskTitle”;
   7:   
   8:      private void UseConstants(IDataReader reader)
   9:      {
  10:             var fieldValue = reader[CustomerIdField];
  11:      }
  12:  }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Use:

   1:  class TheClassUsingTheConstants
   2:  {
   3:      private static class CustomerFields
   4:      {
   5:          public const string Id = “CustomerId”;
   6:          public const string Name = “CustomerName”;
   7:      }
   8:   
   9:      private class TaskFields
  10:      {
  11:           public const string Id= “TaskId”;
  12:           public const string Name = “TaskTitle”;
  13:      }
  14:   
  15:      private void UseConstants(IDataReader reader)
  16:      {
  17:             var fieldValue = reader[CustomerFields.Id];
  18:      }
  19:  }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Session Manager (post on post on post)

Today I read the Ran Wahle’s "Session manager" that was (kind of) response to Shlomo Goldberg’s post about a way to use the session state in type-safe way. Because I tried out both approaches but was only satisfied with another (slightly sharper approach to Ran’s) and I will be glad to share it too (as in all other fields, pick the best that works for you project in hand).

After several projects I have got to conclusion that there is no need for more than one object graph in the session, the more variables, the more your project get messy (without correlation of the method used). So, I’m designing a tree (each project by its own) that will contain the ‘sessional’ information. This leaves us with one (and only) session property to handle with the session state, all other properties are within the ‘root object’ tree (nested object-type properties).

My object will look like:

public class UserSessionInfo
{
    public const string SessionKey = "CurrentUser";

public string UserName { get; set; }

public ShppingCart Cart { get; set;}

//… other related properties …

}

The session initialization will take place in the AccountController (it is a project for learning the ASP.NET MVC using the default… ) right after successful login (in a method ‘SetUserSessionInfo’).

The other place is a ControllerBase, that is a controller that all other controllers derive from (if it was more complex project / WebForms may be another approach like IHttpModule or PageBase) and the initialization is done in ValidateUserSession that is called whenever the session is required from the Controller.Initialize method override (in this case is always but the login / register actions when the request is not authenticated). Of course (following Law of Demeter), I expose a protected property accessors for the properties (usually they will be readonly, but irrelevant for the discussion) like:

protected string UserName

{

    get { return m_currentUser.UserName; } // where ‘m_currentUser’ is a reference to the session object stored in the ValidateUserSession method.

}

Advanteges:

1. You / your team needs to handle only one object which is designed carefully and well thought off instead any one adding parameters here and there loosing the control.

2. This is the other side of ‘Single Responsibility Principle’ by Robert C. Martin, whereas only one object in the whole system (maybe a ‘parent’ object) is used to access ‘sessional’ information.

3. One may ask if it doesn’t have performance penalty because of all information stored in the session. Good question, but you can always leave a reference (like the Cart property) to null taking only the reference bytes (4 / 8) which is neglect able.

Disadvanteges:

Slightly more work of design and thinking… (or does it advantage ;-) )

And final notes about other implementations:

1. Using singleton tightly coupled your whole project to the type and the same instance, which is horrified for testing and it is the ‘most misused design pattern’ i have ever saw.

2. As a good citizen of .net, please forget that the keyword ‘sealed’ ever existed (future post), in this case (if it was written in .net 2 and up it could be ‘static’ class).

3. For the enum approach, I don’t think the ‘ToString’ performance is an issue, just an nondeterministic way to convert to string as it may be localized (currently it isn’t but who knows), using ‘Enum.GetName’ instead would help.

4. A nice wrapper around the session would be C# 3.0 extension methods around the HttpSessionStateBase type like:

public static UserSessionInfo CurrentUser(this HttpSessionStateBase session) { return session[UserSessionInfo.SessionKey] as UserSessionInfo; }

5. A warning: the expression “Session != null” can throw exception of “Session is not available…” in some cases, bad design by .net, but you need to take care.

Have fun!

Quality Code Short Tip #2 – Don’t Create What Isn’t Required

In Israel, this sign say “one-way street Update: dead-end” (you enter and exit the same side):

 OneWay

Now, if you see this sign, its meaning is clear. But if you see this sign:

WrongOneWay

You will start to think “What is this number? is it until 2011? from 2011? serial number of the sign?” etc.

So, why it is not as clear in development?

Many times, developers “prepare for the future” adding variables, db columns, tables etc. for “future use” - “I know we will need it in the future…”, but as in the sign, if you add it now you are adding “noise” to the code / db / etc. and may mislead your fellow developer (or you?)

so: Don’t Create What Isn’t Required Now!

Now, you are working on current tasks, create just what you need to accomplish the current task.

WPF vs. Windows Forms

This argument exists since the first version of WPF (Windows Presentation Framework), so what should one select, WPF or Windows Forms?

I will start with my conclusion / disclaimer:

Any new windows client should use WPF!

Now, for the explanation:
The biggest "flaw" of WPF is its learning curve, it is slightly hard to understand the "rhythmic" of it. Thus, many companies / developers prefer the comfort zone of windows forms as it seems more easy and "fast" to develop.
The fact is that after you pass over the first barrier of WPF, it become much easier, simpler and faster to develop.
Aspects where WPF that led me to my conclusion:

  • Productivity:

The most valuable feature here is WPF data binding, it saves your time because you don't need to manually mess with the controls directly, and by applying good design such MVVM or alike you will go faster. So, you may say "windows forms supports data binding also", and yes, you right but it is like comparing Mercedes to Subaru (nothing bad with Subaru, but …).
I have put this first because in most applications (especially commercial) developers' time is the most valuable in terms of money.
WPF supports many other automations that leads you to the (my?) first rule if productivity: Write Less Code, because writing less code takes less time, introduces less bugs (there is exponential or at least linear correlation between the amount of code you write and the number of bugs you have). Writing less code requires less source code which ease visual studio / source control to work much faster, and thus takes less valuable time of the developer.

  • Usability:

In WPF it is very simple to create more usable application which, for my opinion, should be the most critical measurement for the customer. One if the features that enables this is the Commanding architecture that let's you bind a command to various buttons / input gestures like keyboard shortcuts or even multi-touch gestures in the near future.

  • Performances:

The most valuable feature in this area is the use of Hardware Acceleration which is not only speed up your graphic it is also frees the main CPU for other important tasks. For more information look at WPF- Pick Your API Abstraction by Pablo Fernicola.

  • Technology:

In most fields newer technology is better, with less defects  as it evolves from experience in the problem domain, tooling and processes. I will bet that Microsoft® used better development and product manage process in WPF than in windows forms.

  • Support:

Traditionally Microsoft® supports application for about ten or twelve years (my informal rough estimation) which means that WPF will be supported long after windows forms and it will continue to be developed further in contradiction to windows forms (that already stopped&).

  • Eye Candy:

Beautiful applications sell better, it's a fact. In WPF you almost have to create nicer application because it easier and because it let's you cooperate graphics designers in the process.

References:

In Defense of Eye Candy by Stephen P. Anderson

Enjoy WPF, Now!

Quality Code Short Tip #1 – Say “Defects” not “Bugs”

I wanted to start a short tips series for improving code and application quality, each post will be 1 to few sentences with a tip.

First tip:

Say “Defects”, not “Bugs”

For me, the word “bug” sounds as “something not so important that is in the nature of the application”, which at least it isn’t true! when the application doesn’t do what it should (or do it wrong, or crash etc) it is a Defect in our application. It is hard because we are so naturally says it, but we should start to change our terminology for better software!

Posted: Sep 25 2009, 09:24 AM by Yair Cohen | with no comments
תגים:, ,

Programming Tip For Easier Life or Applying SRP Principle On Variables / Enums

According to the first principle of S.O.L.I.D, SRP – Single Responsibility Principle, a class should have one responsibility, shortly, it should have only one reason to change.

Example

Let assume that we have to create a software for importing CSV data to the database.

Fast & Dirty” 

Reading directly from the CSV file into the database, line by line, on each line parsing (in separated method, or worse inline) the string and writing it to database.

   1:  public class CSVtoDbImporter
   2:  {
   3:      public void Import(string fileName)
   4:      {
   5:          using (var reader = File.OpenRead(fileName))
   6:          {
   7:              string line;
   8:              while ((line = reader.ReadLine()) != null)
   9:              {
  10:                  InsertToDb(line);
  11:              }
  12:          }
  13:      }
  14:   
  15:      public void InsertToDb(string line)
  16:      {
  17:          var values = line.Split(',');
  18:          var insertStatement = string.Format("INSERT INTO Table VALUES({0},'{1}')",values);
  19:          ExecuteCommand(insertStatement);
  20:      }
  21:  }

The problem here is that when the file format changes or the db schema changes this class should be updated (or rewritten), violating the SRP.

SRP Applied”

Reading each row to corresponding POCO object that represents the row loosely from the format (doesn’t care if it CSV, XML or any other form), and a specialized reader, CSVReader that sends this object to another class, DbImporter, that knows how to import it to the db. (performance issues are not relevant here, because on (very-)large files you can still stream the object one at a time and keep the separation)

   1:  public class TableRow
   2:  {
   3:      public int Id { get; set; }
   4:      public string Name { get; set; }
   5:  }
   6:   
   7:  public class CSVReader : IReader
   8:  {
   9:      public TableRow[] Read(string fileName)
  10:      {
  11:          // read and parse each line into TableRow objects and return the array...
  12:      }
  13:  }
  14:   
  15:  public class DbImporter : IDbImporter
  16:  {
  17:      public void Import(TableRow[] rows)
  18:      {
  19:          // insert each row into db
  20:      }
  21:  }

In this snippet, when the database schema changed, only the DbImporter changes, and the reader remains the same. On the other side, if the file format is changed, only the reader implementation is changed.

SRP in Variables

It may seem straignt forward but this principle is violated in variables too in the form of ambiguity: using the same variable to represent more than one meaning, for example:

   1:  int status = (int)Statuses.SomeStatus
   2:   
   3:  // …
   4:   
   5:  if (status == (int)Statuses.SomeStatus) status = 125 /* Some other code, not a status */
   6:   
   7:  First, the principle: 

Variable should have one and only one meaning – if it represents status, it is a status variable, if it represents code it is code variable, never the same.

This ambiguity WILL catch you, and it will be in the most inappropriate time. It introduce parallel flow (do not confuse with parallel computing) for the application making it very hard to maintain the code, harm the productivity and introduce defects (bugs) that  are very hard to spot and fix.

Of-course, this principle applies to properties, constants, enums etc.

So, express yourself!

How To Create XAML Markup Extension in WPF – Creating the Now markup extension

What?

Display a label and analog clock on screen, they should be updated “live” with the time.

How?

I use XAML Markup Extension for several reasons:

  1. It makes it easy to use it on XAML, especially to bind to it.
  2. Learn the framework extension points.
  3. Reuse – easy to use it everywhere with half line of XAML.

Show me the money!

    /// <summary>
    /// XAML Markup Extension to bind dependency property (DateTime or String)
    /// to the current date and time (updated each second)
    /// </summary>
    public class NowExtension : MarkupExtension
    {
        #region State
 
        // default, full date format (current culture)
        private readonly string m_format = 
            CultureInfo.CurrentCulture.DateTimeFormat.FullDateTimePattern;
        // for empty constructor we return the DateTime
        private readonly bool m_returnDate = false;
 
        private DependencyObject m_targetObject;
        private DependencyProperty m_targetProperty;
        private DispatcherTimer m_timer;
 
        #endregion
        #region Constructors
 
        /// <summary>
        /// Create new Now Extension that return the 
        /// current DateTime (DateTime.Now)
        /// </summary>
        public NowExtension()
        {
            m_returnDate = true;
        }
 
        /// <summary>
        /// Create new Now Extension that return the 
        /// current DateTime formatted (calling ToString 
        /// with m_format)
        /// </summary>
        public NowExtension(string format)
        {
            if (!string.IsNullOrEmpty(format))
            {
                m_format = format;
            }
        }
 
        #endregion
 
        /// <summary>
        /// Overrides MarkupExtension.ProvideValue to return 
        /// the current datetime and hook a timer to update the 
        /// target propery each second 
        /// (using DispatcherTime with Background priority)
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var targetHelper = 
                (IProvideValueTarget)
                serviceProvider.GetService(typeof(IProvideValueTarget));
 
            m_targetObject = 
                targetHelper.TargetObject as DependencyObject;
 
            m_targetProperty = 
                targetHelper.TargetProperty as DependencyProperty;
 
            m_timer = new DispatcherTimer(DispatcherPriority.Background);
            m_timer.Interval = TimeSpan.FromSeconds(1);
            m_timer.Tick += new EventHandler(m_timer_Tick);
            m_timer.Start();
 
            if (m_returnDate)
            {
                return DateTime.Now;
            }
 
            return GetNowValue();
        }
 
        protected virtual string GetNowValue()
        {
            return DateTime.Now.ToString(m_format);
        }
 
        void m_timer_Tick(object sender, EventArgs e)
        {
            if (m_targetObject != null && m_targetProperty != null)
            {
                object value = GetNowValue();
                if (m_returnDate)
                {
                    value = DateTime.Now;
                }
                m_targetObject.SetValue(m_targetProperty, value);
            }
        }
    }

How does it works?

The first time the ProviderValue is called, we are hooking to the target DependencyObject / DependencyProperty so we will be able to set the property on timer intervals. Then we start a timer (with interval of 1 second) and in that timer Tick event we set the new value to the hooked property, the last line just return the current value for the first time.

Posted: Apr 19 2009, 08:46 AM by Yair Cohen | with 1 comment(s)
תגים:, , ,

How To Get A Property Name Using Lambda Expression in C# 3.0

During development of WPF application using M-V-VM design pattern (by Josh Smith on MSDN Mag.) I came across a problem of refactoring the view model classes, especially the properties’ names. The view model classes are implementing the INotifyPropertyChanged interface by inheriting from a helper NotifyPropertyChanged base class which have a method to raise the property changed event called ‘SendPropertyChanged’. That method gets “propertyName” parameter which is a string, and this was the problem:

My view model properties looks like:

        private string m_name;
        public string Name
        {
            get 
            {
                return m_name;
            }
            set
            {
                if (m_name != value)
                {
                    m_name = value;
                    SendPropertyChanged("Name");
                }
            }
        }

the problem here is if I change the property name to “CustomerName” I must ensure to correct the string name in the method parameter. Even worse, if for some reason another method / property is calling ‘SendPropertyChanged’ for the ‘Name’ property it will cause invisible problems (you will see it on the screen, but very difficult to spot). And then:

Lambda Expression to the rescue!

What I wanted to achieve is:

        private string m_name;
        public string Name
        {
            get 
            {
                return m_name;
            }
            set
            {
                if (m_name != value)
                {
                    m_name = value;
                    SendPropertyChanged(()=> this.Name);
                }
            }
        }

Note the bolded “() => this.Name”, this will ensure that if anyone changes the name of the property the build will fail (or, using the Refactoring->Rename in VS will change it automatically). After a lot of searches I found the way to do this (in Bernardo Heynemann blog post):

        private string GetPropertyName<T>(Expression<Func<T>> property)
        {
            var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
            if (propertyInfo == null)
            {
                throw new ArgumentException("The lambda expression 'property' 
should point to a valid Property");
            }
 
            var propertyName = propertyInfo.Name;
 
            return propertyName;
        }

Note the parameter type Expression<Func<T>> – whenever you cast a delegate (in this case of Func<T>) into Expression you are getting the associated Expression Tree and not the delegate itself. The call is clean and nice due to another feature of C# 3.0 ‘Type inference’ the compiler determines the type of T parameter and does not require us to add the ugly curly brackets.

Enjoy the new revolution!

Quick tip: When Visual Studio (2008) Stop Opening A Web Application In Web Browser

This problem was hitting me several times and I couldn't spot what it was, so here it is:

The Problem

When starting Debug or Start Without Debugging of a Web Application in Visual Studio 2008 the internal web server is started but the Web Browser doesn't.

The Solution

Right-Click on your Default.aspx file (I assume it will be fine for any .aspx either) and select Browse With... and select the browser you want, that's all!

(in my machine it was configured for XML Editor for mysterious reason :))

Keep Going!

LINQ to SQL Performance loading Hierarchical data

Last week I have trying to load hierarchical data from the same table (Parent/Child). Although I have made it in the past, I was searching the way to accomplish it with LINQ to SQL without SP or at least with the minimum required (in any case, I had a "fallback"). After 4 hours of searching the net without success (there are plenty of articles, nothing met my requirements see here and here).

Then I thought to give LINQ a chance, and I just used it querying the association created by the designer. I was astonished to reveal it caused to only one T-SQL statement (!!!) to load the full hierarchy(bottom to top, meaning each item as its full ancestors list accessed by .Parent property, does not include children), and the performance? total of 50,000 (10,000 per level, 5 levels in hierarchy) loaded in less than 2.5 seconds! which is great for our purpose (in no case I will query the full table without any filtering criteria).

My satisfaction is based on some assumptions:

1. Each T-SQL written to the log (DataContext.Log) is a roundtrip to the server.

2. This test is by far almost 10x than what we would face in production environment.

3. The test was made on my dev machine without network roundtrip, but based on assumption 1, it will be 1 roundtrip which is necessary in any case.

4. I didn't tweak the LINQ engine for the best performance (like read-only datacontext, LoadWith etc.)

Why should I eliminate / minimize the use of SPs / T-SQL and use almost-only LINQ to SQL?

In one word, maintenance, which is, for my opiniongn, the most valuable aspect for most of business applications, because business change and so your application, it will be hard to maintain you will pay a lot of money for each chae and this will minimize or worst, eliminate all your profit. Using LINQ to SQL affects maintenance in several aspects, I will elaborate two of them:

1. Most of development resources are, well, developers. And in C# (or .NET at all) they know C# the most, they have much advanced tools and IDE to use with that language, they are in friendly environment. When those developers are required to write T-SQL / SPs, they are trying to "escape" or eventually do this but the results are fairly bad so you need a DBA to re-write those procedures

2. DataBase is more "static" than the code, more over, changing the database will probably affect many parts (modules) of the application and it is very hard to maintain compared to compiled code.

Conclusion,

Move to LINQ to SQL (L2S), it saves time, streamlines the development and maintenance process!

Internet Explorer 7 position problem with dynamic created elements

Hi all,

This is an issue i'm facing a lot with ajax web applications - when you have dynamically created elements on a web page, Internet Explorer may have problems lying out those items and some items may "disapear" from the page by a magic...

Now, and the times before, the followingexcellent  article comes to he rescue: "On having layout" (cant find who is the editor, there are some in the bottom of the page).

Have fun!

Link:

http://www.satzansatz.de/cssd/onhavinglayout.html

How to configure WCF REST service hosted in IIS (properly)?

Trying to configure WCF REST service hosted in IIS you may encounter an error message saying something like:

"The message with To '*' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree."

where '*' is the address you are trying to access. There are some answers here and there on the web but those are incomplete or hard to understand.

The Problem

When using the "*.svc" file to host a service within ASP.NET web site, regular WCF ServiceHost is created. WCF itself does not understand the REST address (as specified by the UriTemplate property of WebGet attribute), so we should configure the proper endpoint behavior "webHttp".

The Solution

So, here is how to configure WCF REST service to be hosted in IIS:

To host a service on IIS we are creating ".svc" file to map that file URL to the service type, for example:

<%@ ServiceHost Language="C#" Debug="true" Service="[ServiceFullTypeName]" %>

To enable this service as REST service, we will configure the required endpoint and behaviors in web.config:

<system.serviceModel>
<behaviors>
<endpointBehaviors>
          <behavior name="WebBehavior">
            <webHttp/>
          </behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="[ServiceTypeFullName]">
<endpoint address="js" binding="webHttpBinding" behaviorConfiguration="WebBehavior" contract="[ServiceContractName]"/>
</service>
</services>
</system.serviceModel>

Thats all!

Note that the "baseAddress" of this service is the URL to the ".svc" file, the "js" address is not required, but I prefer to distinguish between the "regular" address and the JSON address.

How to reset Identity column in SQL Server?

Recently, a programmer in my team, Amichai Sichel, had found a way to reset identity column in SQL Server DataBase. The reason he had to reset it was for testing and because of relations between tables he could not use TRUNCATE TABLE.

Assuming you want to clear your data, you first need to clean it with DELETE FROM [TableName], then you can RESEED it to any number you want, you need to RESEED it to the value before incrementing (if the column is specified a IDENTITY (1,1) which means its incremental is 1, you need to set it to the value you want minus 1)

DBCC CHECKIDENT('[TableName]', RESEED, 0) -- Will reseed it to 0 and the next identity will be 1 (assuming IDENTITY(1,1))

DBCC CHECKIDENT('[TableName]', NORESEED) -- Will not reseed the value and will return the maximum column value

for more information: http://technet.microsoft.com/en-us/library/ms176057.aspx

Thanks to Amichai Sichel

The stubborn "," or Why Does It Work on FireFox But Not on Internet Explorer

I wanted to share with you a strange behavior that I ran into today: ASP.NET web site that works on FireFox 2 (I assume it will work on 3 too), but it does not work on Internet Explorer!

I have disabled script debugging since I have FireBugs, as the web is full of JavaScript bugs and the popup message is annoying and also the line number that Internet Explorer reports on does not help at all.

After a little struggling I have found that the problem was an unnecessary colon (",") in JavaScript "class", like this:

function A(){}

A.prototype = {
funcA: function(a,b) { return a * b; },
funcB: function() { ... } , // <- Note this colon
};

This works great on FireFox (and FireBugs) but fails in Internet Explorer 7...
I had removed that colon and now it works great.

Testing WCF Service using Visual Studio 2008 Unit Tests

Testing Windows Communication Foundation (WCF) service should be handled in a slightly different way than other "regular" .net types. We should test the service logic (as always) but we also need to test it in few more manners to assure our service quality:

  • Test the service within WCF runtime environment - which can raise several issues that would not be in regular CLR environment.
  • Test for your default binding and for all other bindings required from the service specs.
  • Test DataContract serialization - you will be surprise by a service failure when you see the service is running ok but client still get error (empasizes with REST service)

* The method I will show here uses Visual Studio 2008 Unit Tests framework but it can easily be ported into NUnit or other framework.

Tests Inheritance

Any Unit Test is a plain .net class, so we can use inheritance, polymorphism and overriding to re-use the original (logic) test of the service. The driven unit test class should contain the "TestClass" attribute at least, all methods on parent class marked with "TestMethod" attributes will run also when testing the concrete class.

Let's start

First, we will define the target of the test, the obvious Calculator Service (I always use interface for ServiceContract, also in Demo :)):

   1:  // Defines the Calculator Service contract
   2:  [ServiceContract]
   3:  public interface ICalculatorService
   4:  {
   5:      [OperationContract]
   6:      int Add(int a, int b);
   7:   
   8:      [OperationContract]
   9:      int Subtract(int a, int b);
  10:   
  11:      [OperationContract]
  12:      int Multiply(int a, int b);
  13:   
  14:      [OperationContract]
  15:      int Divide(int a , int b);
  16:  }
  17:      

 

Then, you should define your service implementation (I'll skip it, you can download the full code here). We will test the contract interface and not the concrete implementation be able to test another implementations of the ICalculatorService contract. The logic-test will be defined (code trimmed):

   1:  [TestClass]
   2:  public class CalculatorTest
   3:  {
   4:      ...
   5:      protected virtual ICalculatorService CreateTarget()
   6:      {
   7:              ICalculatorService target = new CalculatorService();
   8:              return target;
   9:      }
  10:   
  11:      [TestMethod]
  12:      public void Add2Positive()
  13:      {
  14:          int a = 1;
  15:          int b = 2;
  16:          int expected = 3;
  17:   
  18:          ICalculatorService calculator = CreateTarget();
  19:          int actual = calculator.Add(a,b);
  20:   
  21:          Assert.AreEqual(expected, actual);
  22:      }
  23:      ...
  24:  }

the key method here is the CreateTarget which creates the target of the test and it is marked as protected virtual so we can override it in sub-class and the test will keep its logic. And we will do just that:

Testing the service within its real environment - WCF runtime

   1:      [TestClass]
   2:      public class CalculatorServiceTestAsWCFService 
   3:                            : ICalculatorServiceTest
   4:      {
   5:          private ServiceHost m_serviceHost;
   6:          [TestInitialize]
   7:          public void InitializeHost()
   8:          {
   9:              m_serviceHost = new ServiceHost(
  10:                          typeof(CalculatorService));
  11:              m_serviceHost.AddServiceEndpoint(
  12:                          typeof(ICalculatorService), 
  13:                          GetTestBinding(), 
  14:                          new Uri( GetTestAddress()));
  15:   
  16:              m_serviceHost.Open();
  17:          }
  18:   
  19:          protected virtual string GetTestAddress()
  20:          {
  21:              return "http://localhost:9999/Calculator";
  22:          }
  23:   
  24:          [TestCleanup()]
  25:          public void CloseHost()
  26:          {
  27:              if (m_serviceHost != null)
  28:              {
  29:                  m_serviceHost.Close();
  30:              }
  31:          }
  32:   
  33:          protected virtual Binding GetTestBinding()
  34:          {
  35:              return new WSHttpBinding();
  36:          }
  37:   
  38:          protected override ICalculatorService CreateTarget()
  39:          {
  40:              ICalculatorService calcServiceClient = 
  41:                  ChannelFactory<ICalculatorService>.CreateChannel(
  42:                                      GetTestBinding(), 
  43:                                      new EndpointAddress(GetTestAddress()));
  44:   
  45:              return calcServiceClient;
  46:          }
  47:      }

Here we inherits from our logic-test class and add several methods:

  1. InitializeHost - on each test, we create a host, and add test service endpoint using the ICalculatorService contract, test address and binding
  2. GetTestAddress,GetTestBinding - virtual methods for generating the testing address and binding. If you want to test your service against several bindings you just need to inherit this class and override these 2 methods.
  3. CloseHost - on test cleanup, closes the host.
  4. CreateTarget - overrides the base class' method to provide a real WCF client for the test, so the test methods will now work in environment as close as possible to the real environment (including serializations, interceptions etc.)

Notes

  • This method assume that the target service logic is not depend on WCF runtime environment like OperationContext for example.
  • Don't over-test the WCF, meaning, test only bindings you want to guaranty (if you work with Compact Framework clients, it would be basicHttpBinding, for example) 

Links

More Posts Next page »