Pierre Greborio.NET

Talking about .NET world
Changing home

Ok, I am moving. I have a new blog at http://blogs.msdn.com/pierreg/. So, hopefully I will post more there :-)

See you...

One year after...what's happened?

Ok, the last year was a really busy one. A lot of thinks changed in my life, both working and personal lives. In an extreme summary: I moved to the Bay Area from Italy with my family and joined the Microsoft IPTV team.

The new change takes a lot of time but I'm really happy of that. So, see you sometime...

Reliability with WCF

Christian points an interesting aspect of the current implementation of the reliability in WCF. We all agree that we need some kind of persistence.

I am thinking something like it is done in MSMQ. When you create a message you can decide to have it durable or not (default). Then, we could have something like the following:

<reliableSession enabled="true" durable="true" />

Durable or recoverable (as in the BCL) ?

Posted: Feb 23 2006, 11:54 AM by PierreG | with no comments
Filed under:
First drop of WCF client addin for Visual Studio 2005

Ok, here it is. I uploaded the first beta of WCF Client tools Addins for Visual Studio 2005. After the setup (available here) you'll fine two new context menus items on the project:

Context menu
  • Add WCF Service Reference...
  • Create WCF Proxy Unit Test...

The first one permits to create the CF proxy class and it's configuration section. As you can see in the following picture you can set a lot of attributes to the code generator (more or less as svcutil.exe tool does)

Add service proxy

 

The second addin generates also the NUnit (version 2.2 or above) code in order to have unit testing on the selected service:

Add Unit Testing

For example, if you want to test the SelfHost service (available on WinFX SDK) you can add the service address (see picture above) and set the test class name. Three files will be generated (app.config if already present will be updated only):

app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns="
http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.serviceModel>
        <client>
            <endpoint address="
http://localhost:8000/servicemodelsamples/service"
                bindingConfiguration="WSHttpBinding_ICalculator" binding="customBinding"
                name="WSHttpBinding_ICalculator" contract="TestClient.ICalculator">
                <identity>
                    <userPrincipalName value="
pierreg@PEWAY.loc" />
                </identity>
            </endpoint>
        </client>
        <bindings>
            <customBinding>
                <binding name="Secure conversation bootstrap binding dda1dd0a-f6e4-4686-8210-90f381484fe3">
                    <security />
                    <textMessageEncoding />
                </binding>
                <binding name="WSHttpBinding_ICalculator">
                    <security authenticationMode="SecureConversation" bootstrapBindingConfiguration="Secure conversation bootstrap binding dda1dd0a-f6e4-4686-8210-90f381484fe3"
                        bootstrapBindingSectionName="customBinding" />
                    <textMessageEncoding />
                    <httpTransport />
                </binding>
            </customBinding>
        </bindings>
    </system.serviceModel>
</configuration>

Note: during the configuration file generation I correct the contract attrbute with the correct class namespace and add the name attribute to the endpoint element (this doesn't happens with svcutil.exe).

contract interface:

namespace TestClient {    
    
    [System.ServiceModel.ServiceContractAttribute(Namespace="
http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator {
       
        [System.ServiceModel.OperationContractAttribute(Action="
http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")]
        double Add(double n1, double n2);
       
        [System.ServiceModel.OperationContractAttribute(Action="
http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")]
        double Subtract(double n1, double n2);
       
        [System.ServiceModel.OperationContractAttribute(Action="
http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")]
        double Multiply(double n1, double n2);
       
        [System.ServiceModel.OperationContractAttribute(Action="
http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")]
        double Divide(double n1, double n2);
    }
}

and finally the test class:

namespace TestClient
{
    using System;
    using System.Text;
    using System.ServiceModel;
    using System.Collections.Generic;
    using NUnit.Framework;
   
   
    [TestFixture()]
    public class ICalculatorServiceTest
    {
       
        public ICalculatorServiceTest()
        {
            /// TODO: Add constructor logic here
        }
       
        [Test()]
        public virtual void TestAdd_WSHttpBinding_ICalculator()
        {

            ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator");

            ICalculator channel = factory.CreateChannel();
            // TODO: Initialize to an appropriate value
            double n1 = default(double);
            // TODO: Initialize to an appropriate value
            double n2 = default(double);

            double expected = default(double);
            double actual = default(double);


            actual = channel.Add(n1, n2);

            Assert.AreEqual(expected, actual, "Add did not return the expected value.");

            ((IChannel)(channel)).Close();
            ((IChannel)(channel)).Dispose();
        }
       
        [Test()]
        public virtual void TestSubtract_WSHttpBinding_ICalculator()
        {

            ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator");

            ICalculator channel = factory.CreateChannel();
            // TODO: Initialize to an appropriate value
            double n1 = default(double);
            // TODO: Initialize to an appropriate value
            double n2 = default(double);

            double expected = default(double);
            double actual = default(double);


            actual = channel.Subtract(n1, n2);

            Assert.AreEqual(expected, actual, "Subtract did not return the expected value.");

            ((IChannel)(channel)).Close();
            ((IChannel)(channel)).Dispose();
        }
       
        [Test()]
        public virtual void TestMultiply_WSHttpBinding_ICalculator()
        {

            ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator");

            ICalculator channel = factory.CreateChannel();
            // TODO: Initialize to an appropriate value
            double n1 = default(double);
            // TODO: Initialize to an appropriate value
            double n2 = default(double);

            double expected = default(double);
            double actual = default(double);


            actual = channel.Multiply(n1, n2);

            Assert.AreEqual(expected, actual, "Multiply did not return the expected value.");

            ((IChannel)(channel)).Close();
            ((IChannel)(channel)).Dispose();
        }
       
        [Test()]
        public virtual void TestDivide_WSHttpBinding_ICalculator()
        {

            ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator");

            ICalculator channel = factory.CreateChannel();
            // TODO: Initialize to an appropriate value
            double n1 = default(double);
            // TODO: Initialize to an appropriate value
            double n2 = default(double);

            double expected = default(double);
            double actual = default(double);


            actual = channel.Divide(n1, n2);

            Assert.AreEqual(expected, actual, "Divide did not return the expected value.");

            ((IChannel)(channel)).Close();
            ((IChannel)(channel)).Dispose();
        }
    }
}

Obviously, you need to have WCF installed as well as NUnit.

Any comment are welcome. Thanks!

Posted: Jan 05 2006, 11:51 AM by PierreG | with 2 comment(s)
Filed under:
From Indigo to WCF tool

Ok, my Indigo Proxy Generator is going to be updated to WCF November CTP. I'll change the name to WCF Proxy Generator ;-)

What's new ? From the proxy generator point of view quite nothing, just the code updated to work with the November CTP. The Indigo Service Tester has been posponed until I'll solve several problems with my PropertyGrid ;-)

In the new package I'll add something that I hope you'll find interesting: WCF Unit Test Wizard. That is a Unit Test project (yes, available with Visual Studio Team System/Developer/Tester) which generates the code (proxy class, configuration and test class) to run tests on WCF services. I'm still studying the VS extensions to run a new test project type correctly, I hope to have a first beta next month.

If you ideas or suggestions, please send them to me. Thanks.

Posted: Dec 30 2005, 05:07 PM by PierreG | with no comments
Filed under:
Naming Guidelines and Visual Controls

According to the .NET naming guidelines it is often suggested to adopt camel case for private properties/fields and pascal case for protected and public properties/fields.

It is unclear how to name visual controls. Let consider a standard label which is protected in a web form. We could name as following:

  1. LblFirstName (classic pascal case for protected fields)
  2. StaticFirstName (contro, agnostic version)
  3. lblFirstName (as usually I do)
  4. _lblFirstName (C++ style)

For read/write controls we could use:

  1. TxtFirstName
  2. ReadWriteFirstName
  3. txtFirstName
  4. _txtFirstName

During these last 10 years of development I changed my programming style. I started with 4, then moved to 3. Today I'm thinking about the 2.

VSTO and Security

VSTO (Visual Studio Tools for Office) is a powerful tool used to have the power of .NET framework insode an Office 2003 document (Word, Excel, Outlook and InfoPath).

The only, and most important, limitation I can register is from a security point of view. The documentation says: "To deploy and run an Office solution that uses managed code extensions, you must grant full trust to the assemblies in the security policy of each end user or computer. If the document is in a network location instead of on the user's computer, you must grant full trust to the document as well."

From a policy company point of view its unacceptable to give full trust access to office assemblies. I hope this will change soon...

Posted: Dec 06 2005, 12:57 PM by PierreG | with 2 comment(s)
Filed under:
Testing web service with Visual Studio Team System

When I used for the first time VSTS (beta 1) one of the miss I found was the "Web Service Test Project" (note: in RTM is still missing). I thought to possible workarounds and found the most intuitive way: unit testing.

Then I created many unit testing for each proxy class that I generated (note: remember that for test cases code generation the proxy class must be into another class library). After some successful tests I started to see how my web service works under load creating a load test. Increasing the number of concurrent users I got immediately some limitations on the client side (agent). I then checked the unit test limitations for web services and found and interesting point:

1.36   Visual Studio 2005 Team Edition for Testers: Set the Proxy Property of a SoapHttpClientProtocol Implementations to Null
If you are running a load test containing unit tests that call Web services, the unit test code should explicitly set the proxy property of the Web service proxy class that implements System.Web.Services.Protocols.SoapHttpClientProtocol. This prevents a performance bottleneck that can occur when the proxy must be automatically detected.


Even setting the proxy class I didn’t found any real improvement. My dual Xon 3GHZ with 2 GB RAM can’t run the test agent with more than 200 concurrent users. So, I had to find a smart way to test web service.

I completely changed my strategy. I created an empty web test project and added a web service request. In the body property I set the XML (SOAP) payload that I registered with WebServiceStudio (note: you can also trace the request messages with some trace tool from unit testing sessions). I added all my custom parameters (context parameters and data sources) just adding the correct syntax into the body, ie.

<soap:Body>
    <getSecurityPricesRequest xmlns="
http://services.peway.com/security/v3/messages">
      <codes>{{SID}}</codes>
      <HistoryPricePeriod DateFrom="2000-04-03T00:00:00" DateTo="2005-11-30T00:00:00" />
    </getSecurityPricesRequest>
  </soap:Body>

Run and wow, it works fine. Under load test I was able to run 1000 concurrent users. That is a definitive improvement. Now, I would have some wizard that helps me in building such request without copy&paste :-)

Posted: Nov 30 2005, 06:03 PM by PierreG | with 1 comment(s)
Filed under:
Web Testing extraction rule

When you test a web application with Visual Studio Team System you can use extraction rules in order to exctract information from the request and reply HTTP streams. By default, the September CTP provides the following extraction rules:

  • Attribute Value
  • Form Field
  • HTTP Header
  • Regular Expression
  • Text
  • Hidden Field

Today I added my custom extraction rule: query string parameter. This expraction rule is very simple, it extract the value of a given query string parameter and eventually copy that value into the web context variable. The code is pretty simple:

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.WebTesting;
using System.ComponentModel;

namespace PEWay.VisualStudio.Extensibility
{
    public class QueryStringParameterExtractionRule : ExtractionRule   
    {
        private string ctxParameter = string.Empty;
        private string parameterName = string.Empty;
        private bool isCaseSensitive = false;

        [Description("Type a name for the QueryString parameter.")]
        public string ParameterName
        {
            get { return parameterName; }
            set
            {
                if (value != string.Empty)
                    parameterName = value;
            }
        }

        [Description("Ignore case during search for matching the parameter name.")]
        public bool IsCaseSensitive
        {
            get { return isCaseSensitive; }
            set { isCaseSensitive = value; }
        }

        [Description("The name of a text context variable to associate with the extracted value.")]
        public override string ContextParameterName
        {
            get { return ctxParameter; }
            set
            {
                if (value != string.Empty)
                    ctxParameter = value;
            }
        }
       
        public override string RuleName
        {
            get { return "Extract Query String parameter"; }
        }

        public override string RuleDescription
        {
            get { return "Extracts a query string parameter value."; }
        }

        public override void Extract(object sender, ExtractionEventArgs e)
        {
            StringComparison compType;
            e.Success = false;

            if (string.IsNullOrEmpty(parameterName))
            {
                e.Message = "No query string parameter name defined.";
                return;
            }

            if (isCaseSensitive == true)
                compType = StringComparison.Ordinal;
            else
                compType = StringComparison.OrdinalIgnoreCase;

            if (e.Request.HasQueryStringParameters)
            {
                foreach (QueryStringParameter parameter in e.Request.QueryStringParameters)
                {
                    if (parameter.Name.Equals(parameterName, compType))
                    {
                        e.Success = true;

                        if (!string.IsNullOrEmpty(ctxParameter))
                        {
                            // Check if the context variable exists
                            if (e.WebTest.Context[ctxParameter] == null)
                                e.WebTest.Context.Add(ctxParameter, parameter.Value);
                            else
                                e.WebTest.Context[ctxParameter] = parameter.Value;
                        }
                    }
                }
            }

            if (e.Success)
                e.Message = "Query string parameter extracted.";
            else
                e.Message = "No query string parameter extracted.";
        }
    }
}

How to use it ? Create a class library and reference it to your web test project. The rule will be included automatically in the list.

Posted: Sep 22 2005, 11:52 AM by PierreG | with no comments
Filed under:
Busy time
It's a lot that I don't post. Why ? I'm in study phase: Indigo (WFC) and Team System. Too many things to study :-)
Posted: Sep 06 2005, 02:52 PM by PierreG | with 3 comment(s)
Filed under:
More Posts Next page »