Matt's ramblings

Thursday, August 7, 2008

WCF Client Proxy IDisposable - Generic WCF Service Proxy

I have run into this issue on several clients now.  The basic issue is when using WCF on the client, using ClientBase<>, and you do not close the channel, you can tie up the server until the channel times out.  So, once the max instances, sessions, or concurrent calls is reached and the clients are not closing their channels, the server will block and queue up subsequent calls.  The un-closed client channels will eventually timeout, which causes a fault on the client, and the next set of calls will then make it through.

When I first hit this issue, my thought was to wrap my client base code in a using () statement so Dispose() would then be called.  But, ClientBase<> does not implement IDisposable.  Here is some info on the issue...

Guidance on factory close and message faults

Why does ClientBase Dispose need to throw on faulted state

So, after lots of testing to understand all the WCF knobs to tweak, I came up with a generic class I called ServiceProxy for clients to use when creating/using client channels.  This has been through several revisions and here is what I have ended up with.  The idea to add support for the delegate came from this blog entry

iServiceOriented.com

Here is the code for my generic service proxy wrapper...

public class ServiceProxy<TInterface> : ClientBase<TInterface>, IDisposable where TInterface : class

    {

        public delegate void ServiceProxyDelegate<T>(TInterface proxy);

 

        public ServiceProxy()

            : base(typeof(TInterface).ToString())

        {

        }

        public ServiceProxy(string endpointConfigurationName)

            : base(endpointConfigurationName)

        {

        }

 

        protected override TInterface CreateChannel()

        {

            return base.CreateChannel();

        }

 

        public TInterface Proxy

        {

            get

            {

                return this.Channel;

            }

        }

 

        public static void Call(ServiceProxyDelegate<TInterface> proxyDelegate)

        {

            Call(proxyDelegate, typeof(TInterface).ToString());

        }

 

        public static void Call(ServiceProxyDelegate<TInterface> proxyDelegate, string endpointConfigurationName)

        {

            ChannelFactory<TInterface> channel = new ChannelFactory<TInterface>(endpointConfigurationName);

 

            try

            {

                proxyDelegate(channel.CreateChannel());

            }

            finally

            {

                if (channel.State == CommunicationState.Faulted)

                {

                    channel.Abort();

                }

                else

                {

                    try

                    {

                        channel.Close();

                    }

                    catch

                    {

                        channel.Abort();

                    }

                }

            }

        }

 

        public void Dispose()

        {

            if (this.State == CommunicationState.Faulted)

            {

                base.Abort();

            }

            else

            {

                try

                {

                    base.Close();

                }

                catch

                {

                    base.Abort();

                }

            }

        }

    }

 

And, here are some usages samples...

//delegate example1

            string response = null;

            ServiceModel.ServiceProxy<IUnitTestService>.Call(p =>

            {

                response = p.DoStuff("ServiceProxyUsingTest");

            }

            );

 

            //delegate example2

            string response = null;

            ServiceProxy<IUnitTestService>.Call(p => response = p.DoStuff("ServiceProxyUsingTest"));

 

            //using example

            string response = null;

            using (ServiceProxy<IUnitTestService> service = new ServiceProxy<IUnitTestService>())

            {

                response = service.Proxy.DoStuff("ServiceProxyUsingTest");

            }

Tuesday, June 3, 2008

WCF Presentation at South Colorado .Net User Groupo

Here is the content from my WCF presentation today at the South Colorado .Net User Group. The zip file includes the powerpoint, code, and a sql backup file of the demo database. Feel free to email me with any questions.


WCFDemo.zip

Wednesday, May 28, 2008

Server 2008 Virtual Cluster with Hyper-V

I spent the last few days building out a virtual Server 2008 clustered environment in Hyper-V RC0 (I hvae not upgraded to RC1 yet) to do some prototyping for a project. After some playing, I found out you cannot create a shared vhd for multiple virutals to share. So the challenge is how do I setup a shared drive for my cluster quorum and storage. After some research, I found this blog entry (which is right-on, worked great!)
http://blogs.technet.com/pfe-ireland/archive/2008/05/16/how-to-create-a-windows-server-2008-cluster-within-hyper-v-using-simulated-iscsi-storage.aspx

You basically need to create a virtual san on another virutal server using iSCSI to create your shared disks for the cluster. I had the StarWind software up and running in no time. NOTE: If you get an error that the StartWind software cannot obtain exclusive access to the drives in the VM, try closing windows explorer if you were browsing that drive. :) I was also able to install StarWind into a virtual running Server 2008 standard without any problems.






Another note...after getting everything up and running, I was adding a second cluster resource and needed a another cluster storage drive. After shutting down the virtual running the StarWind software, I added another SCSI vhd through the Hyper-V management console. Once I started the virtual back up, I was unable to format the new drive for use. I had to shutdown the StarWind service before I was able to format the drive, even though that drive was not yet added as a device in StarWind.

I am now in the process of setting up a couple of clustered MSMQ queues to use with WCF and some backend processing applications. As this comes together and hopefully works, I will post more information.

Wednesday, May 7, 2008

Team Foundation Server 2008 Hardware Migration

In the last two weeks, I have been through two TFS hardware migrations, neither of which went smoothly. The first migration involved moving to a new server on a new domain and the second was a new server on the same domain. Neither installation is that large so we have both TFS and SQL running on the same box.

First, I started by following the documentation from Microsoft
http://msdn.microsoft.com/en-us/library/ms404869.aspx

The part that did not work was moving the data tier. It would fail with a variety of errors. I checked the connection string web.config in the Services virtual under the Team Foundation Server site hosted on port 8080. It was right, but TFS would not work. After some digging around in the event log, I saw that it was still trying to connect to the old database server. Thinking I missed some steps, I started back over from the beginning and ran into the same issues again. I was not able to find any other connection string in any of the TFS website structure, so I started digging into the database. This sure was starting to feel like a BizTalk database recovery (which is much worse!!). In the TFSIntegration database, there is a table called tbl_database (just in case being in the Tables collection wasn't enough of a clue that it was a table). And there they were, serveral entries with the old database server name. So, I manually changed these to the new db server and tfs was working!!! After that, everyone was able to sync up their source just fine and we were working again. The team project sites were even working.

This same fix worked on both TFS migrations. After running into the same issue on the second migration, I did find this article http://msdn.microsoft.com/en-us/library/bb909757.aspx, which made me feel a little better about our hack solution.

In the end, two successful migrations. In reading some of the issues others have run into, the migration doc needs some work. I still don't know why following the doc didn't work for the data tier and what the right way is (maybe this is it!).

Sunday, December 16, 2007

AppDomain CreateInstanceAndUnwrap w/ Visual Studio 2008

I recently converted a project form Visual Studio 2005 to Visual Studio 2008 RTM. I am using AppDomain.CurrentDomain.CreateInstanceAndUnwrap to dynamically create an instance similar to the following

string assembly = "Test.dll";
string type = "Test.MyClass";
MyClass obj = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assembly, type) as MyClass;

This worked fine in 2005 but gets an exception in 2008 - "could not load file or assembly or one of it's dependancies". Looking at the fusion log, which is now in the exception info window in Studio (very nice), I could see that it was looking for Test.dll.dll, Test.dll.exe. So, the extension is being appended to the end of the assembly name. After removing ".dll" from the name of the assembly, the code works fine.

Tuesday, December 11, 2007

.Net Framework 3.5 Redist...200MB!!!!

I went to download the .net framework 3.5 redist package and it is basically 200mb...wow!!! That is rather large compared to the other versions of the framework. I usually avoid the smaller setup bootstrapper since I don't want to wait for it when I am installing the framework on a server. But, what about deploying client apps? One client has a windows app and they are not going to want to include a 200mb redist with their package.

After reading a couple of forum posts, using the boostrapper looks to be the way to go. Using this, you should be able to download just the components that you need. Here are the links...

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2437304&SiteID=1

http://http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2451232&SiteID=1


You can download both versions of the setup here
http://www.microsoft.com/downloads/details.aspx?FamilyId=333325FD-AE52-4E35-B531-508D977D32A6&displaylang=en

Friday, November 23, 2007

Windows Server 2008 Stored User Names and Passwords

I have been setting up my development environmet in Server 2008 RC0 to start getting a feel for it. Since I deal with multiple domains and user accounts including, my home and clients, I use "Stored User Names and Passwords". Well, this appears to have changed slightly. The way i set it up in XP Pro and Server 2003 looks like this


As I went to set this up in Server 2008, I had to find out where. In the Control Panel, there is an item called "User Accounts". In this window, there is a link on the left called "Manage your network passwords". This brings up the familiar screen for setting up cached accounts. My first attempt gave me this


Notice the validation error. So, a couple of quick tests and I eneded up with this


where I used *.MyDomain instead of MyDomain\*. In my first test of this (connecting to network share), it appears to work fine. The next set of testing will be if it works when authenticating to sql server and tfs. I will find out once I get all that loaded up.