Loading ...

WCF: 'System.Nullable is not convertible by 'QueryStringConverter' | CodeAsp.Net

WCF: 'System.Nullable is not convertible by 'QueryStringConverter'

 /5
0 (0votes)

Today I was in a need where I had to use nullable types as the parameters for WCF service methods. I was having the following   signature of my method:

void DoWork(int? param1, int? param2);

and uri to call this method was this:

results?param1={param1}&param2={param2}

When I tried to call the above WCF service url I got the following exception:
'System.Nullable`1[System.Int32]', but type 'System.Nullable`1[System.Int32]' is not convertible by 'QueryStringConverter'

Reason:

The reason I was getting this error because by default the QueryStringConverter used by WCF services was not handling the Nullable types. 

Solution:

We need to create a custom QueryStringConverter to handle the Nullable Types. Following is the code of custom querystring convertor:

NullableQueryStringConverter.cs code (Custom QueryString Convertor):

using System;
using System.ServiceModel.Dispatcher;

namespace TestWCF.WCF
{
    /// <summary>
    /// Custom <see cref="System.ServiceModel.Dispatcher.QueryStringConverter"/> converter to support nullable types in querystring.
    /// </summary>
    public class NullableQueryStringConverter : QueryStringConverter
    {
        /// <summary>
        /// Determines whether the specified type can be converted to and from a string representation.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> to convert.</param>
        /// <returns>A value that specifies whether the type can be converted.</returns>
        public override bool CanConvert(Type type)
        {
            Type underlyingType = Nullable.GetUnderlyingType(type);

            return (underlyingType != null && base.CanConvert(underlyingType)) || base.CanConvert(type);
        }

        /// <summary>
        /// Converts a query string parameter to the specified type.
        /// </summary>
        /// <param name="parameter">The string form of the parameter and value.</param>
        /// <param name="parameterType">The <see cref="Type"/> to convert the parameter to.</param>
        /// <returns>A value that specifies whether the type can be converted.</returns>
        public override object ConvertStringToValue(string parameter, Type parameterType)
        {
            Type underlyingType = Nullable.GetUnderlyingType(parameterType);
            return underlyingType != null
                       ? (String.IsNullOrEmpty(parameter) ? null : base.ConvertStringToValue(parameter, underlyingType))
                       : base.ConvertStringToValue(parameter, parameterType);
        }
    }//end class
}// end namespace

Below are the steps how we can use the above "NullableQueryStringConverter" in our WCF code. 


Step 1: Create a ServiceHostFactory.
You don't need to create a new factory if you are already having one.
MyServiceHostFactory.cs code:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace TestWCF.WCF
{
    /// <summary>
    /// Factory that provides instances of <see cref="System.ServiceModel.ServiceHost"/> in managed hosting environments where the host instance is created dynamically in response to incoming messages.
    /// </summary>
    public class MyServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }
    }//end class
}// end namespace

Step 2: Create a ServiceHost. This will act as host for your services. You need to attach your custom WebHttpBehavior in it.
MyServiceHost.cs code :

using System;
using System.ServiceModel;

namespace TestWCF.WCF
{
    /// <summary>
    /// Provides a host for services.
    /// </summary>
    public class MyServiceHost : ServiceHost
    {
        public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }

        protected override void OnOpening()
        {
            if (this.Description != null)
            {
                foreach (var endpoint in this.Description.Endpoints)
                {
                    if (endpoint.Binding != null)
                    {
                        var webHttpBinding = endpoint.Binding as WebHttpBinding;

                        if (webHttpBinding != null)
                        {
                            endpoint.Behaviors.Add(new MyWebHttpBehavior());
                        }
                    }
                }
            }

            base.OnOpening();
        }
    }//end class
}// end namespace

Step 3: Create custom WebHttpBehavior. Override the "GetQueryStringConverter" to plug our own custom convertor (NullableQueryStringConverter) here.
MyWebHttpBehavior.cs code:

using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace TestWCF.WCF
{
    public class MyWebHttpBehavior : WebHttpBehavior
    {
        /// <summary>
        /// Gets the query string converter.
        /// </summary>
        /// <param name="operationDescription">The service <see cref="System.ServiceModel.Description.OperationDescription"/>.</param>
        /// <returns>A <see cref="System.ServiceModel.Dispatcher.QueryStringConverter"/> instance.</returns>
        protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
        {
            return new NullableQueryStringConverter();
        }    
    }//end class
}// end namespace


And this is how our service declaration will be:

<%@ ServiceHost Language="C#" Debug="true" Service="TestWCF.WCF.MyService" CodeBehind="MyService.svc.cs" Factory="TestWCF.WCF.MyServiceHostFactory" %>

Note I have set the Factory for the above WCF service to "TestWCF.WCF.MyServiceHostFactory" which we created above. That's it after plugging the custom querysting convertor I was able to work with nullable types as the WCF querystring params.

Comments (no comments yet)

Top Posts