February 2008 Entries

Delegate inference allows you to make a direct assignment of a method name to a
delegate variable, without wrapping it first with a delegate object.

The oldwayclass shows implementation in C# 1.1

class OldWayClass
{
   delegate void notifyDelegate();
   public void InvokeMethod()
   {
      notifyDelegate del = new notifyDelegate(SomeMethod);
      del();
   }
   void SomeMethod()
   {...}
}


and the NewWayClass is the sample implementation in C# 2.0

class NewWayClass
{
   delegate void notifyDelegate();
   public void InvokeMethod()
   {
      notifyDelegate del = SomeMethod;
      del();
   }
   void SomeMethod()
   {...}
}

When you assign a method name to a delegate, the compiler first infers the delegate's type. Then the compiler verifies that there is a method by that name and that its signature matches that of the inferred delegate type. Finally, the compiler creates a new object of the inferred delegate type, wrapping the method and assigning it to the delegate. The compiler can only infer the delegate type if that type is a specific delegate type—that is, anything other than the abstract type Delegate. Delegate inference is a very useful feature indeed, resulting in concise, elegant code.

Covariance and contravariance provide a degree of flexibility when you match method signatures with delegate types. Covariance permits a method to have a more derived return type than what is defined in the delegate. Contravariance permits a method with parameter types that are less derived than in the delegate type.

contravariance example:

This example demonstrates how delegates can be used with methods that have parameters of a type that are base types of the delegate signature parameter type. With contravariance, you can now use one handler in places where, previously, you would have had to use separate handlers. For example both sellNotifyDlg and sellBondNotify delegates are using the same handler - EquitySaleReport since both stock and bond derive from Equity base class

using System;
using System.Collections.Generic;
using System.Text;

namespace ContraVariance
{
    //base class
    class Equity
    {
        int _price;

        public Equity(int Price)
        {
            _price = Price;
        }
        public override string ToString()
        {
            return GetType().Name + " : " + _price;
        }
    }
    //derived
    class Stock : Equity
    {
        public Stock(int Price)
            : base(Price)
        {

        }
    }

    //derived
    class Bond : Equity
    {
        public Bond(int Price)
            : base(Price)
        {

        }
    }

    class Program
    {
        delegate void StockSellNotify(Stock s);
        delegate void BondSellNotify(Bond b);

        static void EquitySaleReport(Equity e)
        {
            Console.WriteLine("Report of sale is " + e);
        }

        static StockSellNotify sellNotifyDlg;
        static BondSellNotify sellBondNotify;

        static void Sell(Stock s)
        {
            if (null != sellNotifyDlg)
            {
                sellNotifyDlg(s);
            }
        }

        //overload
        static void Sell(Bond  b)
        {
            if (null != sellBondNotify)
            {
                sellBondNotify(b);
            }
        }
      

        static void Main(string[] args)
        {
            sellNotifyDlg += EquitySaleReport;
            Sell(new Stock(100));

            sellBondNotify += EquitySaleReport;
            Sell(new Bond(101));

            //both sellNotifyDlg and sellBondNotify are using the same handler - EquitySaleReport

           
        }
    }
}

In my next post i will put a sample for Covariance and try to refine the contravariance sample with generics ...

Happy programming !!!

When we generate (WCF) service proxy class for a service by using svcutil.exe, it creates a proxy that derives from System.ServiceModel.ClientBase<TChannel>. The proxy implements IDisposable and the client code can be wraped inside using statement and guaranteed clean-up in the face of exceptions.

However, the System.ServiceModel.ClientBase<TChannel> class can throw exceptions from its Dispose method, because it internally invokes Close() method which might lead t0 a faulted state. In that case you have to call Abort for clean-up. Most times you are not interested in knowing whether the Dispose fails or not and you just want to have guaranteed clean up of any resources held by the proxy.

Check out this discussion on the WCF forum for why Microsoft implemented the dispose in this way.

To prevent you from writing a lot of code to accomplish this clean-up, I have written a generic GenericServiceProxyAgent class that does it for you.

The idea is that you derive a class from my GenericServiceProxyAgent<TProxy, TChannel> class. Insert your proxy class (that should derive from ClientBase<TChannel>) name for TProxy, and the service interface name for TChannel. The helper class wraps the proxy and doesn't directly expose its methods. From your derived class you can use the protected Proxy property to get access to the service proxy. You should add methods to your derived class that delegate to the proxy.

Create a convenience method to the derived helper that create request messages and unpack response messages. So our helper methods have a different signature than the methods on the proxy class itself.

here is the code snippet.

 

 


using System;
using System.Collections.Generic;
using System.ServiceModel;

namespace xxx.Net.Services
{
    /// <summary>
    /// Generic proxy class for a WCF services.
    /// </summary>
    /// <typeparam name="TProxy">The type of WCF service proxy to wrap.</typeparam>
    /// <typeparam name="TChannel">The type of WCF service interface to wrap.</typeparam>
    public class GenericServiceProxyAgent<TProxy, TChannel> : IDisposable
        where TProxy : ClientBase<TChannel>, new()
        where TChannel : class
    {
        /// <summary>
        /// variable to hold proxy instance
        /// </summary>
        private TProxy _proxy;

        /// <summary>
        /// Gets the WCF service proxy wrapped by this instance.
        /// </summary>
        protected TProxy Proxy
        {
            get
            {
                if (_proxy != null)
                {
                    return _proxy;
                }
                else
                {
                    throw new ObjectDisposedException("GenericServiceProxyAgent");
                }
            }
        }

        /// <summary>
        /// default constructor.
        /// </summary>
        protected GenericServiceProxyAgent()
        {
            _proxy = new TProxy();
        }

        /// <summary>
        /// Disposes the current instance.
        /// </summary>
        public void Dispose()
        {
            try
            {
                if (_proxy != null)
                {
                    if (_proxy.State != CommunicationState.Faulted)
                    {
                        _proxy.Close();
                    }
                    else
                    {
                        _proxy.Abort();
                    }
                }
            }
     catch (FaultException unknownFault)
     {
       System.Diagnostics.Debug.WriteLine("An unknown exception was received. " + unknownFault.Message);
       _proxy.Abort();
     }

            catch (CommunicationException)
            {
  System.Diagnostics.Debug.WriteLine("Service proxy encountred a communication exception and aborted");
                _proxy.Abort();
            }
            catch (TimeoutException)
            {
  System.Diagnostics.Debug.WriteLine("Service proxy encountred a timeout exception and aborted");
                _proxy.Abort();
            }
            catch (Exception)
            {
  System.Diagnostics.Debug.WriteLine("Service proxy encountred a unknown exception and aborted");
                _proxy.Abort();
                throw;
            }
            finally
            {
                _proxy = null;
            }
        }
    }
}

 

 

Note: Always check the "CommunicationState" before invoking any method on them, this is certainly an additional line of code but certainly a best practise

Happy programming !!!

 

i just finished writing Windows service host for my WCF services, there were no crash or exceptions thrown either by client or server,

I was just browing event log to check things were fine, then noticed at end of each call to WCF service, there was a log message with the following exception

System.ServiceModel.CommunicationException occurred
  Message="The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:02:00'."
  Source="System.ServiceModel"

ok here is the solution: when using netTcpBinding the service client has to call the close() method of the service in order to relase the instance back to the pool

Agile way to fix this is by change the binding type to WSHttp or BasicHttp. it will work

Happy Programing !!!

I guess most of us know what a static class is, you can't instiantiate, cannot have any instancing members etc.

This might sound funny but the truth is Static class are "Abstract and Sealed", never understood why ?

If you dont agree with me, use reflector or ILDASM and view your static Class .

Happy Programming !!!

----

This afternoon i had changed the name of one of the Assembly which was refered by ASP.net web site. I had removed the Old reference and re-added the new assembly.

Few moments later i tried to build the website and it's not possible due to a failure in the build process. Error List had several errors. I clicked on the error descrpition and it opened a class file. This file doesn't belong to my current project. It was a temporary asp.net file , this file is related to a real class file on my project and the code is same.

I put off the Cassini and tried rebuild again, the result was same.

Solution :

Remove the related ASPX and .CS file from the ASP.Net web solution, re-build and run the solution. if it doesnt spit any more wiered errors then re-add the ASPX and .CS file to the solution it should compile.

Note: ASP.Net is just a code generator

we have newly added the  web client solution was added to the source control

Strange error when we tried to add a new Business Module to the solution

Here is the error description

Microsoft.Practices.RecipeFramework.ActionExecutionException: An exception occurred during the binding of reference or execution of recipe CreateModuleCS. Error was: Action AddCompositeWebAssemblyReferencesToModule
failed to execute:
Folder C:\Consensus.Net\UI\Consensus.Net.Web\Library does not exist.
You can remove the reference to this recipe through the Guidance Package Manager. ---> System.InvalidOperationException: Folder C:\Consensus.Net\UI\Consensus.Net.Web\Library does not exist
   at
Microsoft.Practices.RecipeFramework.Extensions.Actions.VisualStudio.AddAssembliesReferenceAction.BuildAssembliesPathList(Boolean
gaced)
   at
Microsoft.Practices.RecipeFramework.Extensions.Actions.VisualStudio.AddAssembliesReferenceAction.Execute()
   at
Microsoft.Practices.RecipeFramework.Recipe.Microsoft.Practices.RecipeFramework.Services.IActionExecutionService.Execute(String
actionName, Dictionary`2 inputValues)
   at
Microsoft.Practices.RecipeFramework.Recipe.Microsoft.Practices.RecipeFramework.Services.IActionExecutionService.Execute(String
actionName)
   at
Microsoft.Practices.RecipeFramework.Extensions.Coordinators.ConditionalCoordinator.Run(Dictionary`2
declaredActions, XmlElement coordinationData)
   at
Microsoft.Practices.RecipeFramework.Recipe.ExecuteActions(IDictionaryService
readOnlyArguments, IDictionaryService arguments, ITypeResolutionService
resolution)
   --- End of inner exception stack trace ---
   at
Microsoft.Practices.RecipeFramework.Recipe.UndoExecutedActionsAndRethrow(Exception
ex)
   at
Microsoft.Practices.RecipeFramework.Recipe.ExecuteActions(IDictionaryService
readOnlyArguments, IDictionaryService arguments, ITypeResolutionService
resolution)
   at Microsoft.Practices.RecipeFramework.Recipe.Execute(Boolean allowSuspend)
   at Microsoft.Practices.RecipeFramework.GuidancePackage.Execute(String
recipe, IAssetReference reference, IDictionary arguments)
   at
Microsoft.Practices.RecipeFramework.GuidancePackage.ExecuteFromTemplate(String
recipe, IDictionary arguments)
   at
Microsoft.Practices.RecipeFramework.VisualStudio.Templates.UnfoldTemplate.ExecuteRecipe(BoQolean
executeActions)
   at
Microsoft.Practices.RecipeFramework.VisualStudio.Templates.UnfoldTemplate.RunFinished()

Solution :

The "Library" folder was missing in the Root of the UI solution, I then figured out that Assemblies inside Library folder is used by the WCSF not the underlying source or solution file. so VSS didnt find any of the project has direct reference to this folder and assemblies and didnt add it to the VSS repository. Add manually to VSS and to the solution. ensure you backup the solution before adding it to source control.

Sounds funny but its the fact

-----

 

System Requirements

To view and run the Service Factory assets in your development environment, you need the following software installed on your computer:

In addition to the preceding requirements, if you want to install the Service Factory source code, you also need the following software installed on your computer:

Files

Runtime Binary Software Factory - Modeling Edition CTP (VS2008).zip
runtime binary, 4753K, uploaded Dec 28 2007 - 884 downloads
Example Building HOL for Visual Studio 2008.zip
example, 1808K, uploaded Dec 28 2007 - 400 downloads
Example Building HOL for Visual Studio 2008.exe
example, 1928K, uploaded Dec 28 2007 - 225 downloads

Note : Runtime Binaries are available for download, no source code yet.

Things were quite fine untill we were not using source control, here is another exception while generating Data Repository Classes.

Microsoft.Practices.RecipeFramework.ActionExecutionException: An exception occurred during the binding of reference or execution of recipe CreateDataRepositoriesFromDCProject. Error was: Action AddIDbToBusinessEntityNameMapper failed to execute:

Access to the path 'C:\Consensus.Net\CoreBooking\Source\Resource Access\Consensus.Net.DataAccess\Generic\IDbToBusinessEntityNameMapper.cs' is denied..

You can remove the reference to this recipe through the Guidance Package Manager. ---> System.UnauthorizedAccessException: Access to the path 'C:\Consensus.Net\CoreBooking\Source\Resource Access\Consensus.Net.DataAccess\Generic\IDbToBusinessEntityNameMapper.cs' is denied.

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

   at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite)

   at Microsoft.Practices.ServiceFactory.DataAccess.Actions.VisualStudio.AddItemFromStringToProjectItemAction.Execute()

   at Microsoft.Practices.RecipeFramework.Recipe.Microsoft.Practices.RecipeFramework.Services.IActionExecutionService.Execute(String actionName, Dictionary`2 inputValues)

   at Microsoft.Practices.RecipeFramework.Recipe.Microsoft.Practices.RecipeFramework.Services.IActionExecutionService.Execute(String actionName)

   at Microsoft.Practices.RecipeFramework.Extensions.Coordinators.ConditionalCoordinator.Run(Dictionary`2 declaredActions, XmlElement coordinationData)

   at Microsoft.Practices.RecipeFramework.Recipe.ExecuteActions(IDictionaryService readOnlyArguments, IDictionaryService arguments, ITypeResolutionService resolution)

   --- End of inner exception stack trace ---

   at Microsoft.Practices.RecipeFramework.Recipe.UndoExecutedActionsAndRethrow(Exception ex)

   at Microsoft.Practices.RecipeFramework.Recipe.ExecuteActions(IDictionaryService readOnlyArguments, IDictionaryService arguments, ITypeResolutionService resolution)

   at Microsoft.Practices.RecipeFramework.Recipe.Execute(Boolean allowSuspend)

   at Microsoft.Practices.RecipeFramework.GuidancePackage.Execute(String recipe, IAssetReference reference, IDictionary arguments)

   at Microsoft.Practices.RecipeFramework.GuidancePackage.Execute(IAssetReference reference)

   at Microsoft.Practices.RecipeFramework.RecipeReference.OnExecute()

   at Microsoft.Practices.RecipeFramework.AssetReference.Execute()

   at Microsoft.Practices.RecipeFramework.VisualStudio.RecipeMenuCommand.OnExec()

   at Microsoft.Practices.RecipeFramework.VisualStudio.AssetMenuCommand.Invoke()

Solution :

Guidance receipe requires base factory files like "IDbToBusinessEntityNameMapper" , "IDomainObjectFactory" etc.

 

Since all these files are checked under source control, you have check out the Base factory files under Generic folder and App.Config file. inorder to sucessfully execute the guidance package

 

Hope this information helps